feat(plugins): paramètres projet plugins + attribution skills/tools aux agents — #282 (manifeste accepte contributes.skills IdeA-native multi-harness; store .ideai/project-plugins.json v1: enable plugin par projet + assignments skills/tools par agent; refs + use cases settings/assign/unassign; resolver skills pour idea_skill_read et injection catalogue lancement agent; permissions MCP dynamiques projetées par harness Claude Code/Codex/OpenCode; tombstones uninstall, hot reload recalcule catalogue et marque assignments cassés; frontend: Settings projet Plugins, détail capabilities, attribution agent, catalogue permissions; bump pointeur IdeaSDK 6eb8db3; QA verte: cargo test -p application, project_plugin_settings 3/3, dto_plugins 2/2, structured_launch_d3 26/26, catalogue mcp 7/7, frontend 5 tests ProjectPluginSettings/plugin, npm build frontend)

This commit is contained in:
2026-09-08 15:48:57 +02:00
parent bdc20a134a
commit 86ed0aa00b
38 changed files with 2127 additions and 89 deletions

View File

@ -36,6 +36,8 @@ pub use crate::ticket_dto::*;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PluginContributionSummaryDto {
/// Agent skills count.
pub skills: usize,
/// Top-level menus count.
pub top_level_menus: usize,
/// Menu items count.
@ -51,6 +53,7 @@ pub struct PluginContributionSummaryDto {
impl From<application::PluginContributionSummary> for PluginContributionSummaryDto {
fn from(value: application::PluginContributionSummary) -> Self {
Self {
skills: value.skills,
top_level_menus: value.top_level_menus,
menu_items: value.menu_items,
slash_commands: value.slash_commands,
@ -60,6 +63,89 @@ impl From<application::PluginContributionSummary> for PluginContributionSummaryD
}
}
/// Project-scoped plugin activation and assignment settings returned to clients.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ProjectPluginSettingsDto {
/// Schema version.
pub version: u32,
/// Per-project plugin activation choices.
pub plugins: Vec<domain::ProjectPluginActivation>,
/// Per-agent plugin capability assignments.
pub agents: Vec<domain::AgentPluginAssignments>,
}
impl From<domain::ProjectPluginSettings> for ProjectPluginSettingsDto {
fn from(value: domain::ProjectPluginSettings) -> Self {
Self {
version: value.version,
plugins: value.plugins,
agents: value.agents,
}
}
}
/// Project plugin settings plus the globally installed manifest catalogue.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ProjectPluginSettingsViewDto {
/// Persisted project settings.
pub settings: ProjectPluginSettingsDto,
/// Currently installed and valid plugin manifests.
pub installed: Vec<domain::PluginManifest>,
}
impl From<application::ProjectPluginSettingsView> for ProjectPluginSettingsViewDto {
fn from(value: application::ProjectPluginSettingsView) -> Self {
Self {
settings: value.settings.into(),
installed: value.installed,
}
}
}
/// Request to toggle a globally installed plugin for one project.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SetProjectPluginEnabledRequestDto {
/// Owning project id.
pub project_id: String,
/// Globally installed plugin id.
pub plugin_id: String,
/// Desired project activation state.
pub enabled: bool,
}
/// Request to assign or unassign a plugin skill for an agent.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MutateAgentPluginSkillRequestDto {
/// Owning project id.
pub project_id: String,
/// Target agent id.
pub agent_id: String,
/// Owning plugin id.
pub plugin_id: String,
/// Manifest-local skill id.
pub skill_id: String,
}
/// Request to assign or unassign a plugin MCP tool for an agent.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MutateAgentPluginToolRequestDto {
/// Owning project id.
pub project_id: String,
/// Target agent id.
pub agent_id: String,
/// Owning plugin id.
pub plugin_id: String,
/// Manifest-local MCP server id.
pub server_id: String,
/// Tool name advertised by that server.
pub tool_name: String,
}
/// Admin plugin DTO.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]

View File

