A personal SDLC for Claude Code and OpenCode: thin lifecycle commands orchestrate a twelve-agent roster bound by the 4 Karpathy rules, hooks deterministically enforce everything a machine can check, and captured knowledge compounds across sessions and projects.
From the Portuguese word for harmony, and for Harmonia, the Greek goddess of harmony — the cosmos as ordered music and balance (the Music of the Spheres). The name evokes order, structure, and beauty: exactly what a good SDLC provides. It is instantly readable and pronounceable, and it feels classical and mythic.
claude plugin marketplace add foliveira/harmonia
claude plugin install harmoniaInstalls are pinned to a release, not to master: the marketplace entry names the exact commit a CalVer version was cut from, so claude plugin install and claude plugin update both give you that tree rather than whatever is on the branch. The current release is 2026.08.16.
Working on the engine itself is a different path — add the repo as a directory marketplace and the plugin runs from your working tree, so a change is live in the next session with no release step.
Add to that repo's .claude/settings.local.json:
{ "enabledPlugins": { "harmonia": false } }Emergency brake: set HARMONIA_DISABLE=1 in the environment — the session-start hook checks it first and stays silent.
The repo itself is the distribution artifact: clone it and run the installer.
git clone https://github.com/foliveira/harmonia
cd harmonia
bash bin/install-opencode.shThe installer writes into your OpenCode config directory (--target <dir> beats OPENCODE_CONFIG_DIR, which beats the default ~/.config/opencode) and places two things:
commands/harmonia-<name>.md— one command file per skill. OpenCode command names carry no namespace separator, so every/harmonia:xin the tables below is typed/harmonia-xthere.harmonia/— the engine home: a copy ofbin/,core/, andskills/, with the plugin-root variable in prompt bodies rewritten to the engine home's absolute path.
The target path may contain only the characters [A-Za-z0-9._/-]: placed bodies embed the engine-home path in unquoted shell instructions, so the installer refuses whitespace and other shell metacharacters rather than splice a path that would break them.
Generated command files carry a marker comment, and that marker is the ownership boundary: every run re-creates the marked commands/harmonia-*.md files (stale ones left by removed skills included) and never touches unmarked files. If a file of your own sits at a name the run would generate, the installer aborts and lists it. To update:
git pull && bash bin/install-opencode.shRe-running converges to a fresh install. Uninstall is the two owned paths, marker-filtered so any harmonia-*.md files of your own survive:
rm -rf ~/.config/opencode/harmonia
grep -lF 'generated by harmonia install' ~/.config/opencode/commands/harmonia-*.md | xargs rm -fBoth paths assume the default ~/.config/opencode; adjust them if you installed elsewhere with --target or OPENCODE_CONFIG_DIR.
Two capabilities do not port to OpenCode; the installer prints both on every run:
- Roster subagent dispatch: OpenCode has its own agent system (
~/.config/opencode/agents/), and harmonia installs nothing into it. Where a stage says "dispatch the <agent>", an OpenCode session runs that stage's procedure in the main session, with the charters readable at<engine home>/core/charters/. A real roster port is the first candidate for a contributor (next section). - Session-start injection: no hook fires when a session opens. Every stage command reads
core/RULES.mditself when the digest is not in context, so the working contract loads on first harmonia command use. Optional: add<engine home>/core/RULES.mdto theinstructionsarray of youropencode.json; the installer never edits that file.
Ports arrive as PRs. These are the repo-side facts a port must honor — bin/install-opencode.sh is the worked example, and other harnesses' internals are unverified here:
- Place
bin/,core/, andskills/somewhere stable, preserving the executable bits onbin/(plain bash, invoked by path). - Substitute the closed literal
${CLAUDE_PLUGIN_ROOT}in placed.md/.yamlfiles with the absolute path of the placed engine root. Never rewritebin/*.sh— the scripts resolve their own location when that variable is unset. - Surface each
skills/<name>/SKILL.mdbody through the harness's user-typed command surface, re-heading the frontmatter in the harness's own vocabulary (every command is human-invoked by contract). - Adapt or document the four Claude-specific capabilities: roster dispatch (
agents/), session-start injection (hooks/hooks.json), plugin-root substitution, and/harmonia:namespacing. - Ship an update act that converges — re-running it equals a fresh install — and copy the pattern in
tests/install.batsto verify the port repo-locally against a scratch target.
Every session starts with the 4 rules and relevant learnings injected automatically. The lifecycle is seven explicit commands:
| Command | What runs |
|---|---|
/harmonia:ideate |
ideator (+ rubber duck) widen the option space into ideas.md |
/harmonia:discuss |
scoper pins scope — goal, boundaries, non-goals, run: success criteria |
/harmonia:plan |
planner designs inside the scope boundary |
/harmonia:implement |
red-green loop: test engineer leads, implementer follows, coverage gate feeds gap rounds |
/harmonia:review |
review lead chairs the panel, dispatches triggered lenses, audits gates and receipts, writes one verdict |
/harmonia:capture |
knowledge curator files learnings; committer ships structured commits |
/harmonia:quick |
express lane: implementer + lead-solo review, gates still active |
Each task lives in .harmonia/tasks/<task-id>/ in the target repo — a self-gitignoring workspace where stages pass artifacts by path. Entry stages mint it; later stages resolve it; interruption recovery is re-invoking a stage against the on-disk artifacts.
Six commands act on a task outside the lifecycle stages: they record your decision on the built work, move learnings to and from memory, read the workspace state, and retire a task you are dropping. None of them advances a stage.
| Command | What it does |
|---|---|
/harmonia:accept |
Records your acceptance of the built work so capture can proceed; supersedes a standing rejection. |
/harmonia:reject |
Records that you rejected the built work, blocking capture until you re-accept or abandon the task; supersedes a standing acceptance. |
/harmonia:abandon |
Retires the active task workspace so resolution skips it. |
/harmonia:remember |
Captures a single learning into the right memory tier. |
/harmonia:recall |
Surfaces relevant past learnings for the current repo mid-session. |
/harmonia:status |
Read-only readout of the active task's stage, markers, and receipts. |
Three more commands are neither stages nor touchpoints. One chains stages; two set a repo up before any task runs.
| Command | What it does |
|---|---|
/harmonia:flow |
Runs an already-pinned task through plan, implement, and review in one unattended pass. It chains neither end: discuss stays manual because it is dialogic, and acceptance stays manual under the human-only gate. |
/harmonia:onboard |
Captures an existing repo's canonical verify commands and its own coverage command into .harmonia/project.yaml. |
/harmonia:trust |
Records your consent, on this machine, to run a repository's .harmonia/project.yaml coverage command. Until you do, that command is refused. |
- Criteria — implement refuses to start until the scope declaration carries machine-checkable
- run:criteria; at review thecriteria-rungate executes every one of them from the repo root, echoes the whole set it ran, and fails the review if any criterion fails. - Coverage — 100% line (and branch, where the format measures it) on changed code, soft block. Exemptions are in-code markers with a mandatory justification (
// harmonia:exempt <why>), surfaced to the reviewer in the gate report's exemptions-honored section. Overrides append to a versioned audit log at.harmonia/coverage-exemptions.yaml. Unsupported languages exit as advisory cannot-measure, never a false pass. - Receipts — every gate run writes a receipt (task id, timestamp, diff digest); review fails work whose receipts are missing or stale, and a test-immutability hash violation is treated the same way.
Two tiers of learnings: a global tier under ~/.harmonia/learnings/ for cross-project patterns, summarized one line each in ~/.harmonia/index.md, and docs/learnings/ in each repo for the project tier. HARMONIA_HOME moves the global store. Writes go through capture: the knowledge curator files learnings at /harmonia:capture, and /harmonia:remember files a single one. Capture refuses two of them at the global tier — client-flagged content, which stays project-tier, and an entry carrying no recognized language tag, which the filter below could never surface. That second refusal is overridable, and an entry recorded that way says so in its body.
Recall reads three sources: both tiers, plus legacy docs/solutions/ entries, read-only, for continuity. Only the global tier is filtered, and it is filtered on language alone: an index line is kept when one of its tags matches a language detected in the repo you are in, read from that repo's tracked file extensions. Project and legacy entries are always relevant to their own repo, so nothing filters them. What is left is ordered newest first and cut at a line budget: 12 lines at session start, 30 when the script runs on its own. Run /harmonia:recall to pull more mid-session. Any roster agent or hook can run the underlying script directly:
bash ${CLAUDE_PLUGIN_ROOT}/bin/memory/recall.shPointing Harmonia at a repository runs some of that repository's own configuration, so the trust model is written down rather than implied. SECURITY.md states what is guarded — workspace containment, artifact provenance, and consent for a repository's coverage command — and, just as explicitly, which routes are deliberately still open. Report a vulnerability privately through the process it describes, never a public issue.
Twelve agents. Each has a charter in core/charters/ — the portable truth — and a thin Claude Code wrapper in agents/. A stage dispatches them, and each consumes named artifacts and produces named ones, so a handoff is a file on disk rather than a conversation.
| Agent | Runs at | What it does |
|---|---|---|
| ideator | ideate | Widens the option space before Harmonia commits to one direction |
| rubber duck | ideate, discuss | A thinking partner: asks the questions that let you find the answer |
| scoper | discuss, plan | Pins the scope — goal, boundaries, non-goals, machine-checkable criteria |
| planner | plan | Designs how to build, strictly inside the scope declaration's boundary |
| test engineer | implement, review | Writes tests first: failing tests for behavior, covering tests at gaps |
| implementer | implement, quick | Makes failing tests pass, and never edits a test |
| reviewer | review, quick | Review lead: chairs the panel, dispatches lenses, audits gates and receipts, writes one verdict |
| simplifier | review | Challenges every abstraction and line that does not earn its keep |
| doc reviewer | review | Checks documentation against the code and the diff |
| knowledge curator | capture | Classifies and files learnings into the right memory tier |
| committer | capture | Organizes the work into single-concern commits that communicate intent |
| doc producer | on request | Writes documentation for shipped behavior. No stage dispatches it — invoke it when you want docs |
The review panel is the test engineer, simplifier and doc reviewer, convened under the review lead. The lead arbitrates everything into one verdict; seats do not vote.
Five files in core/lenses/. Each declares its own triggers in frontmatter, so dispatch follows the diff rather than a list the reviewer hardcodes.
| Lens | Fires | On |
|---|---|---|
| security | automatically | auth, secrets, input parsing, network-facing |
| regression | automatically | markers, base-ref handling, receipts, shell quoting — checked against both learning tiers |
| adversarial | the lead's call | new abstractions, architectural changes, novel patterns |
| performance | the lead's call | hot paths, algorithmic complexity, large data, tight loops |
| blindspot | not a review lens | the scoper dispatches it once per task at first scope mint, to surface unknowns before the boundary is drawn |
Dev toolchain: bats, jq, yamllint, check-jsonschema, kcov, diff-cover (and gocover-cobertura for Go targets).
bats tests/ # the whole suite
bin/validate-core.sh # lifecycle schema + lens resolution
bin/coverage/gate.sh --self --base <ref> # the gate, dogfooded on this repoThe engine is bash + YAML only, and it is held to its own coverage bar.
Harmonia systematizes my own workflow. It vendors nothing, but draws inspiration from: multica-ai/andrej-karpathy-skills · EveryInc/compound-engineering-plugin · Yeachan-Heo/oh-my-claudecode · addyosmani/agent-skills · mattpocock/skills
MIT licensed.