From 473d80224880dd718cb2612fd49b987cd6097b2c Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 24 May 2026 17:38:53 +0000 Subject: feat(executor): MCP-oriented planning preamble, applied by ContainerRunner (Phase 2) Rewrites the planning preamble to point the agent at the four MCP tools (ask_user/report_summary/spawn_subtask/record_progress) instead of the CLAUDOMATOR_QUESTION_FILE / CLAUDOMATOR_SUMMARY_FILE conventions: ask_user ends the turn, report_summary replaces the summary file, spawn_subtask replaces the POST-to-/api/tasks planning step. Git discipline is retained. ContainerRunner previously applied no preamble at all; it now prepends this preamble (via buildAgentInstructions) when the MCP back-channel is active and skip_planning is false, so the in-container agent is actually guided to use the tools. Gemini agents (no MCP) are unaffected. https://claude.ai/code/session_01SESwn7kQ7oP62trWw6pc39 --- internal/executor/container.go | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'internal/executor/container.go') diff --git a/internal/executor/container.go b/internal/executor/container.go index f0f728c..78c3ed7 100644 --- a/internal/executor/container.go +++ b/internal/executor/container.go @@ -305,12 +305,6 @@ func (r *ContainerRunner) runContainer(ctx context.Context, t *task.Task, e *sto return fmt.Errorf("writing env file: %w", err) } - // Inject custom instructions via file to avoid CLI length limits - instructionsFile := filepath.Join(workspace, ".claudomator-instructions.txt") - if err := os.WriteFile(instructionsFile, []byte(t.Agent.Instructions), 0644); err != nil { - return fmt.Errorf("writing instructions: %w", err) - } - // Per-task MCP back-channel: mint a scoped token bound to this run's channel // and write an mcp-config pointing the agent at the host agent MCP server. mcpEnabled := false @@ -327,6 +321,15 @@ func (r *ContainerRunner) runContainer(ctx context.Context, t *task.Task, e *sto mcpEnabled = true } + // Inject custom instructions via file to avoid CLI length limits. When the + // MCP back-channel is active, prepend the planning preamble that points the + // agent at the ask_user/report_summary/spawn_subtask/record_progress tools. + instructions := buildAgentInstructions(t, mcpEnabled) + instructionsFile := filepath.Join(workspace, ".claudomator-instructions.txt") + if err := os.WriteFile(instructionsFile, []byte(instructions), 0644); err != nil { + return fmt.Errorf("writing instructions: %w", err) + } + args := r.buildDockerArgs(workspace, agentHome, e.TaskID) innerCmd := r.buildInnerCmd(t, e, isResume, mcpEnabled) @@ -501,6 +504,17 @@ func (r *ContainerRunner) buildDockerArgs(workspace, claudeHome, taskID string) // (the workspace is bind-mounted at /workspace). const mcpConfigContainerPath = "/workspace/.claudomator-mcp.json" +// buildAgentInstructions returns the agent's instructions, prepending the +// MCP-tool planning preamble when the back-channel is active and planning is +// not skipped. +func buildAgentInstructions(t *task.Task, mcpEnabled bool) string { + instructions := t.Agent.Instructions + if mcpEnabled && !t.Agent.SkipPlanning { + instructions = withPlanningPreamble(instructions) + } + return instructions +} + // writeMCPConfig writes a claude CLI mcp-config that registers the per-task // agent MCP server over HTTP with a bearer token. func writeMCPConfig(workspace, mcpURL, token string) error { -- cgit v1.2.3