diff --git a/cmd/supervisor/main.go b/cmd/supervisor/main.go index c7f9c7f..fae8886 100644 --- a/cmd/supervisor/main.go +++ b/cmd/supervisor/main.go @@ -43,6 +43,17 @@ func main() { os.Exit(1) } + protocolsPrompt, err := os.ReadFile(cfg.ConfigDir + "/protocols.md") + if err != nil { + logger.Error("read protocols.md", "path", cfg.ConfigDir+"/protocols.md", "err", err) + os.Exit(1) + } + + // prependProtocols prepends the shared protocols to a skill discipline file. + prependProtocols := func(skillPrompt []byte) string { + return string(protocolsPrompt) + "\n---\n\n" + string(skillPrompt) + } + tddPrompt, err := os.ReadFile(cfg.ConfigDir + "/tdd.md") if err != nil { logger.Error("read tdd.md", "path", cfg.ConfigDir+"/tdd.md", "err", err) @@ -114,7 +125,7 @@ func main() { reg := registry.New() reg.Register(tdd.New(tdd.Config{ SystemPrompt: string(systemPrompt), - SkillPrompt: string(tddPrompt), + SkillPrompt: prependProtocols(tddPrompt), DefaultModel: models.ChainFor("tdd", "")[0], ExecutorFn: buildOrch("tdd"), SessionsDir: cfg.SessionsDir, @@ -130,35 +141,35 @@ func main() { SessionsDir: cfg.SessionsDir, })) reg.Register(retrospective.New(retrospective.Config{ - SkillPrompt: string(retroPrompt), + SkillPrompt: prependProtocols(retroPrompt), DefaultModel: models.ChainFor("retrospective", "")[0], SessionsDir: cfg.SessionsDir, ExecutorFn: buildOrch("retrospective"), })) reg.Register(review.New(review.Config{ - SkillPrompt: string(reviewPrompt), + SkillPrompt: prependProtocols(reviewPrompt), DefaultModel: models.ChainFor("review", "")[0], ExecutorFn: buildOrch("review"), SessionsDir: cfg.SessionsDir, IngestBaseURL: cfg.IngestBaseURL, })) reg.Register(skilldebug.New(skilldebug.Config{ - SkillPrompt: string(debugPrompt), + SkillPrompt: prependProtocols(debugPrompt), DefaultModel: models.ChainFor("debug", "")[0], ExecutorFn: buildOrch("debug"), SessionsDir: cfg.SessionsDir, IngestBaseURL: cfg.IngestBaseURL, })) reg.Register(spec.New(spec.Config{ - SkillPrompt: string(specPrompt), + SkillPrompt: prependProtocols(specPrompt), DefaultModel: models.ChainFor("spec", "")[0], ExecutorFn: buildOrch("spec"), SessionsDir: cfg.SessionsDir, IngestBaseURL: cfg.IngestBaseURL, })) reg.Register(trainer.New(trainer.Config{ - ReaderPrompt: string(trainerReaderPrompt), - WriterPrompt: string(trainerWriterPrompt), + ReaderPrompt: prependProtocols(trainerReaderPrompt), + WriterPrompt: prependProtocols(trainerWriterPrompt), DefaultModel: models.ChainFor("trainer", "")[0], ExecutorFn: buildOrch("trainer"), SessionsDir: cfg.SessionsDir, diff --git a/config/supervisor/protocols.md b/config/supervisor/protocols.md index 500d24c..b3632a8 100644 --- a/config/supervisor/protocols.md +++ b/config/supervisor/protocols.md @@ -1,27 +1,55 @@ -# The Hyperguild Way +# The Hyperguild Way — Worker Protocols -These protocols are injected into every worker invocation. They define how you behave as a member of the hyperguild. +Injected into every worker invocation alongside the skill discipline file. +Defines the behavioral contract all workers must follow regardless of skill or model. + +--- ## Output contract -Every response is raw JSON matching the response schema. No preamble, no prose, no markdown. Malformed output is treated as a failed invocation. +Every response is raw JSON matching the skill's output schema. +- No preamble, no explanation, no prose before or after the JSON +- No markdown code fences around the JSON +- Malformed output is treated as a failed invocation +- If uncertain, return valid JSON anyway — put uncertainty in `message` ## Quality gate -`verified: true` only when a subprocess exit code confirms the outcome. Never self-assess. "I think the tests pass" is not verified. +`verified: true` means the artifact was independently confirmed correct: +- For code: the test runner exited 0 +- For files: the file exists at the path you wrote +- Never set `verified: true` based on self-assessment — only on external confirmation +- "I think the tests pass" is not verified. Run them. ## Escalation -If stuck after 3 attempts, return `status: error` with a clear `message` explaining why. Do not retry silently. Do not fabricate a passing result. +If stuck after a genuine attempt: +- Return `status: error` with a clear reason in `message` +- Do not retry silently or produce low-confidence output labelled as a pass +- Do not hallucinate file paths, test results, or exit codes +- Maximum 3 attempts per phase — if output is identical across two consecutive attempts, stop immediately -## Working offline +## Context usage -If brain context is absent from your prompt, proceed using your discipline file only. Note the gap in your `message` field: "no brain context available". +You may receive a `## Relevant knowledge` block and/or a `## Session history` block before your task. +- **Relevant knowledge**: patterns, decisions, and conventions from past sessions. Let them inform your approach — do not contradict them without reason. +- **Session history**: what has already happened in this session. Build on it, do not repeat it. +- If either block is absent, proceed with the skill discipline file only. Note the absence in `message` if it materially affects quality. -## Handoff format +## Handoff discipline -Structure your output so the next worker in a chain can consume it without transformation. Use the standard result schema. Do not add extra fields. +Structure output so the next worker in a chain can consume it without transformation: +- `file_path`: absolute path to the primary artifact you produced +- `runner_output`: verbatim stdout+stderr from the last command you ran (truncate to 2000 chars if longer) +- `message`: one sentence — what you did and whether it worked + +## Scope + +You have access to `Bash`, `Read`, and `Write` only. +- Do not attempt to call MCP tools or make HTTP requests +- Do not modify files outside `project_root` without explicit instruction +- If the task requires capabilities you do not have, return `status: error` ## Session logging -The Go skill handler records your invocation in the session log automatically. You do not need to do this yourself. +The Go skill handler records your invocation automatically. You do not need to log anything yourself.