From e2ba6c86344786f45b8eb78189880bfa3a86822b Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Tue, 23 Dec 2025 15:02:40 +0700 Subject: [PATCH] Add developer_instructions to Codex wrapper --- .../server/agent/orchestrator-instructions.ts | 52 +++++++ .../server/agent/providers/claude-agent.ts | 129 +----------------- .../src/server/agent/providers/codex-agent.ts | 50 ++++++- 3 files changed, 97 insertions(+), 134 deletions(-) create mode 100644 packages/server/src/server/agent/orchestrator-instructions.ts diff --git a/packages/server/src/server/agent/orchestrator-instructions.ts b/packages/server/src/server/agent/orchestrator-instructions.ts new file mode 100644 index 000000000..d1eaace83 --- /dev/null +++ b/packages/server/src/server/agent/orchestrator-instructions.ts @@ -0,0 +1,52 @@ +/** + * Returns orchestrator mode instructions to append to the system prompt. + * These instructions are from CLAUDE.md and guide agents on how to work + * effectively in this repository. + */ +export function getOrchestratorModeInstructions(): string { + return ` + +## Orchestrator Mode Instructions + +When asked to go into orchestrator mode, you must **only accomplish tasks by managing other agents**. Do NOT perform the work yourself. + +### Agent Control Best Practices + +- **When agent control tool calls fail**, make sure you list agents before trying to launch another one. It could just be a wait timeout. +- **Always prefix agent titles** so we can tell which ones are running under you (e.g., "🎭 Feature Implementation", "🎭 Design Discussion"). +- **Launch agents in the most permissive mode**: Use full access or bypass permissions mode. +- **Set cwd to the repository root** - The agent's working directory should usually be the repo root. + +### Agent Use Cases + +You can run agents to: +- **Implement a task** - Spawn an agent to write code and implement features +- **Have a design discussion** - Discuss architecture and design decisions +- **Have a pairing session** - Collaborate on problem-solving +- **Test some feature** - Run tests and verify functionality +- **Do investigation** - Research and explore the codebase + +### Clarifying Ambiguous Requests + +**CRITICAL:** When user requests are ambiguous or unclear: + +1. **Research first** - Spawn an investigation agent to understand the current state +2. **Ask clarifying questions** - After research, ask the user specific questions about what they want +3. **Present options** - Offer multiple approaches with trade-offs +4. **Get explicit confirmation** - Never assume what the user wants + +### Investigation vs Implementation + +**CRITICAL:** When asked to investigate: + +- **Investigate only** - Do not implement fixes during investigation unless explicitly requested +- **Report findings** - Share discovered information clearly +- **Ask for direction** - After investigation, ask the user what to do next + +### Tool Usage Discipline + +- **Do not ask users to run commands** β€” Always run the commands yourself. +- **Do not repeat the user’s instructions verbatim** β€” Summarize them in your own words. +- **Be explicit about results** β€” Tell the user what happened after every command. +`; +} diff --git a/packages/server/src/server/agent/providers/claude-agent.ts b/packages/server/src/server/agent/providers/claude-agent.ts index c7292b110..a773d1586 100644 --- a/packages/server/src/server/agent/providers/claude-agent.ts +++ b/packages/server/src/server/agent/providers/claude-agent.ts @@ -40,6 +40,7 @@ import type { PersistedAgentDescriptor, } from "../agent-sdk-types.js"; import { resolvePaseoPort } from "../../config.js"; +import { getOrchestratorModeInstructions } from "../orchestrator-instructions.js"; const CLAUDE_CAPABILITIES: AgentCapabilityFlags = { supportsStreaming: true, @@ -77,133 +78,7 @@ const VALID_CLAUDE_MODES = new Set( DEFAULT_MODES.map((mode) => mode.id) ); -/** - * Returns orchestrator mode instructions to append to the system prompt. - * These instructions are from CLAUDE.md and guide agents on how to work - * effectively in this repository. - */ -function getOrchestratorModeInstructions(): string { - return ` - -## Orchestrator Mode Instructions - -When asked to go into orchestrator mode, you must **only accomplish tasks by managing other agents**. Do NOT perform the work yourself. - -### Agent Control Best Practices - -- **When agent control tool calls fail**, make sure you list agents before trying to launch another one. It could just be a wait timeout. -- **Always prefix agent titles** so we can tell which ones are running under you (e.g., "🎭 Feature Implementation", "🎭 Design Discussion"). -- **Launch agents in the most permissive mode**: Use full access or bypass permissions mode. -- **Set cwd to the repository root** - The agent's working directory should usually be the repo root. - -### Agent Use Cases - -You can run agents to: -- **Implement a task** - Spawn an agent to write code and implement features -- **Have a design discussion** - Discuss architecture and design decisions -- **Have a pairing session** - Collaborate on problem-solving -- **Test some feature** - Run tests and verify functionality -- **Do investigation** - Research and explore the codebase - -### Clarifying Ambiguous Requests - -**CRITICAL:** When user requests are ambiguous or unclear: - -1. **Research first** - Spawn an investigation agent to understand the current state -2. **Ask clarifying questions** - After research, ask the user specific questions about what they want -3. **Present options** - Offer multiple approaches with trade-offs -4. **Get explicit confirmation** - Never assume what the user wants - -### Investigation vs Implementation - -**CRITICAL:** When asked to investigate: - -- **Investigation agents MUST NOT fix issues** - They should only identify, document, and report problems -- **Always ask for confirmation** - After investigation, present findings and ask: "Should I proceed with implementing fixes?" -- **Only implement if explicitly requested** - Don't auto-fix without user approval - -### Strategic Planning and Task Breakdown - -**CRITICAL:** For large or complex tasks, you MUST plan strategically before spawning agents: - -1. **Break down the work** into small, focused tasks -2. **Design the agent workflow**: What agents will you need? In what order? -3. **Plan checkpoints**: Where do you need review agents? Test agents? Integration points? -4. **Ensure each agent commits their work** before moving to the next phase -5. **Plan for validation**: How will you verify each piece works before proceeding? - -Example workflow for a large feature: -- Investigation agent β†’ Design discussion agent β†’ Multiple implementation agents (one per component) β†’ Test agent β†’ Review agent β†’ Integration agent - -### Rigorous Agent Interrogation - -**CRITICAL:** Agents start with ZERO context about your task. You must always provide complete context in your initial prompt. - -When working with agents, you must dig deep and challenge them rigorously: - -#### For Implementation Agents - -- **Don't accept surface-level completion**: Ask them to show you the code they implemented -- **Trace the implementation**: Ask them to walk through the code flow step by step -- **Uncover gaps**: Dig hard to find possible gaps in their understanding - - "Show me exactly where you handle error case X" - - "What happens if the user does Y before Z?" - - "Walk me through the data flow from input to output" -- **Ask for alternatives**: "Provide 3 different solutions to this problem and explain the trade-offs of each" -- **Rank and compare**: "Rank these approaches by performance, maintainability, and complexity" -- **Challenge their decisions**: Play devil's advocate on their architectural choices - - "Why not use approach X instead?" - - "What are the downsides of your solution?" - - "How will this scale?" - -#### For Investigation/Debugging Agents - -- **Don't stop at the first answer**: Keep digging deeper -- **Explore different angles**: "What are 3 other possible causes?" -- **Request proof**: "Show me the specific code that proves this hypothesis" -- **Challenge assumptions**: "How do you know that's the root cause? What else could it be?" -- **Ask for comprehensive analysis**: "What are all the places in the codebase that could be affected?" - -#### For Review Agents - -- **Security review**: "What are the security implications? Any OWASP vulnerabilities?" -- **Edge cases**: "What edge cases are not handled?" -- **Performance**: "Where are the performance bottlenecks?" -- **Maintainability**: "How maintainable is this code? What would make it better?" - -### Debugging with Logging and Playwright - -**CRITICAL:** When debugging frontend or server issues: - -- **Frontend debugging**: Use Playwright MCP to interact with the app at \`http://localhost:8081\` - - Take screenshots to verify UI state - - Click through flows to reproduce issues - - Use browser console to check for errors - - Verify network requests and responses -- **Server debugging**: Add strategic logging to trace execution - - Log request/response payloads - - Log state transitions - - Log error conditions - - Use server logs to correlate with frontend behavior -- **Full-stack debugging**: Combine both approaches - - Use Playwright to trigger frontend actions - - Check server logs to see backend behavior - - Verify data flow from client β†’ server β†’ client - -### Agent Management Principles - -- **Keep agents focused** - Each agent should have a clear, specific responsibility -- **You can talk to them** - Send prompts and guidance as they work -- **Monitor progress** - Check status and provide feedback -- **Always provide context** - Remember: agents start with zero knowledge of your task -- **Verify work rigorously** - Don't trust, verify. Ask agents to prove their work -- **Commit frequently** - Ensure each agent commits their changes before moving on -- **Plan for quality gates** - Use test and review agents as checkpoints - -**CRITICAL: ALWAYS RUN TYPECHECK AFTER EVERY CHANGE.** -`; -} - +// Orchestrator instructions moved to shared module. type ClaudeAgentConfig = AgentSessionConfig & { provider: "claude" }; export type ClaudeContentChunk = { type: string; [key: string]: any }; diff --git a/packages/server/src/server/agent/providers/codex-agent.ts b/packages/server/src/server/agent/providers/codex-agent.ts index 11fc7f192..0068c0063 100644 --- a/packages/server/src/server/agent/providers/codex-agent.ts +++ b/packages/server/src/server/agent/providers/codex-agent.ts @@ -39,11 +39,13 @@ import type { ListPersistedAgentsOptions, PersistedAgentDescriptor, } from "../agent-sdk-types.js"; +import { getOrchestratorModeInstructions } from "../orchestrator-instructions.js"; type CodexAgentConfig = AgentSessionConfig & { provider: "codex" }; type CodexExtraConfig = { agentControlMcpUrl?: string; + developerInstructions?: string; }; type CodexWrapperInfo = { @@ -282,7 +284,8 @@ function resolveAgentControlMcpUrl(config: CodexAgentConfig): string | null { async function createCodexWrapperScript( realCodexPath: string, - mcpUrl: string + mcpUrl: string, + developerInstructions: string ): Promise { const templatePath = await resolveCodexWrapperTemplatePath(); const template = await fs.readFile(templatePath, "utf8"); @@ -290,7 +293,11 @@ async function createCodexWrapperScript( const wrapperPath = path.join(dir, "codex-wrapper"); const content = template .replace("__REAL_CODEX__", escapeBashValue(realCodexPath)) - .replace("__MCP_URL__", escapeBashValue(mcpUrl)); + .replace("__MCP_URL__", escapeBashValue(mcpUrl)) + .replace( + "__DEV_INSTRUCTIONS__", + escapeBashTomlValue(encodeTomlBasicString(developerInstructions)) + ); await fs.writeFile(wrapperPath, content, { mode: 0o700 }); await fs.chmod(wrapperPath, 0o700); return { path: wrapperPath, dir }; @@ -325,11 +332,35 @@ function appendCallerAgentId(url: string, agentId: string): string { } } -function escapeBashValue(value: string): string { +function resolveDeveloperInstructions(config: CodexAgentConfig): string | null { + const extras = config.extra?.codex as CodexExtraConfig | undefined; + const override = + extras && typeof extras === "object" + ? extras.developerInstructions + : undefined; + if (typeof override === "string" && override.trim().length > 0) { + return override.trim(); + } + const defaultInstructions = getOrchestratorModeInstructions().trim(); + return defaultInstructions.length > 0 ? defaultInstructions : null; +} + +function encodeTomlBasicString(value: string): string { return value .replace(/\\/g, "\\\\") .replace(/"/g, '\\"') - .replace(/\$/g, "\\$"); + .replace(/\r?\n/g, "\\n"); +} + +function escapeBashValue(value: string): string { + return value + .replace(/"/g, '\\"') + .replace(/\$/g, "\\$") + .replace(/`/g, "\\`"); +} + +function escapeBashTomlValue(value: string): string { + return value.replace(/\$/g, "\\$").replace(/`/g, "\\`"); } export class CodexAgentClient implements AgentClient { @@ -433,14 +464,19 @@ export class CodexAgentClient implements AgentClient { config: CodexAgentConfig ): Promise { const mcpUrl = resolveAgentControlMcpUrl(config); - if (!mcpUrl || !this.baseCodexPath) { - if (mcpUrl && !this.baseCodexPath) { + const developerInstructions = resolveDeveloperInstructions(config); + if ((!mcpUrl && !developerInstructions) || !this.baseCodexPath) { + if ((mcpUrl || developerInstructions) && !this.baseCodexPath) { console.warn("[Codex] MCP wrapper skipped (no codex binary path available)"); } return { codex: new Codex(this.baseOptions) }; } - const wrapper = await createCodexWrapperScript(this.baseCodexPath, mcpUrl); + const wrapper = await createCodexWrapperScript( + this.baseCodexPath, + mcpUrl ?? "", + developerInstructions ?? "" + ); const env = { ...process.env, ...(this.baseOptions.env ?? {}),