Goal
Upstream-shaped feature (vanilla rule: issue here + upstream PR, we carry the delta): add a per-role instructions file to ao's project config so the daemon injects project-specific standing instructions into a session's system prompt by role — orchestrator vs worker — instead of projects smuggling role policy through the shared repo CLAUDE.md.
Proposed shape:
RoleOverride (backend/internal/domain/projectconfig.go) currently carries only harness + agent config. Add InstructionsFile (path relative to the project root, absolute allowed); buildSystemPrompt (backend/internal/session_manager/manager.go) reads and appends its contents after the built-in per-kind prompt for that SessionKind, at spawn and restore (restore already recomputes prompts). Missing/unreadable file: log a warning, spawn without it — never block a spawn.
How we got here
ao already types sessions (KindWorker/KindOrchestrator) and injects hardcoded per-kind system prompts. But there is no vanilla slot for a project's own standing policy per role, so we put orchestrator policy into the repo CLAUDE.md — which every session in the checkout loads — and an interactive session acted on it and double-dispatched workers (2026-07-06 incident). The interim fix is a prose pointer in CLAUDE.md keyed on the injected role prompt; this feature makes the injection native and deletes the pointer. Upstream is already moving this direction (AgentWrapper#2361 enriched the coordinator prompt; AgentWrapper#2444 custom AO agent prompts for Kiro).
Acceptance criteria
Context / pointers
backend/internal/domain/projectconfig.go (RoleOverride), backend/internal/session_manager/manager.go (buildSystemPrompt, orchestratorPrompt, workerOrchestratorPrompt)
- Depends conceptually on the trackerIntake+policy-restructure ticket (provides
.claude/orchestrator-policy.md); no hard ordering
- Priority: P2 · type: feature
Goal
Upstream-shaped feature (vanilla rule: issue here + upstream PR, we carry the delta): add a per-role instructions file to ao's project config so the daemon injects project-specific standing instructions into a session's system prompt by role — orchestrator vs worker — instead of projects smuggling role policy through the shared repo CLAUDE.md.
Proposed shape:
RoleOverride(backend/internal/domain/projectconfig.go) currently carries only harness + agent config. AddInstructionsFile(path relative to the project root, absolute allowed);buildSystemPrompt(backend/internal/session_manager/manager.go) reads and appends its contents after the built-in per-kind prompt for thatSessionKind, at spawn and restore (restore already recomputes prompts). Missing/unreadable file: log a warning, spawn without it — never block a spawn.How we got here
ao already types sessions (
KindWorker/KindOrchestrator) and injects hardcoded per-kind system prompts. But there is no vanilla slot for a project's own standing policy per role, so we put orchestrator policy into the repo CLAUDE.md — which every session in the checkout loads — and an interactive session acted on it and double-dispatched workers (2026-07-06 incident). The interim fix is a prose pointer in CLAUDE.md keyed on the injected role prompt; this feature makes the injection native and deletes the pointer. Upstream is already moving this direction (AgentWrapper#2361 enriched the coordinator prompt; AgentWrapper#2444 custom AO agent prompts for Kiro).Acceptance criteria
RoleOverride.InstructionsFilein domain config with validation (path sanity) + testsbuildSystemPromptappends file contents per kind at spawn and restore; missing file degrades gracefully (warn, continue); tests cover both kinds + restore pathcd backend && go build ./... && go vet ./... && go test ./...--modelonao spawn(upstream-shaped) #1 per-session --model, Addcodex-fuguagent adapter (upstream-shaped, like #1) #3 codex-fugu)backend/internal/session_manager/**(sensitive path — autonomous merge forbidden); report merge-ready insteadContext / pointers
backend/internal/domain/projectconfig.go(RoleOverride),backend/internal/session_manager/manager.go(buildSystemPrompt,orchestratorPrompt,workerOrchestratorPrompt).claude/orchestrator-policy.md); no hard ordering