Repository navigation
feat!: builder 2 — the builder soul, agent-led setup and peer messaging - #16
Merged
Merged
Conversation
Lutherwaves
marked this pull request as draft
October 21, 2026 19:25
…from coming back Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ng it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…d ledger no longer crashes builder Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…s walked through setup one step at a time Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd with it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ay out of the transcript Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…told The builder skill carries the thirteen tenets (rule and test each), the two settlements, a rule for when nobody answers, and a routing table with a fallback per row. Every reply that ships work starts with the builder report. The eval runner gains an optional per-fixture allow file, so an agent can run the fixture's tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…estions, and every explanation reads plainly The report comes once, at the end of a finished piece of work, not on every reply. An agent builds without waiting only when the person says they cannot answer or the run is unattended. Explanations follow ASD-STE100 and offer other formats in one line. Commits are signed Conventional Commits, never WIP, never --no-verify. Eval runs use an onboarded temp BUILDER_HOME. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Calls is now a list; each line needs a "because". The compact soul names the five report fields. The eval's last bullet now separates the two runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rules carry their scars and their guards Add the shape skill (an outcome-first issue template) and the canon skill (a rule template with incident, guard and supersedes), each with an eval fixture. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…, and the evals check only what the skills add - canon: a scarless rule in an agent file moves to the rules file as "none recorded — ask the owner"; conventions stay under ## Conventions; a one-line next-step offer follows the builder report. - shape: the squint test rejects titles that fit any request in any product. - Both SKILL.md files list their template order; tests/test_templates.py fails when a template drifts from it. - Expect bullets now name only behaviours the baseline did not show. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…is sent that they did not see Adds the reach skill and lib/reach.py: notes to the person go by notification, teammate messages are drafts the person approves, unnamed rooms are refused, duplicates and bursts are skipped, and every send and skip is logged to reach-log.jsonl in the builder home. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and no agent can widen its own send rules reach now hashes the recipient and normalised text, logs who got each message, requires a recipient for teammates and rooms, falls back to safe defaults on malformed rules, refuses to overwrite a corrupt reach.json, and the skill gates every send-rule change on the person's yes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ver with a brief A session names its role, hands out-of-lane work to its owner as a brief, writes its record before /compact, and never switches another session's checkout. matchblox is the cockpit when installed; every command that types into a session waits for the person's yes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ne each, the ones that wait for them first Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d leaves no session folders behind Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…l session Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…w homes, so their history follows them watch-limits moves to skills/budget, and code-graph's setup.sh, drift.sh and watcher-prompt.md move to skills/harness. Pure moves, plus the two paths that point at them; the content changes land in the next commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…itory's graph fresh in one skill - budget (was watch-limits): burn-proj.py --from-matchblox projects each account's weekly window from `matchblox usage --json`; exit 2 with the install line when matchblox is missing. cctop, ctx-wire, the metrics badges and update-metrics.sh are gone. - harness absorbs code-graph: baseline, provision, route (snippet inline), freshness, verify; drift.sh now detects edits on macOS too. - intake: reach as an optional, read-only source of the messages the person marks; a teammate's text is never a mark; matchblox replaces cctop. - validate.sh checks every skill's shape: "Use when", 60-150 lines, Common mistakes, Self-check. Evals cannot schedule jobs or register MCP servers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…budget and intake skip what they cannot trust - harness: when setup.sh cannot run, give the command and why it has no --name, do the route and freshness steps, and hand over the verify question with its pass rule. - budget: burn-proj.py skips malformed or unmeasured accounts with a cause, never a traceback, and labels lines by the number of accounts; the skill names the 7,37 schedule either way and reads `word`, not `status`. - intake: seen.txt keeps the edit time of each message and a hash of each proposal, so a pass proposes nothing twice; only the person's own reaction marks a message; reach.json's path is given. - evals: intake checks a task whose reconciler cannot run; harness checks that no savings figure is a fact. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and builder asks for signed commits Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…k, and a pull request is checked at its own head Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…every habit builder now notices three more gaps in a setup: matchblox without its hooks, no code graph, and no early autocompact. Each one gets a just-in-time recommendation. The builder skill and soul carry the standing rules for visuals as shareable pages and private names out of public repositories. tests/evals/parity.sh runs the builder and shape fixtures in the current setup and in a builder-led config dir, with the shared run.sh guards. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… from CLAUDE_CONFIG_DIR code_graph also reads projects.<dir>.mcpServers in .claude.json. The superpowers and gstack signals now read the same config dir as the new signals. The autocompact step names CLAUDE_CONFIG_DIR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
parity.sh copies only the installed superpowers version and its marketplace, links only the gstack clone, and refuses a config dir that is, holds or sits inside the real one, or holds settings it did not write. It no longer invents matchblox hooks, and it reads the auth status from stdout only. fleet and reach point to the standing rules in the soul. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…res, and still reads the old place Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…guess what they cannot see Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…x, and ask an unknown step only once Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… that is not UTF-8 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…m it reads The session start builds one text and prints it as Claude Code JSON, Cursor JSON or plain text, chosen by --harness and --format. The no-python fallback prints the same shapes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tion to its own tool Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tests pass every run Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…th that harness's own command Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ugin systems Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… version Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…shows only what passed run.sh takes --harness claude|codex|cursor|opencode and writes a verdict stub per run. support-table.py records graded verdicts as counts and builds the README table from them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… fixture passed, and evals never write into your checkout render and check take the fixture set from tests/evals/*/prompt.md. A harness with ungraded fixtures is experimental. The Cursor runner copies skills into the temp work dir instead of linking them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ilder from one README Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The session-start text now tells the agent to run `ledger.py next --harness <h>`, and `next --harness X` reads the signals of X, so the hook and `next` offer the same step on Codex, Cursor and opencode. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Under --harness auto the Cursor env markers are ignored, so a Claude Code session that inherits CURSOR_VERSION keeps the soul. Cursor still works through --harness cursor or BUILDER_HARNESS=cursor. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The harness skill writes .mcp.json, which only Claude Code reads. Until other harnesses get their own wiring, they no longer see a setup step that cannot finish. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On the first pass, intake copies the old seen.txt to the new path before it appends, so a handled message is not handled again. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codex session start uses the Claude Code step list until detection lands, the Cursor path must be absolute, the opencode and Codex installs say how far they were proven, and parity.sh is named as Claude Code only. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…he graded results budget and builder met 5/5 each on Claude Code 2.1.307; the recorder keeps one version, so they show as not graded (see #17). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…m the opened project
The plugin hook ran "./hooks/session-start", resolved against the hook's
working directory. If Cursor runs plugin hooks from the opened project, a
repository could ship its own hooks/session-start and have it run. The
command now starts from ${CURSOR_PLUGIN_ROOT}, quoted. If Cursor does not
set or expand it, the path is /hooks/session-start, which does not exist,
so the hook fails closed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… behind it, now that one harness has results Case 22 seeded drift by replacing the line "No harness has passed its evals yet.", which the README no longer has once a results file exists. The sed then changed nothing and the case passed for the wrong reason (CI failed it). The case now writes a fake "supported" row between the support markers, whatever the table holds. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Lutherwaves
force-pushed
the
feat/builder-2
branch
from
October 22, 2026 09:09
26dcbe3 to
73ce978
Compare
Lutherwaves
marked this pull request as ready for review
October 22, 2026 09:19
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
builder 1.0 is one plugin that gives a coding agent the habits of a seasoned builder. It starts from the person, records each decision with its reason, proves the work, and writes nothing outside the machine without a send rule or the person's yes.
It runs on Claude Code, Codex CLI, Cursor CLI and opencode from one core. It sits on top of superpowers, gstack,
ghand MCPs, and does not replace them.What changes
hookSpecificOutput, Cursor getsadditional_context, and opencode gets plain text through its plugin.~/.config/builderserves every harness. Each step is offered only on a harness where it works, with that harness's own command.builder,shape,canon,reach,fleet,intake,budget,harness. Skill bodies name actions, not tools. One mapping file per harness (skills/builder/harnesses/<harness>.md) maps each action to that harness's tool, or says what to do where it has none..claude-plugin,.codex-pluginplus.agents/plugins/marketplace.json,.cursor-pluginplushooks/hooks-cursor.json, andpackage.jsonwith.opencode/plugins/builder.js(no dependencies).lib/harness.pynames the harness and its paths. No~/.claudeliteral is left in the signals. builder state that sat under~/.claudemoves to$BUILDER_HOME; builder still reads the old place and never deletes it.tests/evals/run.sh --harness <h>runs each fixture through that harness's headless runner. The README support table is rendered from graded results, never by hand.Verification
experimentalon 2.1.308 with 2 fixtures not graded. The full table and the misses are in test: run builder's evals on Codex, Cursor and opencode, and fill the support table #17.builder:<name>.sessionStartfrom a project.cursor/hooks.json(an earlier live check).parity.sh. Until test: run builder's evals on Codex, Cursor and opencode, and fill the support table #17 adds Codex detection, Codex gets the Claude Code step list and mapping. The README states both points.Release
ef049accarriesRelease-As: 1.0.0. When you squash-merge, keep the lineRelease-As: 1.0.0in the commit body, or release-please cuts 0.2.0. release-please now bumps the version in every manifest and inpackage.json.Design: builder on any harness
builder for any agent harness — design (2026-10-21)
Extends the builder 2 design (summarised at the top of this PR). Everything there still holds unless this document says otherwise. This work lands in the same PR (#16), so the first public release (1.0.0) is generic from day one (owner ruling, 2026-10-21).
Intent
matchblox runs Claude Code, Codex and opencode sessions side by side, and teammates use Cursor too. builder is the habits layer on top, so it cannot be tied to one harness. Its model is obra/superpowers: one source of skills, a thin adapter per harness, and installation through each harness's own mechanism. A colleague on Codex, Cursor CLI or opencode installs builder and gets the same soul, the same onboarding, the same skills and the same safety rules as a Claude Code user.
Owner's words: "this builder must be a generic plugin, like obra/superpowers is"; "can we tweak it so it works for cursor-cli (cursor-agent) and codex equally well". opencode is added because matchblox supports it.
Goals
cursor-agent/agent) and opencode.skills/,lib/and the soul are shared and are not forked per harness.Non-goals
reachand matchblox.Anti-goals (failure even if it "works")
PushNotification,SendMessage,AskUserQuestion) as the only way to do something.~/.codex,~/.cursor,~/.config/opencodeor~/.claudeconfig to install or enable itself.Constraints
claude -p,codex exec,agent -pandopencode run.Facts the design rests on (research, 2026-10-21; see "Verify first")
skills/.claude-plugin/plugin.json+marketplace.jsonSessionStarthook →hookSpecificOutput.additionalContextclaude -pCLAUDE_CONFIG_DIR.mcp.json,~/.claude.jsonskills/,.agents/skills,~/.agents/skillsplugin.json/.codex-plugin/plugin.json+.agents/plugins/marketplace.json;codex plugin marketplace add owner/repoSessionStartin pluginhooks/hooks.json, same JSON as Claude (setsCLAUDE_PLUGIN_ROOTfor compatibility); plugin hooks run only after the user trusts themcodex execCODEX_HOMEconfig.toml[mcp_servers]skills/,.agents/skills,.cursor/skills.cursor-plugin/plugin.json(+hookspath)sessionStart→{"additional_context": …}(CLI support unverified: forum reports say the CLI fires only shell hooks)agent -p(--forceto write)CURSOR_CONFIG_DIR.cursor/mcp.json,~/.cursor/mcp.json.opencode/skills,.agents/skills,.claude/skillsplugininopencode.json(git or npm)opencode runOPENCODE_CONFIG_DIRopencode.jsonmcpsuperpowers 7.0.0 does all four this way:
skills/;hooks/session-startthat picks the JSON shape from an env var (CURSOR_PLUGIN_ROOT→additional_context;CLAUDE_PLUGIN_ROOT→hookSpecificOutput);.opencode/plugins/superpowers.jsfor opencode;references/<harness>-tools.md.The how (decided)
1. Layout
2. Harness detection:
lib/harness.pydetect(env) -> "claude" | "codex" | "cursor" | "opencode" | "unknown":BUILDER_HARNESSoverrides detection.CLAUDE_PLUGIN_ROOTtoo, so Codex is checked before Claude, on a Codex-only marker.paths(harness, env) -> dictgives:lib/signals.pytakes all paths fromharness.paths. No~/.claudeliteral remains outsideharness.py.3. Session start: one logic, four shapes
session_start.pybuilds the same text on every harness: the soul, the onboarding or one recommendation, and the mapping file for the detected harness, appended in at most 15 lines. It prints:{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":…}}{"additional_context": …}--format text), read bybuilder.jsbuilder.jsrunspython3 hooks/session_start.py --format textonce per top-level session. It injects the result the way superpowers' opencode plugin does, and skips child (subagent) sessions. If python3 is missing, it injectssoul-compact.mdalone.Cursor CLI fallback. The Cursor CLI may not fire
sessionStart. In that case, builder tells the person in its README Cursor section to add one line to the project'sAGENTS.md(Cursor CLI readsAGENTS.md). The line points at the builder skill. Thebuilderskill's description also carries the trigger, so skill discovery can load it. builder does not writeAGENTS.mditself. Thecanonskill may offer to write it, with a yes, as it already does for agent files.4. Skills name actions, not tools
skills/builder/harnesses/<harness>.mdmaps each action to the harness's tool, or to "not available: do X instead".claude.md: PushNotification,/usage, the artifact page,/loop, the cron tools, and the claude.ai Slack connector.shapeskill", not/builder:shape. Each mapping file gives the harness's own syntax.5. Recommendations per harness
lib/recommendations.json,howmay be a string (the same on every harness) or a map{claude, codex, cursor, opencode}.how.harnesses: [...]. Examples:superpowers: a per-harness install command; each comes from superpowers' own README.gstack: offered only where gstack documents support. The supported harnesses are checked during implementation.autocompact: Claude only.matchblox-setup: claude, codex and opencode, which matchblox supports. Cursor is included only ifmatchblox setupcovers it.code-graph: on every harness, with the per-harness MCP config.signing,gh,channel,fleet,canon: the same on all harnesses.6. State outside any harness dir
~/.claudemoves under$BUILDER_HOME(default~/.config/builder). This covers the intake config,seen.txt, and the code-graphrepos.txt.~/.config/builder. One ledger serves all harnesses on a machine: a step answered in one harness is answered everywhere.7. Notifications, usage and sessions
matchblox notify, when present;reach.py notify).The code does not change; only the skill wording does.
matchblox usage, which covers each account matchblox knows./usage, and Codex/status(to verify).matchblox sessionswhen present. Otherwise builder counts the session processes of all four harnesses.8. Evals per harness
tests/evals/run.sh --harness <h>runs the existing fixtures with that harness's headless runner, with builder installed from the working copy.--plugin-dir, as today.--force, with the plugin dir.OPENCODE_CONFIG_DIR.expect.mdstays the same for all harnesses; the grading bar does not change.parity.shstays Claude Code only. Ruling 4 was about the owner's current setup, which is Claude Code.9. Release and validation
scripts/validate.shchecks:hooks-cursor.json;package.json;skills/builder/harnesses/. This is a grep guard, with a list of tool names.extra-files).codex,cursor,opencodeandagent-skills.10. Docs
Verify first (before building on them)
sessionStart: doescursor-agentfire it from a plugin, from.cursor/hooks.json, or not at all? Test it on this machine.hooks/hooks.jsonwithSessionStartruns after trust;.agents/skills?Each finding goes in the ledger, as a ruling if it changes this design.
Left to the builder
index.jsre-exports.opencode/plugins/builder.jsor the reverse.harness.py,session_start.pyandsignals.pyhas a unit test, and each adapter has a smoke test that runs without the harness installed.Verified on this machine (2026-10-21)
sessionStartfrom the project's.cursor/hooks.json({"version":1,"hooks":{"sessionStart":[{"command":…}]}}), and it honours{"additional_context": …}. In acursor-agent -prun the model repeated a word that only the hook had given it. The forum reports are out of date for this version.CLAUDECODE,CLAUDE_PROJECT_DIRand otherCLAUDE*variables. Cursor addsCURSOR_VERSION,CURSOR_PROJECT_DIRandCURSOR_INVOKED_AS.session-start --harness cursor, and so on). Env detection is only a fallback, and it checks the innermost harness marker first.codex execreturns 401, so the hook test needs the owner to runcodex login.Calls made after the builder check (mine; the owner can overturn)
expect.mdbullet as met or not met, quoting the transcript.tests/evals/results/<harness>.jsonholds these verdicts: harness, harness version, date, fixture, bullets met out of total. It holds no transcripts and no local paths.~/.claude/intake→$BUILDER_HOME/intake, with a fallback that reads the old path).None(unknown), notfalse.PushNotification,SendMessage,AskUserQuestion,TodoWrite,ScheduleWakeup,CronCreate,CronDelete,Monitor,Artifact,WebFetch,apply_patchandupdate_plan. The list grows as the mapping files grow.gh,tmux,matchblox,git, Slack, Todoist) are allowed in skill bodies./loopand/usagecount as harness features. They move to the mapping files.builderskill description keeps its trigger, so skill discovery still loads the soul before trust.🤖 Generated with Claude Code