export type BootstrapInput = { agentId: string; openclawSessionKey: string; workspace: string; /** Skills XML block extracted from the OpenClaw system prompt, if any */ skillsBlock?: string; /** Subset of OpenClaw context files present in the workspace (for persona/identity) */ workspaceContextFiles?: string[]; }; /** * Build the one-time bootstrap message injected at the start of a new Claude session. * This tells Claude it is operating as an OpenClaw contractor agent. * Must NOT be re-injected on every turn. */ export function buildBootstrap(input: BootstrapInput): string { const contextFiles = input.workspaceContextFiles ?? []; const hasSoul = contextFiles.includes("SOUL.md"); const hasIdentity = contextFiles.includes("IDENTITY.md"); const lines = [ `You are operating as a contractor agent inside OpenClaw.`, ``, `## Context`, `- Agent ID: ${input.agentId}`, `- Session key: ${input.openclawSessionKey}`, `- Workspace: ${input.workspace}`, ``, `## Role`, `You receive tasks from OpenClaw users and complete them using your tools.`, `You do not need to manage your own session context — OpenClaw handles session routing.`, `Your responses go directly back to the user through OpenClaw.`, ``, `## Guidelines`, `- Work in the specified workspace directory.`, `- Be concise and action-oriented. Use tools to accomplish tasks rather than describing what you would do.`, `- Each message you receive contains the latest user request. Previous context is in your session memory.`, `- If a task is unclear, ask one focused clarifying question.`, ]; // Inject persona/identity context from OpenClaw workspace files. // These files define who this agent is and how it should behave. if (hasSoul || hasIdentity) { lines.push(``, `## Persona & Identity`); if (hasSoul) { lines.push( `Read ${input.workspace}/SOUL.md now (using the Read tool) and embody the persona and tone it describes.`, `SOUL.md defines your values, communication style, and boundaries — treat it as authoritative.`, ); } if (hasIdentity) { lines.push( `Read ${input.workspace}/IDENTITY.md now (using the Read tool) to understand your name, creature type, and personal vibe.`, `If IDENTITY.md is empty/template-only, you may fill it in as you develop your identity.`, ); } } // Memory system note: OpenClaw uses workspace/memory/*.md + MEMORY.md. // Claude Code also maintains per-project auto-memory at ~/.claude/projects//memory/. // Both are active; Claude Code's auto-memory is loaded automatically each session. // OpenClaw memory tools (memory_search, memory_get) are available as MCP tools // but require bridge-side implementations to execute (not yet wired). if (contextFiles.includes("MEMORY.md") || contextFiles.some(f => f.startsWith("memory/"))) { lines.push( ``, `## Memory`, `OpenClaw memory files exist in ${input.workspace}/memory/ and ${input.workspace}/MEMORY.md.`, `Use the Read tool to access these directly. For writing new memories, write to ${input.workspace}/memory/.md.`, ); } if (input.skillsBlock) { lines.push( ``, `## Skills`, `The following skills are available. When a task matches a skill's description:`, `1. Read the skill's SKILL.md using the Read tool (the field is the absolute path).`, `2. Follow the instructions in SKILL.md. Replace \`{baseDir}\` with the directory containing SKILL.md.`, `3. Run scripts using the Bash tool, NOT the \`exec\` tool (you have Bash, not exec).`, ``, input.skillsBlock, ); } return lines.join("\n"); }