ulysses-protocol
Skill64 starsChanged 4 months agoMITView on GitHub
Thoughtbox-first Ulysses workflow for surprise-gated debugging. Use this when debugging gets uncertain and you need explicit plan, outcome, and reflection discipline without relying on local shell state.
- Reads credentials
In this repository102 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- assumptionsSkill
- capture-learningSkill
- Codex-opus-4-6-promptingSkill
- Codex-promptSkill
- mcp-code-modeSkill
- deploy-team-hubSkill
- diagramSkill
- distillSkill
- effect-tsSkill
- escalateSkill
- evalSkill
- experimentSkill
- hddSkill
- hub-auditSkill
- hub-collabSkill
- implementSkill
- knowledgeSkill
- peer-notebook-delivery-guardSkill
- research-taskSkill
- session-reviewSkill
- source-command-hdd-decideSkill
- source-command-hdd-hddSkill
- source-command-hdd-researchSkill
- source-command-hdd-stage-adrSkill
- source-command-hdd-validateSkill
- statusSkill
- supabaseSkill
- synthesizeSkill
- tasteSkill
- teamSkill
- test-suiteSkill
- theseus-protocolSkill
- thoughtbox:debugSkill
- thoughtbox:decisionSkill
- thoughtbox:evolutionSkill
- thoughtbox:knowledge-querySkill
- thoughtbox:onboardSkill
- thoughtbox:refactorSkill
- thoughtbox:researchSkill
- thoughtbox:session-reviewSkill
- thoughtbox-teamSkill
- ulc-loopSkill
- workflow-brainstormingSkill
- workflow-ideationSkill
- workflow-reflectionSkill
- workflow-revisionSkill
- workflows-compoundSkill
- workflowSkill
- workflows-planSkill
- workflows-reviewSkill
- workflows-workSkill
- workflow-tournamentSkill
- assumptionsSkill
- capture-learningSkill
- claude-opus-4-6-promptingSkill
- claude-promptSkill
- mcp-code-modeSkill
- deploy-team-hubSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
12 rules. About 0 are common, 4 are distinctive, and 8 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
8
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 18
Do not use .ulysses/ files or scripts/ulysses.sh as authoritative state.
- Very specific: line 19
Do not use legacy direct handles like thoughtbox_gateway or thoughtbox_ulysses as the interaction surface when Code Mode is available.
- Very specific: line 48
If you need schema or example confirmation, call thoughtbox_search before executing.
- Very specific: line 50
Use thoughtbox_execute and call tb.ulysses({ operation: ...
- Very specific: line 109
Do not act before plan is recorded.
- Very specific: line 134
If the returned state reaches S=2 with no active_step, stop mutating work and move to reflect.
- Very specific: line 168
After reflect, you may optionally launch debugger or researcher agents to test competing explanations.
- Distinctive: line 181
Use the returned server state as the only source of truth.
- Distinctive: line 205
No action without a recorded primary step and recovery step with bound validator cells.
- Distinctive: line 237
Keep cells deterministic. The same observed input must produce the same verdict.
- Distinctive: line 239
Write the cell before taking the step.
- Very specific: line 243
Use subagents only after reflect when more evidence would help.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Ulysses Protocol
Ulysses is a Thoughtbox-owned debugging protocol.
The invariants live in the server-side Ulysses implementation behind
tb.ulysses(...).
The durable trace lives in Thoughtbox thoughts and knowledge.
Codex hooks only enforce the current server state.
Do not use .ulysses/ files or scripts/ulysses.sh as authoritative state.
Do not use legacy direct handles like thoughtbox_gateway or thoughtbox_ulysses
as the interaction surface when Code Mode is available.
API Surface
The current public Thoughtbox MCP surface is Code Mode:
- Discovery:
thoughtbox_search - Execution:
thoughtbox_execute - Ulysses operations:
tb.ulysses({ ... }) - Validator notebook setup:
tb.notebook.create(...)andtb.notebook.addCell(...)
Each thoughtbox_execute call should contain at most one state-mutating
Ulysses operation. Read-only confirmation calls such as
tb.ulysses({ operation: "status" }) are safe to use for state checks.
Example execution wrapper:
async () => {
return await tb.ulysses({
operation: "status",
});
}Runtime Contract
- Protocol entry is explicit-only in v1.
- If you need schema or example confirmation, call
thoughtbox_searchbefore executing. - Use
thoughtbox_executeand calltb.ulysses({ operation: ... })for every protocol transition. - Hooks may block mutating work when the server reports
S=2; read-only inspection remains allowed. - Helper agents may gather evidence after
reflect, but only the coordinator callstb.ulysses.
Commands
init
Required inputs:
- Problem statement
- Optional constraints
Call:
async () => {
return await tb.ulysses({
operation: "init",
problem: "<problem>",
constraints: ["<optional constraint>"],
});
}Then record a structured Thoughtbox thought summarizing the debugging context.
plan
Required inputs:
- Primary action
- Recovery action
- Primary validator: a notebook code cell that decides the primary step's outcome
- Recovery validator: a notebook code cell that decides the recovery step's outcome
- Optional
irreversible
Each validator is a code cell that reads observed data from process.env.TB_OBSERVED_PATH and writes a verdict to process.env.TB_VERDICT_PATH. Use the auto-materialised helper:
import { observed, pass, fail } from "./tb-validate.js";
const d = observed<{ errors: number }>();
d.errors === 0 ? pass("clean run") : fail(`${d.errors} errors`, d);Cells are snapshotted at plan time (source + package.json + tsconfig hashed with sha256). Later edits to the notebook cannot influence the verdict.
Call:
async () => {
return await tb.ulysses({
operation: "plan",
primary: "<primary action>",
recovery: "<recovery action>",
irreversible: false,
primaryValidator: { notebookId: "<id>", cellId: "<id>" },
recoveryValidator: { notebookId: "<id>", cellId: "<id>" },
});
}Do not act before plan is recorded.
outcome
Required inputs:
observed: any JSON-serialisable value piped into the validator cell bound for the current S phase. The cell's pass/fail verdict — not any agent claim — drives the state machine.- Optional
details(free-form notes attached to the history event)
Call:
async () => {
return await tb.ulysses({
operation: "outcome",
observed: { errorCount: 3, lastLog: "..." },
details: "<what happened>",
});
}State transitions derived from the verdict:
- Validator pass → assessment
expected, S→0, checkpoint - Validator fail at S=1 → assessment
unexpected-unfavorable, S→2, recovery pending - Validator fail at S=2 → forbidden_moves recorded, REFLECT required
- Snapshot hash mismatch (predicate tampered with after bind) → forces S=2 immediately, records
validator_tamperinghistory event
If the returned state reaches S=2 with no active_step, stop mutating work and move to reflect.
bind_final_validator
Pin a notebook code cell as the predicate that gates complete(resolved). The cell is snapshotted and pinned at bind time.
Call:
async () => {
return await tb.ulysses({
operation: "bind_final_validator",
notebookId: "<id>",
cellId: "<id>",
});
}reflect
Required inputs:
- Falsifiable hypothesis
- Falsification criteria
Call:
async () => {
return await tb.ulysses({
operation: "reflect",
hypothesis: "<hypothesis>",
falsification: "<what would disprove it>",
});
}After reflect, you may optionally launch debugger or researcher agents to test competing explanations. They return evidence only. The coordinator records the next plan or outcome.
status
Call:
async () => {
return await tb.ulysses({
operation: "status",
});
}Use the returned server state as the only source of truth.
complete
terminalState='resolved' is hard-gated by the final validator if one is bound. The agent must supply observed data; the validator runs against the pinned snapshot, and the terminal is rejected if the validator returns fail or its hash does not match.
Call:
async () => {
return await tb.ulysses({
operation: "complete",
terminalState: "resolved",
observed: { errorCount: 0, passingTests: 42 },
summary: "<transferable learning>",
});
}The other terminals (insufficient_information, environment_compromised) do not run the final validator and accept the existing call shape.
Completion should yield both protocol closure and a reusable knowledge artifact in Thoughtbox.
Invariants
- No action without a recorded primary step and recovery step with bound validator cells.
- Outcomes are deterministic: the validator cell — not the agent — decides assessment.
- Predicates are frozen at plan time by snapshot hash; tampering forces S=2.
- Surprises accumulate on the server, not in local files.
reflectis mandatory atS=2.- Hypotheses must be falsifiable.
complete(resolved)is hard-gated by the final validator when bound.- Knowledge capture is part of completion, not an optional afterthought.
Authoring Validator Cells
A validator cell is an ordinary code cell in a Thoughtbox notebook. Use the auto-materialised helper for ergonomics:
import { observed, pass, fail } from "./tb-validate.js";
interface Observed {
errorCount: number;
status: "ok" | "degraded" | "down";
}
const d = observed<Observed>();
if (d.status === "ok" && d.errorCount === 0) {
pass("system healthy");
} else {
fail(`status=${d.status}, errors=${d.errorCount}`, d);
}Verdict semantics: pass → assessment expected. fail → assessment unexpected-unfavorable. Anything else (no verdict file, malformed JSON, crash, timeout) → pass=false, reason="malformed_verdict".
Authoring rules:
- Keep cells deterministic. The same observed input must produce the same verdict.
- Make the predicate as specific as possible — that's where the anti-gaming property comes from.
- Write the cell before taking the step; revising it after seeing the observed data defeats the purpose.
Subagent Use
Use subagents only after reflect when more evidence would help.
Good uses:
- Reproduce a hypothesis independently
- Compare two candidate explanations
- Gather targeted code or log evidence
Bad uses:
- Letting a subagent call
tb.ulysses - Letting a hook spawn subagents automatically
- Treating subagents as owners of protocol state
References
- Public MCP surface:
thoughtbox_search,thoughtbox_execute - Ulysses SDK call:
tb.ulysses({ operation: ... }) - Durable context and thought trace: Thoughtbox session, thought, and knowledge operations through Code Mode
- Protocol implementation:
src/protocol/ulysses-tool.ts - Specification reference:
references/protocol-spec.md
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