@ -14,52 +14,54 @@ use std::sync::{Arc, Mutex};
use application::orchestrator::UpdateProjectContext as GuardedUpdateProjectContext;
use application::{
AddIssueAttachment, AgentResumer, AgentWakeService, AllocateManagedTemp, AppError,
AssignIssueAgent, AssignSkillToAgent, AssignTicketToSprint, AttachLiveAgent,
AuthenticateSession, BackgroundCommandArchive, BulkDeleteIssues, BulkUpdateIssuePriority,
BulkUpdateIssueStatus, CancelBackgroundTask, ChangeAgentProfile, CheckEmbedderSuggestion,
ClearChatDraft, CloneOpenCodeProfileFromSeed, CloneProfileFromSeed, CloseProject, CloseTab,
CloseTerminal, CloseTicketAssistant, ConfigureProfiles, ContextGuardUseCases,
CreateAgentFromScratch, CreateAgentFromTemplate, CreateIssue, CreateLayout, CreateMemory,
CreateProject, CreateSkill, CreateSprint, CreateTemplate, DeleteAgent, DeleteEmbedderProfile,
DeleteIssue, DeleteLayout, DeleteMemory, DeleteModelArtifact, DeleteModelServer, DeleteProfile,
DeleteSkill, DeleteSprint, DeleteTemplate, DescribeEmbedderEngines, DetectAgentDrift,
DetectProfiles, DismissEmbedderSuggestion, EnsureLocalModelServer, ExecuteSlashCommand,
FirstRunState, GcManagedTemp, GetAppExitWorkGuardState, GetLiveStateLean, GetMemory,
GetProjectPermissions, GetProjectSystemPermissions, GetProjectWorkState, GitBranches,
GitCheckout, GitCommit, GitGraph, GitInit, GitLog, GitStage, GitStatus, GitUnstage,
HarvestMemoryFromTurn, HealthUseCase, ImportChatAttachments, InspectConversation,
InstallPluginFromArchive, InstallPluginFromDirectory, JsonPluginManifestValidator, LaunchAgent,
LaunchAgentInput, LinkIssues, ListAgents, ListAgentsInput, ListClaudeModels, ListCodexModels,
ListDevices, ListEmbedderProfiles, ListIssues, ListLayouts, ListMemories, ListModelServers,
AssignIssueAgent, AssignSkillToAgent, AssignTicketToSprint, AssignedSkillResolver,
AttachLiveAgent, AuthenticateSession, BackgroundCommandArchive, BulkDeleteIssues,
BulkUpdateIssuePriority, BulkUpdateIssueStatus, CancelBackgroundTask, ChangeAgentProfile,
CheckEmbedderSuggestion, ClearChatDraft, CloneOpenCodeProfileFromSeed, CloneProfileFromSeed,
CloseProject, CloseTab, CloseTerminal, CloseTicketAssistant, ConfigureProfiles,
ContextGuardUseCases, CreateAgentFromScratch, CreateAgentFromTemplate, CreateIssue,
CreateLayout, CreateMemory, CreateProject, CreateSkill, CreateSprint, CreateTemplate,
DeleteAgent, DeleteEmbedderProfile, DeleteIssue, DeleteLayout, DeleteMemory,
DeleteModelArtifact, DeleteModelServer, DeleteProfile, DeleteSkill, DeleteSprint,
DeleteTemplate, DescribeEmbedderEngines, DetectAgentDrift, DetectProfiles,
DismissEmbedderSuggestion, EnsureLocalModelServer, ExecuteSlashCommand, FirstRunState,
GcManagedTemp, GetAppExitWorkGuardState, GetLiveStateLean, GetMemory, GetProjectPermissions,
GetProjectSystemPermissions, GetProjectWorkState, GitBranches, GitCheckout, GitCommit,
GitGraph, GitInit, GitLog, GitStage, GitStatus, GitUnstage, HarvestMemoryFromTurn,
HealthUseCase, ImportChatAttachments, InspectConversation, InstallPluginFromArchive,
InstallPluginFromDirectory, JsonPluginManifestValidator, LaunchAgent, LaunchAgentInput,
LinkIssues, ListAgents, ListAgentsInput, ListClaudeModels, ListCodexModels, ListDevices,
ListEmbedderProfiles, ListIssues, ListLayouts, ListMemories, ListModelServers,
ListOpenCodeProviders, ListPluginRuntimeContributions, ListPlugins, ListProfiles,
ListProjectFiles, ListProjects, ListResumableAgents, ListSkills, ListSlashCommands,
ListSprints, ListTemplates, LiveAgentRegistry, LiveSessions, LiveStateLeanProvider,
LiveStateProvider, LiveStateReadProvider, LoadLayout, MarkIssueAttachmentSummarized,
McpRuntime, McpToolPermissionCatalogue, MoveTabToNewWindow, MutateLayout, OnnxModelView,
ListProjectFiles, ListProjectPluginSettings, ListProjects, ListResumableAgents, ListSkills,
ListSlashCommands, ListSprints, ListTemplates, LiveAgentRegistry, LiveSessions,
LiveStateLeanProvider, LiveStateProvider, LiveStateReadProvider, LoadLayout,
MarkIssueAttachmentSummarized, McpRuntime, McpToolPermissionCatalogue, MoveTabToNewWindow,
MutateAgentPluginSkill, MutateAgentPluginTool, MutateLayout, OnnxModelView,
OpenPluginLayoutWindow, OpenProject, OpenTerminal, OpenTicketAssistant, OrchestratorService,
PairAttemptLimiter, PairDevice, PermissionProjectorRegistry, PluginCommandTasks,
PluginConfigDocuments, PluginEventSubscriptions, PluginStorageAccess,
PluginToolchainDiagnostics, PluginWorkspaceAccess, ProposeContext, PurgeManagedTemp,
QueryProjectStructure, ReadAgentContext, ReadChatDraft, ReadContext, ReadConversationPage,
ReadIssue, ReadIssueAttachment, ReadIssueCarnet, ReadMcpToolPermissions, ReadMemory,
ReadMemoryIndex, ReadProjectContext, ReadSkill, ReadTemplate, RecallMemory, ReconcileLayouts,
ReconcileLiveState, ReconcileLiveStateInput, ReconcilePluginMcpServers, RecordTurn,
RecordTurnProvider, ReferenceProfiles, ReleaseManagedTemp, ReloadPlugin, ReloadPluginInput,
RenameDevice, RenameLayout, RenameSprint, ReorderSprints, ResizeTerminal,
PluginToolchainDiagnostics, PluginWorkspaceAccess, ProjectPluginResolver, ProposeContext,
PurgeManagedTemp, QueryProjectStructure, ReadAgentContext, ReadChatDraft, ReadContext,
ReadConversationPage, ReadIssue, ReadIssueAttachment, ReadIssueCarnet, ReadMcpToolPermissions,
ReadMemory, ReadMemoryIndex, ReadProjectContext, ReadSkill, ReadTemplate, RecallMemory,
ReconcileLayouts, ReconcileLiveState, ReconcileLiveStateInput, ReconcilePluginMcpServers,
RecordTurn, RecordTurnProvider, ReferenceProfiles, ReleaseManagedTemp, ReloadPlugin,
ReloadPluginInput, RenameDevice, RenameLayout, RenameSprint, ReorderSprints, ResizeTerminal,
ResolveAgentCapabilities, ResolveAgentPermissions, ResolveAgentSystemPermissions,
ResolveManagedTemp, ResolveMemoryLinks, RestoreOpenWindows, RetryBackgroundTask,
ReviewPluginPackage, RevokeAllDevices, RevokeDevice, RotateConversationLog, SaveChatDraft,
SaveEmbedderProfile, SaveModelServer, SaveOpenCodeProviderProfile, SaveProfile,
SessionLimitService, SetActiveLayout, SetPluginEnabled, SlashCommandRegistry,
SnapshotOpenWindows, SnapshotRunningAgents, SpawnBackgroundCommand, StopLiveAgent,
StructuredRoutingMode, StructuredSessions, SuggestedThisSession, SyncAgentWithTemplate,
TerminalSessions, TouchDevice, UnassignSkillFromAgent, UnassignTicketFromSprint,
UninstallPlugin, UnlinkIssues, UpdateAgentContactable, UpdateAgentContext, UpdateAgentEffort,
UpdateAgentMcpToolPermissions, UpdateAgentPermissions, UpdateAgentSystemPermissions,
UpdateIssue, UpdateIssueCarnet, UpdateLiveState, UpdateMemory, UpdateProjectContext,
UpdateProjectMcpToolPermissions, UpdateProjectOrchestrator, UpdateProjectPermissions,
UpdateProjectSystemPermissions, UpdateSkill, UpdateTemplate, WakeSessionProvider, WriteMemory,
WriteToTerminal, AGENT_MEMORY_RECALL_BUDGET,
SessionLimitService, SetActiveLayout, SetPluginEnabled, SetProjectPluginEnabled,
SlashCommandRegistry, SnapshotOpenWindows, SnapshotRunningAgents, SpawnBackgroundCommand,
StopLiveAgent, StructuredRoutingMode, StructuredSessions, SuggestedThisSession,
SyncAgentWithTemplate, TerminalSessions, TouchDevice, UnassignSkillFromAgent,
UnassignTicketFromSprint, UninstallPlugin, UnlinkIssues, UpdateAgentContactable,
UpdateAgentContext, UpdateAgentEffort, UpdateAgentMcpToolPermissions, UpdateAgentPermissions,
UpdateAgentSystemPermissions, UpdateIssue, UpdateIssueCarnet, UpdateLiveState, UpdateMemory,
UpdateProjectContext, UpdateProjectMcpToolPermissions, UpdateProjectOrchestrator,
UpdateProjectPermissions, UpdateProjectSystemPermissions, UpdateSkill, UpdateTemplate,
WakeSessionProvider, WriteMemory, WriteToTerminal, AGENT_MEMORY_RECALL_BUDGET,
};
use async_trait::async_trait;
use domain::ports::{
@ -70,10 +72,10 @@ use domain::ports::{
FileSystem, GitPort, IdGenerator, IssueNumberAllocator, IssueStore, ManagedTempStore,
McpToolPermissionStore, MemoryRecall, MemoryStore, ModelArtifactDownloader, PermissionStore,
PluginManifestValidator, PluginMcpSupervisor, PluginPackageStore, PluginRegistryStore,
PluginStorageStore, ProcessSpawner, ProfileStore, ProjectStore, PtyHandle, PtyPort,
RuntimePermissionProbe, ScheduledTask, Scheduler, SecretStore, SkillStore, SprintStore,
StructuredSessionEnvironmentPreparer, SystemPermissionStore, TemplateStore, ToolInvoker,
WakeError, WakeReason, WindowStateStore,
PluginStorageStore, ProcessSpawner, ProfileStore, ProjectPluginSettingsStore, ProjectStore,
PtyHandle, PtyPort, RuntimePermissionProbe, ScheduledTask, Scheduler, SecretStore, SkillStore,
SprintStore, StructuredSessionEnvironmentPreparer, SystemPermissionStore, TemplateStore,
ToolInvoker, WakeError, WakeReason, WindowStateStore,
};
use domain::profile::{
AgentProfile, ContextInjection, McpConfigStrategy, McpTransport, StructuredAdapter,
@ -98,18 +100,18 @@ use infrastructure::{
FsHandoffStore, FsIssueNumberAllocator, FsIssueStore, FsLiveStateStore, FsManagedTempStore,
FsMcpToolPermissionStore, FsMemoryStore, FsModelServerRegistry, FsOrchestratorWatcher,
FsPermissionStore, FsPluginPackageStore, FsPluginRegistryStore, FsPluginStorageStore,
FsProfileStore, FsProjectStore, FsProviderSessionStore, FsSecretStore, FsSkillStore,
FsSprintStore, FsSystemPermissionStore, FsTemplateStore, FsWindowStateStore, Git2Repository,
HeuristicHandoffSummarizer, HfModelArtifactDownloader, HttpOpenAiCompatibleProbe,
HttpProviderModelCatalogue, IdeaiContextStore, InMemoryConversationRegistry, InMemoryMailbox,
InMemoryPairAttemptLimiter, LlamaCppRuntime, LocalEnvironmentReader, LocalFileSystem,
LocalManagedProcess, LocalProcessSpawner, ManagedTempToolProvider, McpServer, MediatedInbox,
NaiveMemoryRecall, OrchestratorWatchHandle, PortablePtyAdapter, ProcessCliVersionReader,
ReadOnlyRuntimePermissionProbe, RwFileGuard, StructuredSessionFactory, SystemClock,
SystemMillisClock, TemplateToolProvider, TicketAssistantEnvironmentPreparer,
TicketToolProvider, TokioBroadcastEventBus, TokioScheduler, ToolPolicyRegistry, UuidGenerator,
VectorMemoryRecall, DEFAULT_OLLAMA_BASE_URL, ONNX_CACHE_SUBDIR, RECOMMENDED_ONNX_MODELS,
VECTOR_HTTP_ENABLED, VECTOR_ONNX_ENABLED,
FsProfileStore, FsProjectPluginSettingsStore, FsProjectStore, FsProviderSessionStore,
FsSecretStore, FsSkillStore, FsSprintStore, FsSystemPermissionStore, FsTemplateStore,
FsWindowStateStore, Git2Repository, HeuristicHandoffSummarizer, HfModelArtifactDownloader,
HttpOpenAiCompatibleProbe, HttpProviderModelCatalogue, IdeaiContextStore,
InMemoryConversationRegistry, InMemoryMailbox, InMemoryPairAttemptLimiter, LlamaCppRuntime,
LocalEnvironmentReader, LocalFileSystem, LocalManagedProcess, LocalProcessSpawner,
ManagedTempToolProvider, McpServer, MediatedInbox, NaiveMemoryRecall, OrchestratorWatchHandle,
PortablePtyAdapter, ProcessCliVersionReader, ReadOnlyRuntimePermissionProbe, RwFileGuard,
StructuredSessionFactory, SystemClock, SystemMillisClock, TemplateToolProvider,
TicketAssistantEnvironmentPreparer, TicketToolProvider, TokioBroadcastEventBus, TokioScheduler,
ToolPolicyRegistry, UuidGenerator, VectorMemoryRecall, DEFAULT_OLLAMA_BASE_URL,
ONNX_CACHE_SUBDIR, RECOMMENDED_ONNX_MODELS, VECTOR_HTTP_ENABLED, VECTOR_ONNX_ENABLED,
};
pub mod dto;
@ -1552,6 +1554,14 @@ pub struct BackendCore {
pub plugin_registry_store: Arc<dyn PluginRegistryStore>,
/// Manifest validator exposed for the Tauri asset protocol adapter.
pub plugin_manifest_validator: Arc<dyn PluginManifestValidator>,
/// Read project-scoped plugin activation and assignment settings.
pub list_project_plugin_settings: Arc<ListProjectPluginSettings>,
/// Enable or disable an installed plugin for one project.
pub set_project_plugin_enabled: Arc<SetProjectPluginEnabled>,
/// Assign or unassign a plugin skill for a project agent.
pub mutate_agent_plugin_skill: Arc<MutateAgentPluginSkill>,
/// Assign or unassign a plugin MCP tool for a project agent.
pub mutate_agent_plugin_tool: Arc<MutateAgentPluginTool>,
// --- Templates & sync (L7) ---
/// Create a template in the global store.
pub create_template: Arc<CreateTemplate>,
@ -1827,6 +1837,16 @@ impl BackendCore {
let plugin_storage_store = Arc::clone(&plugin_storage) as Arc<dyn PluginStorageStore>;
let plugin_manifest_validator =
Arc::clone(&plugin_validator) as Arc<dyn PluginManifestValidator>;
let project_plugin_settings =
Arc::new(FsProjectPluginSettingsStore::new(Arc::clone(&fs_port)));
let project_plugin_settings_store =
Arc::clone(&project_plugin_settings) as Arc<dyn ProjectPluginSettingsStore>;
let project_plugin_resolver = Arc::new(ProjectPluginResolver::new(
Arc::clone(&project_plugin_settings_store),
Arc::clone(&plugin_package_store),
Arc::clone(&plugin_registry_store),
Arc::clone(&plugin_manifest_validator),
));
let plugin_mcp_supervisor_port =
Arc::clone(&plugin_mcp_supervisor) as Arc<dyn PluginMcpSupervisor>;
@ -2355,6 +2375,10 @@ impl BackendCore {
app_data_dir.to_string_lossy().into_owned(),
));
let skill_store_port = Arc::clone(&skill_store) as Arc<dyn SkillStore>;
let assigned_skill_resolver = Arc::new(
AssignedSkillResolver::new(Arc::clone(&skill_store_port))
.with_plugin_skills(Arc::clone(&project_plugin_resolver)),
);
// Memory store + naïve recall (LOT A/B — §14.5.1/§14.5.4). Built here so the
// recall port can be injected into LaunchAgent below (it composes the project
@ -2455,8 +2479,9 @@ impl BackendCore {
&prompt_store_port,
)));
let agent_capabilities =
Arc::new(ResolveAgentCapabilities::new(Arc::clone(&skill_store_port)));
let agent_capabilities = Arc::new(ResolveAgentCapabilities::with_resolver(Arc::clone(
&assigned_skill_resolver,
)));
let create_agent = Arc::new(CreateAgentFromScratch::new(
Arc::clone(&contexts_port),
@ -2505,6 +2530,7 @@ impl BackendCore {
Arc::clone(&memory_recall_port),
Some(Arc::clone(&check_embedder_suggestion)),
)
.with_assigned_skill_resolver(Arc::clone(&assigned_skill_resolver))
.with_structured_routing_mode(StructuredRoutingMode::HumanPtyFallback)
.with_permission_store(Arc::clone(&permission_store_port))
.with_system_permission_store(Arc::clone(&system_permission_store_port))
@ -2562,6 +2588,7 @@ impl BackendCore {
Arc::clone(&memory_recall_port),
Some(Arc::clone(&check_embedder_suggestion)),
)
.with_assigned_skill_resolver(Arc::clone(&assigned_skill_resolver))
.with_structured_routing_mode(StructuredRoutingMode::RequireStructured)
.with_permission_store(Arc::clone(&permission_store_port))
.with_system_permission_store(Arc::clone(&system_permission_store_port))
@ -2739,9 +2766,9 @@ impl BackendCore {
// Lecture d'un skill par nom pour l'outil MCP `idea_skill_read` : compose
// le SkillStore et le manifeste agent afin d'autoriser uniquement les
// skills assignés au requester courant.
let read_skill = Arc::new(ReadSkill::new(
let read_skill = Arc::new(ReadSkill::with_resolver(
Arc::clone(&contexts_port),
Arc::clone(&skill_store_port),
Arc::clone(&assigned_skill_resolver),
));
let assign_skill = Arc::new(AssignSkillToAgent::new(
Arc::clone(&contexts_port),
@ -2751,6 +2778,25 @@ impl BackendCore {
Arc::clone(&contexts_port),
Arc::clone(&events_port),
));
let list_project_plugin_settings = Arc::new(ListProjectPluginSettings::new(
Arc::clone(&project_plugin_resolver),
Arc::clone(&plugin_package_store),
Arc::clone(&plugin_manifest_validator),
));
let set_project_plugin_enabled = Arc::new(SetProjectPluginEnabled::new(
Arc::clone(&project_plugin_settings_store),
Arc::clone(&plugin_package_store),
));
let mutate_agent_plugin_skill = Arc::new(MutateAgentPluginSkill::new(
Arc::clone(&project_plugin_settings_store),
Arc::clone(&contexts_port),
Arc::clone(&project_plugin_resolver),
));
let mutate_agent_plugin_tool = Arc::new(MutateAgentPluginTool::new(
Arc::clone(&project_plugin_settings_store),
Arc::clone(&contexts_port),
Arc::clone(&project_plugin_resolver),
));
// --- Memory use cases (LOT A — §14.5.1) ---
// `memory_store` / `memory_store_port` / `memory_recall_port` are built
@ -3595,6 +3641,10 @@ impl BackendCore {
plugin_package_store: Arc::clone(&plugin_packages),
plugin_registry_store: Arc::clone(&plugin_registry_store),
plugin_manifest_validator: Arc::clone(&plugin_manifest_validator),
list_project_plugin_settings,
set_project_plugin_enabled,
mutate_agent_plugin_skill,
mutate_agent_plugin_tool,
ticket_tool_binder,
template_tool_binder,
managed_temp_tool_binder,