Point an agent or a patient human at this one file. Follow it in order, and you
end with an agentic project (e.g. agentic-acme): a repo carrying the methodology's techniques
(the operating manual, the rooms, the verification tools) and able to upgrade
as the methodology moves. It is written to be literal: do each step, run the
stated check, and stop to ask the human at the points marked (human).
This file is the process. It does not contain the techniques. Those live in the template, versioned:
https://github.com/connollydavid/host-template
You copy the template's techniques in at a chosen revision and record that revision. Later you upgrade by re-running this file against a newer one. The template owns the techniques and the upgrade ledger; this file owns only the steps that apply them.
git, and network access to the template URL above.- The
host-lifecycleandhost-lintbinaries (download from their GitHub releases, or build them).host-lifecycledoes the mechanical work (classify, scaffold, stamp, number, upgrade), token-free.host-lintdoes the audit.
- Case: what governance the repo already has (its starting state). Decides how you establish governance.
- Mode: how much you change, and whether history moves (the blast radius). Decides how you apply the audit.
Pick the case first, then the mode.
| Case | The repo has | You will |
|---|---|---|
| a | no CLAUDE.md |
copy the canonical manual in and record the repo's own conventions |
| b | a CLAUDE.md that predates this methodology |
merge its rules with the spine (human) |
| c | a .host stamp (it adopted an earlier revision) |
upgrade by diffing template revisions |
host-lifecycle classify <dir> prints a, b, or c, unless the target is
itself a software repository (a root build manifest such as Cargo.toml /
package.json / go.mod / pyproject.toml, with no .host stamp and no
.host-software recipe). In that case it refuses (exits non-zero, prints the
steps below) rather than a case letter: a host is a separate meta-repo, and you
must never adopt a software repo in place. Embed the software as the Where room of
a new host instead (the Scaffold the rooms and embed the software step, below);
the refusal message spells out exactly how.
| Mode | What it touches | Use when |
|---|---|---|
| Preview | nothing (report only) | always; run it first |
| Shallow PR (default) | one branch/PR; live files only; history untouched | almost always |
| Staged | several PRs; live files only | the live diff is too large to review in one PR |
| Deep rewrite | history (archive-first, force-push) | only when history coherence is worth more than its provenance |
Selection rule. Default to Shallow. Go to Staged when the live diff is
too big to review in one sitting. Choose Deep only when rewriting history
buys coherence worth more than the disruption, and never on history carrying
provenance you do not control (an upstream patch series, tags others have pulled).
Deep always means: push a protected archive/ branch first, then rewrite, then
force-push with lease. History is immutable by default; outside Deep, tells in
the log are acknowledged, not rewritten.
A host records which template revision it adopted, at the repo root:
template = "https://github.com/connollydavid/host-template"
revision = "<sha-or-tag>"
adopted = "YYYY-MM-DD"
host-lifecycle adopt writes it; host-lifecycle version reads it. The
revision is what a later case-(c) upgrade diffs from, so it must be exact.
host-lifecycle classify <dir>reports the case (or a refusal if the target is a software repo; stop and follow its steps, and do not adopt software in place).host-lint --allreports naming tells in live tracked files (you will fix these).host-lint --prosereports prose tropes in authored docs (the LLM-slop markers it flags). You will clean these to zero, the way you clear naming tells.host-lint --logreports tells in history (informational; do not rewrite unless Deep).- Write down the rename map (each ordinal-named file mapped to its content-named home
under
plan/) and, for case (b), the merge plan. Apply nothing yet.
- (a) Copy the template's
CLAUDE.mdin unchanged at the chosen revision. Then find the repo's implicit conventions (build, test, style) by reading the code or asking the human, and record them under a project-specifics heading. Do not impose a rule that contradicts the repo's existing style. - (b) (human) Merge. For each rule in the existing
CLAUDE.md, decide: subsumed by the spine (drop it, note it in provenance), project-specific (keep it under the project-specifics heading), or conflicts (stop, get a human ruling). Preserve any attribution or license the old file carried. - (c) Upgrade: see Upgrading below; the ledger drives it.
host-lifecycle adopt <dir> <revision> creates cast/ plan/ call/ idempotently
and writes the stamp. Then embed the software in the Where slot as a bare store
with worktrees: <name>.git/ plus the canonical worktree <name>/ and any
parallel worktrees. Commit a .host-software recipe with one [software "<name>"]
stanza per component (URL, pinned SHA, worktree set); gitignore the trees;
materialize with host-lifecycle software --materialize. If the software is
already a gitlink submodule, convert it in place (preserve the pin, de-register
the gitlink, write .host-software, gitignore the trees), creating, moving, or
rewriting no software commit.
Every worktree must surface under the host root, never a bare external
path. When a backing store has to live elsewhere (another filesystem or platform,
e.g. a native-Windows build that cannot sit on a WSL share), record it on the
parallel line as worktree = <dir> <branch> <pin> store=<path> [host=<os>]:
--materialize realises the store at <path> and the in-tree <dir> as a
symlink/junction to it, so an edit through <dir>/… still lands in the tree under
test. host=<os> (optional) is the OS that materializes the store (where you run
host-lifecycle), not the build platform; a Windows Dev Drive reached from WSL is
host=linux. software --check HAZARDs any worktree path that escapes the root.
Add the four verification tools as submodules (reference, do not vendor: each is
pinned to a commit), then generate their skill symlinks with link-skills.sh
after materialization (do not git-track a symlink into a path that a fresh clone
has not materialized). allium, specula and host-lifecycle each ship Claude skills
under skills/, so an agent drives them through those skills rather than from memory:
tools/host-lint github.com/connollydavid/host-lint (Rust)
tools/host-lifecycle github.com/connollydavid/host-lifecycle (Rust)
tools/allium github.com/juxt/allium (Rust CLI + agent skill)
tools/specula github.com/specula-org/Specula (TLA+, runs on the JVM)
tools/host-prove github.com/connollydavid/host-prove (deep-verification rungs; opt-in)
The submodule gives you a tool's specs and its driver, not the binary component that runs them. Two of the four are pure Rust binaries; the other two carry a runtime you install separately. Pin the exact versions below: they are the set this methodology is verified against. Install each:
- host-lint, host-lifecycle (hygiene + lifecycle): the two Rust binaries from
"What you need". Build with
cargo build --releasein each submodule under Rust1.95.0(the digest-pinnedrust:1.95.0container is the reproducible-build anchor; CI builds in it), or download a release. Then install thehost-lintgit hooks withhost-lifecycle software --install-hooks .(copiespre-commit,commit-msg, and the built binary) so new commits are gated from here on. - host-lifecycle skills:
tools/host-lifecyclealso ships one skill per lifecycle phase (classify,adopt,embed,remap,verify,publish,upgrade), wired by the samelink-skills.sh. Drive each phase through its skill and command; the phases are unconditional (no opt-out). - allium (requirements lane, behavioural specs / property-based): its skills
(
elicit/distill/tend/weed/propagate) come from thetools/alliumsubmodule vialink-skills.sh; author and maintain.alliumthrough them, not by hand (Claude Code users may instead/plugin install allium). The.alliumspecs are checked by thealliumCLI:cargo install allium-cli@3.4.2, orbrew tap juxt/allium && brew install allium. - specula (timing and concurrency lane, TLA+): its TLA+ workflow skills also
come from the
tools/speculasubmodule. The.tlaspecs are model-checked by TLC, a Java tool: install a Temurin21JDK andtla2tools.jarv1.8.0from thetlaplus/tlaplusreleases, then runjava -cp tla2tools.jar tlc2.TLC -config <spec>.cfg <spec>.tla. CI runs exactly these versions (actions/setup-javaTemurin21plus the pinnedv1.8.0jar); see the Specula workflow. - host-prove (deeper rungs, opt-in): above the bounded lanes,
tools/host-provedrives three heavier verifiers as skills. Apalache does symbolic/parametric TLA+ via SMT, TLAPS (tlapm) does unbounded proof (authoring needs a strong model), and a target-specific code-conformance verifier covers Rust via Kani. Each skill turns the tool's output into one machine-readable verdict, so a rung runs down to a small model. Wire the submodule andlink-skills.shonly when you declare a rung by dispositioning an obligationkani:/apalache:/tlaps:. Verifiers install from official prebuilt binaries pinned by version + SHA256 (no Docker).
Lanes are mandatory once a spec exists; phases always. When a component carries
a .allium, its CI MUST run allium check + analyse + plan, every allium plan obligation MUST be dispositioned in a <spec>.obligations manifest (checked
by host-lifecycle obligations <spec> --tests <dir>), and software --check
HAZARDs a .allium with no manifest; a .tla MUST have a TLC lane. A declared
deeper rung is the same rule one level up: an obligation dispositioned
kani:/apalache:/tlaps: MUST have its CI lane (cargo kani / apalache-mc /
tlapm) or software --check HAZARDs it, but only once declared; the rungs are
opt-in and inert otherwise. The lifecycle phases above are unconditional. The full
rules live in the template's CLAUDE.md.
The pins CI exercises directly are Rust 1.95.0 (host-lint, host-lifecycle, and
the reproducible build) and TLA+ tla2tools v1.8.0 on Temurin 21 (the timing
lane). The requirements lane in this reference host runs on Rust proptest, so
allium-cli 3.4.2 is its current-release pin rather than one this host's CI
exercises; adopt it when you wire the allium lane.
Live layer: rename with the dictionary. Turn the rename map into a
.host-remap dictionary (old => new per line). git mv each ordinal-named file
to its content-named home, then host-lifecycle remap --check <dir> until clean
(disposition each remaining tell: a dictionary entry, a .host-lint-allow entry
for genuine vocabulary, or an excluded path). Commit (the clean tree is the
verbatim archive), then run host-lifecycle remap --apply <dir>, which makes only
the declared substitutions, map-only by construction. Commit, then git rm .host-remap (its
durable copy goes in the call/ decision). Shallow: one PR. Staged: split
governance, then tooling, then the bulk rename. Deep (human): archive-first, then rewrite
history too.
Prose layer: clean the slop. host-lint --prose flags the LLM-slop prose tropes
(decoration dashes and arrows, tricolons, and the rest) in authored docs. Reword them
to plain prose so the docs read as written, not generated: zero tropes, the same
bar as the naming audit. The append-only record is excepted (below).
Record layer: exclude, don't rewrite. The append-only record (MEMORY.md, closed
milestone bodies) is history, and MEMORY.md is the agent's own working memory;
exclude it from both the naming audit and the prose audit with a .host-lintignore,
rather than rewriting it.
The stamp is already written: you wrote it when you scaffolded the rooms. Record
a call/ decision ("adopted template @ <revision>") and add a MEMORY.md
entry, so the migration is auditable from a fresh session.
host-lifecycle validate plan/andhost-lifecycle validate call/reportok.host-lifecycle software --checkshows each worktree at its pin, noHAZARD(this also enforces the spec lanes and the.obligationsmanifest).- For each
.allium,host-lifecycle obligations <spec> --tests <dir>shows every obligation dispositioned. host-lint --allis clean on live files (the record excluded via.host-lintignore).host-lint --proseshows zero prose tropes in authored docs (the agent'sMEMORY.mdexcepted).- A throwaway commit with a tell in its message is blocked by the hook.
- If the repo ships an mdBook site, it builds.
Adopting is one event; the template moves on. The .host stamp records what you
have applied: a baseline ledger entry (every entry at or before its position in
UPGRADING.md counts applied) plus an optional applied set of entries taken out of
order. The template's UPGRADING.md is the ledger of actions, one [upgrade "<revision>"] stanza each, ordered by file position; a stanza may declare
independent/depends and a verify post-condition.
- Fetch the template to the target revision.
host-lifecycle upgrade <dir>lists every ledger entry not yet applied, by ledger position (never git ancestry). A legacy single-revisionstamp is migrated once to abaseline.upgrade --nextprints the single next safe action.- Apply an entry, then record it:
host-lifecycle upgrade --record <id>, where the id may be an unambiguous prefix or a ledger ordinal. The tool validates the id, refuses if adependsis unapplied, then runs the entry'sverify(or requires--unverified call/NNNNwhen it has none) before appending an append-only claim. Never hand-edit the stamp. A lateindependententry may be cherry-applied without an earlier unrelated one; deferred entries stay pending and re-list (fail-safe), andupgrade --advancelater compacts a contiguous applied run into thebaseline. - Re-apply the spine doc changes across the span; leave project-specifics alone.
host-lifecycle software --checkre-checks every recorded claim; record the upgrade incall/andMEMORY.md.
The ledger lives with the techniques that generate it, in the template. This file does not change when the template adds an entry; only the template does.
- Idempotent and resumable.
adoptskips rooms that exist. If interrupted, re-runclassifyand continue. - Token-free where mechanical.
host-lifecyclescaffolds, numbers, stamps, and runs the dictionaryremap;host-lintaudits. Spend model effort only on the judgment: the case-(b) merge, eliciting case-(a) conventions, naming each milestone, and audit triage. The substitutions are deterministic. - Repo-root config the tools read.
.host-software(the Where recipe),.host(the stamp),.host-remap(the rename dictionary, transient),.host-lint-allow(sanctioned vocabulary),.host-lintignore(excluded paths). All are plain line-oriented files.