conductor previously jumped straight to lh host, which succeeds even without .agents/harness.config.json, then silently hit a hard failure later reading .agents/memory/INDEX.md (lh doctor confirms: config not initialised). New projects had no automatic recovery path — lh init was documented as a manual step users had to remember. - conductor now runs lh doctor first; if config is missing it runs lh init --yes (non-interactive defaults) and re-checks, before lh host - still stops and reports the exact failing check if lh doctor finds something it can't self-heal (e.g. no verify commands configured) - README/QUICKSTART updated: lh init/lh doctor documented as optional manual pre-flight, not a required step, since conductor self-heals Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
12 KiB
Quick Start Guide
This walks a new user from zero to a finished, verified change using
redsen-lean-harness. For full command/flag reference see the main
README.md; this doc is the shortest path to "it worked".
0. Prerequisites
- Node >= 20
- Git
- GitHub Copilot CLI or VS Code Copilot
- A
CONTEXT7_API_KEY(required —lh doctorfails without it)
export CONTEXT7_API_KEY="<your key>" # add to ~/.bashrc or ~/.zshrc
The harness never writes this key to disk. It is read from the environment only.
1. Get the harness into your project
The harness has two layers you install separately: the behaviour layer
(.github/agents, skills, instructions, prompts, mcp.json — markdown, read by the
host) and the determinism layer (the lh CLI — Node, called by the agents). Every install
path below gets you the behaviour layer; only B and C also give you lh on PATH in one step.
A. Copilot CLI plugin (recommended — start here)
This is the primary distribution path for GitHub Copilot CLI users. It registers the
agents/skills/instructions host-wide, so every repo you open in that Copilot CLI account can
invoke its agents (e.g. redsen-lean-harness:conductor) and skills (e.g. /fast-track) — verified end-to-end on this machine:
# preferred: via the marketplace this repo publishes (no npm publish required, no deprecation warning)
copilot plugin marketplace add redsentech/lean-harness
copilot plugin install redsen-lean-harness@redsen
# also works, but Copilot CLI prints a deprecation warning for direct-source installs:
copilot plugin install redsentech/lean-harness
Use this when: you're a day-to-day Copilot CLI user who wants the harness available across multiple projects and doesn't need to modify the harness itself.
Limitation: this installs the behaviour layer only. You still need lh on PATH (see
below) — either npm install -g @redsentech/lean-harness from GitHub Packages (once you've
pointed the @redsentech scope at it, see The lh CLI), or step
B/C below.
B. Bootstrap an existing repo with the onboarding script
Use this when: you're on VS Code Copilot (which has no plugin installer and reads
.github/ directly), you want to try the harness against one specific repo before deciding to
install it host-wide, or you want lh linked in one shot without a separate npm step.
git clone git@github.com:redsentech/lean-harness.git # one-time, holds the source of scripts/onboard.mjs
cd lean-harness && npm install
node scripts/onboard.mjs /path/to/your-project --dry-run # preview only
node scripts/onboard.mjs /path/to/your-project --yes # do it
This copies the behaviour layer into /path/to/your-project, npm links the lh CLI onto
PATH there, and runs lh init + lh doctor for you. Safe to re-run.
C. Clone and work inside this repo directly
Use this when: you're contributing to the harness itself (fixing an agent, a skill, or lh).
git clone git@github.com:redsentech/lean-harness.git
cd lean-harness
npm install
npm link # puts `lh` on PATH globally, pointing at this checkout
2. Initialize and verify the environment
Inside your project (skip if the onboarding script already ran this):
lh init # first-run wizard; writes .agents/harness.config.json
lh doctor # confirms Node, git, Context7 key, verify commands, etc.
lh doctor should print all green checks. If it flags "no verify command configured", add a
test/build/lint command to .agents/harness.config.json — the Ralph loop uses it to decide
when a lane is actually done.
This creates a per-repo .agents/ footprint:
.agents/
harness.config.json
architecture.md # living ADR log
conventions.md # living project conventions
memory/INDEX.md # the only file auto-loaded every run
memory/{seed,failures,corrections,insights,conventions,quirks}.md
3. Run your first task
Open Copilot CLI or VS Code Copilot in the project and pick the entry point that matches the size of the change.
Full pipeline (new feature, non-trivial change):
Use the conductor agent to build a rate limiter for the public API
How agent invocation actually works (per the official docs):
@in Copilot CLI only mentions files, never agents. There are three real ways to invoke a custom agent:
/agent— opens an interactive picker to browse and select.- Name it in your prompt —
Use the conductor agent to ...— Copilot infers which agent you mean.copilot --agent=NAME -p "..."— force a specific agent non-interactively.Agent name note: inside this repo (or any repo where the harness lives natively in
.github/agents), the bare nameconductorresolves. Once installed as a plugin into another project, Copilot CLI namespaces agents only — the resolvable name becomesredsen-lean-harness:conductor,redsen-lean-harness:architect, etc. (confirmed viacopilot --agent <bad-name>, whose error message lists every real agent name it knows, always namespaced for plugin-sourced agents). Skills are never namespaced —/fast-track,/design,/build,/verify,/onboard, etc. work as plain slash commands regardless of install method (confirmed viacopilot plugins list --kind skill --json, whosenamefields carry no prefix).Known limitation: a plugin-sourced agent can be launched (by full name in a prompt, or via
--agent=plugin-name:agent-name) even when it isn't proactively suggested. Copilot's owncopilot plugins listcommand documents that "custom agents ... require a live session and will be added in a follow-up" — i.e. the CLI's own agent-introspection tooling doesn't yet fully cover plugin-contributed agents, which likely also affects what the/agentpicker surfaces and what the model volunteers unprompted. Naming the agent explicitly (Use the conductor agent to ...) reliably works around this today.If naming the agent explicitly still fails: the plugin was likely loaded before a fix landed. Run
copilot plugin marketplace update redsen && copilot plugin update redsen-lean-harness, then start a newcopilotsession — an already-running session keeps the plugin snapshot it loaded at startup and won't pick up the update until restarted.
This runs the whole pipeline: interrogator asks clarifying questions with recommended
answers (you must answer before it proceeds — this is a deliberate gate), architect writes
the spec and acceptance criteria, splitter breaks it into lanes, builder/verifier run the
Ralph loop per lane (in parallel git worktrees when lanes don't overlap), integrator merges
sequentially, and scribe journals everything as it happens.
Small brownfield fix (skip spec + DAG ceremony):
/fast-track fix the off-by-one in pagination
Learn an unfamiliar codebase first:
/onboard
4. When do you need to type lh yourself?
Short answer: almost never during a normal pipeline run. Every agent's instructions
require it to call the relevant lh subcommand itself, at a specific point, every time —
you don't ask for it and you can't opt it out. The table below is exhaustive: every lh
subcommand, who calls it, and when.
| Command | Who runs it | When |
|---|---|---|
lh index |
interrogator, scout, architect, splitter |
Automatically, before reading files, to build token-budgeted context |
lh host |
conductor |
Automatically, first thing, to pick parallel-vs-sequential strategy |
lh run start/event/end |
conductor (start/end), every agent (event) |
Automatically, for every phase transition — never skipped |
lh lane create/status/merge |
conductor, builder, integrator |
Automatically, before a write lane starts and when it merges |
lh memory get/put/scan |
interrogator, architect, builder, scribe |
Automatically, to pull relevant shards before work and record facts/failures after |
lh graph |
verifier (always), plus architect/splitter/conductor/reviewer/scout/integrator at their own checkpoints |
Automatically — it's exit criterion #3, never skipped |
lh doctor |
conductor (first thing, before lh host), also you whenever you want to check the environment yourself |
Automatically at the start of every pipeline run — conductor's step 1 |
lh init --yes |
conductor, automatically, only if lh doctor reports config not initialised |
Self-heals a missing .agents/ baseline with non-interactive defaults, then re-runs lh doctor |
lh report <run-id> |
You | After a run, when you want a human-readable markdown summary instead of raw NDJSON. No agent generates this for you |
So in everyday use you don't have to type lh init or lh doctor by hand at all —
conductor runs lh doctor first, and if that reports the repo isn't initialised, it runs
lh init --yes for you (defaults, no prompts) and re-checks before doing anything else. It
still stops and reports the exact failing check if lh doctor finds something it can't
self-heal (for example no verify commands configured yet in a brand-new, empty repo).
lh init/lh doctor remain available for you to run by hand too — useful before starting
(to pre-flight a repo), after upgrading Node/git/the plugin, or to diagnose a stuck run outside
the agent flow. The only command with no agent equivalent at all is lh report (reading a past
run's summary). Everything else — lh index, lh host, lh run, lh lane, lh memory,
lh graph — is invoked by the agents as a scripted, mandatory step in their own instructions.
5. Know when it's actually done
A lane only completes when all five hold (otherwise it iterates, and escalates to you at the iteration cap):
- Every declared verify command exits 0
- Every acceptance criterion is individually checked off
lh graphpassesreviewerapproves- No files changed outside the lane's declared scope
6. Where things are written
Everything the harness does is self-documenting — nothing lives only in a chat transcript:
| What | Where |
|---|---|
| Design decisions | .agents/specs/<slug>/decisions.md |
| Spec + acceptance criteria | .agents/specs/<slug>/spec.md |
| Lane DAG | .agents/specs/<slug>/plan.dag.json |
| Run telemetry | .agents/runs/<id>/events.ndjson |
| Run journal | .agents/runs/<id>/journal.md |
| ADRs | .agents/architecture.md |
| Durable conventions | .agents/conventions.md |
| Cross-run memory | .agents/memory/*.md |
Troubleshooting
| Symptom | Fix |
|---|---|
lh doctor fails on Context7 |
export CONTEXT7_API_KEY=... in your shell, then re-run |
lh doctor warns "no verify command" |
Add a test/build/lint command to harness.config.json |
lh init refuses to run again |
Expected — it won't clobber an existing config. Use lh init --force to reset |
lh not found after onboarding |
Re-run without --no-npm-link, or invoke via the absolute path the script prints |
Agents/skills installed via copilot plugin install but lh init/lh doctor fail with "command not found" |
Expected — plugin install only adds the behaviour layer. Run npm link from a clone (path C) or scripts/onboard.mjs (path B) to get lh on PATH |
copilot plugin install owner/repo prints a deprecation warning |
Expected for direct-source installs. Use copilot plugin marketplace add + copilot plugin install name@marketplace instead (path A) |
npm install -g @redsentech/lean-harness gives 404/403 |
.npmrc isn't pointed at GitHub Packages, or the token lacks read:packages. Run node scripts/setup-npm-registry.mjs — see Generating a GitHub token if you don't have one yet |
setup-npm-registry.mjs doesn't open a browser (SSH/headless) |
Expected — it falls back to printing the token creation URL. Pass --no-open to skip the attempt entirely |
| Pipeline stuck at design gate | interrogator is waiting on your answers — this is intentional, answer the questions |
Next steps
- Read the Pipeline and Agents sections in the README for the full mental model.
- Read the full
lhCLI flag reference for every subcommand. - Read ADR 0001 for why the harness is split the way it is.