No description
  • JavaScript 68.4%
  • TypeScript 28.4%
  • Shell 3.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Riccardo Agnoletto 3d8f88c86f docs: bootstrap describes the npm mcp dependency as the default
README and SKILL.md write 6 said the ts-morph MCP is a git dependency that runs prepare on install; the pinned npm devDependency has been the default since v0.1.0.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 10:51:42 +02:00
.claude docs: bootstrap describes the npm mcp dependency as the default 2026-09-18 10:51:42 +02:00
.github/workflows feat: update template to match source repo with unified CLI, TS validators, and pnpm 2026-02-20 17:41:13 +01:00
.tasks feat: update template to match source repo with unified CLI, TS validators, and pnpm 2026-02-20 17:41:13 +01:00
assets docs: restructure README into three sections and add 1D hero lockup 2026-04-18 01:48:36 +02:00
docs feat: plan-as-contract enforcement — reconcile-plan.sh + templates + checklist 2026-05-16 16:13:13 +02:00
scripts feat: plan-as-contract enforcement — reconcile-plan.sh + templates + checklist 2026-05-16 16:13:13 +02:00
.gitignore feat: add Claude Code harness with bootstrap skill and quality-gate hooks 2026-04-18 00:49:43 +02:00
AGENTS.example.md feat: add code-search skill for LLM tool-selection discipline 2026-04-20 10:46:40 +02:00
BOOTSTRAP.md feat: bootstrap offers ts-morph-readonly MCP wiring for TS monorepos 2026-04-20 21:45:28 +02:00
CLAUDE.md feat: bootstrap wires opencode.json and .pi skills pointer alongside .mcp.json 2026-09-18 10:34:09 +02:00
LICENSE docs: replace gplv3 license file with mit 2026-07-06 11:25:18 +02:00
package.json feat: update template to match source repo with unified CLI, TS validators, and pnpm 2026-02-20 17:41:13 +01:00
pnpm-lock.yaml feat: update template to match source repo with unified CLI, TS validators, and pnpm 2026-02-20 17:41:13 +01:00
quality-gates.conf.example feat: add Claude Code harness with bootstrap skill and quality-gate hooks 2026-04-18 00:49:43 +02:00
README.md docs: bootstrap describes the npm mcp dependency as the default 2026-09-18 10:51:42 +02:00

llm/template — a harness for LLM-assisted dev

A project scaffold for LLM-assisted development: YAML task definitions, an RFC/ADR document flow, and Claude Code hooks that gate subagent output, plus skill/MCP pointers for opencode and pi.

The template is split into three areas, mirrored by the sections below:

  1. Getting started — clone, install, bootstrap.
  2. How the harness is meant to be used — the LLM + human loop it's designed around.
  3. Configuration & tinkering — when defaults don't fit.

1. Getting Started

Clone and install

git clone <template-repo> your-project
cd your-project
rm -rf .git && git init
pnpm install

Bootstrap the harness

Open the project in Claude Code and run:

/bootstrap

(or say "bootstrap this project"). The bootstrap skill:

  1. Detects your stack (Node / Python / Rust / Go) and — for Node — the monorepo flavour (pnpm workspaces / Nx / Turborepo / npm workspaces).
  2. Confirms LINT, TYPECHECK, and TEST commands with you.
  3. Writes quality-gates.conf and AGENTS.md at the repo root.
  4. Personalises the code-search skill with stack-specific guidance.
  5. If a TS monorepo is detected, offers to wire the ts-morph-readonly MCP end-to-end (pinned npm devDependency + tsconfig.tsmorph.json + .mcp.json, mirrored into opencode.json). Declined by default in non-interactive mode.
  6. For every stack, writes opencode.json and .pi/settings.json skill pointers so opencode and pi pick up the same .claude/skills directory as Claude Code.
  7. Drops a .bootstrapped marker.

Until .bootstrapped exists, a UserPromptSubmit hook blocks every non-bootstrap prompt — you can't accidentally burn tokens on an unadapted harness.

Re-run with /bootstrap --update after changing package manager, test runner, or similar. It re-detects the stack and diffs before applying.

What's active after bootstrap

Three hooks registered in .claude/settings.json:

Hook Event Behaviour
preflight.sh SessionStart Non-blocking warnings: missing SSH agent, stale pnpm install, missing .bootstrapped
bootstrap-gate.sh UserPromptSubmit Blocks prompts until .bootstrapped exists (idle after bootstrap)
post-subagent-gate.sh SubagentStop Runs LINT + TYPECHECK from quality-gates.conf; rejects subagent handoff on failure

Which client reads what

Client Reads Skills Hooks / MCP
Claude Code CLAUDE.md .claude/skills .claude/settings.json hooks; .mcp.json MCP
opencode AGENTS.md opencode.json skills.paths opencode.json mcp; no hooks — gates are rules
pi AGENTS.md / CLAUDE.md .pi/settings.json skills none
oh-my-pi (omp) AGENTS.md / CLAUDE.md .claude/skills (native) none

Hook enforcement ships for Claude Code only (the SubagentStop hook evaluates quality-gates.conf automatically); every other client must run those same gates itself — from quality-gates.conf or the AGENTS.md Quality gates section.

Further reading: BOOTSTRAP.md, .claude/skills/bootstrap/SKILL.md.


2. How the harness is meant to be used

The template assumes LLMs do the bulk of the work. Humans produce intent (stories, RFCs, ADRs); LLMs turn intent into executable task YAML, work on it under the supervision of the hooks, and sync results back into the human-readable docs. The file layout, CLI, and hooks exist to make that loop reliable — not to be driven by hand.

The loop

1. Human   → write an RFC or story in docs/
2. LLM     → read intent, produce task YAML in .tasks/tracked/*.yaml
3. LLM     → `pnpm tasks ready` — pick the next unblocked task
4. LLM     → implement against the task's file targets and acceptance criteria
5. Hook    → SubagentStop runs lint + typecheck; rejects the handoff on failure
6. LLM     → mark the task `done` in its YAML
7. LLM     → `pnpm tasks:sync-docs -- --apply` — write completion back into docs
8. Human   → review diff, commit

Artifacts and who writes them

Artifact Written by Read by Purpose
docs/rfcs/*.md, docs/stories/*.md Human LLM Expresses intent, constraints, goals
docs/decisions/*.md (ADRs) Human or LLM Both Records why a choice was made
.tasks/tracked/*.yaml LLM (from intent) LLM Executable work with acceptance criteria
docs/logs/*.md LLM Human What was actually done
CLAUDE.md Human Main agent Project-wide context
AGENTS.md Bootstrap skill Subagents Minimal per-spawn context (stack, commands, gates)
quality-gates.conf Bootstrap skill post-subagent-gate.sh Commands the SubagentStop hook runs

Commands the LLM uses during the loop

pnpm tasks ready                  # next unblocked task
pnpm tasks list --status pending  # all pending tasks
pnpm tasks validate               # YAML against schema (CWE-22/400/776 safe)
pnpm tasks drift                  # detect desync between tasks and docs
pnpm tasks verify-links           # referenced docs must exist
pnpm tasks:sync-docs -- --apply   # write task completion into referenced docs

Why the hooks exist

  • bootstrap-gate.sh — without it, an LLM could run pnpm tasks against a repo whose lint/typecheck commands are still placeholders, producing junk results and junk tasks.
  • post-subagent-gate.sh — without it, a subagent can write plausible-looking code that breaks the build and return a confident "done" summary; the hook forces that failure back into the loop instead of into the main agent's context.
  • preflight.sh — surfaces environmental gotchas (no SSH agent, stale deps) at session start, before the LLM starts inferring from broken tooling.

Templates

LLMs producing artifacts should start from docs/templates/:

Artifact Template
Decision record ADR-TEMPLATE.md
Change proposal RFC-TEMPLATE.md
User story STORY-TEMPLATE.md
Detailed design SPEC-TEMPLATE.md
Implementation log LOG-TEMPLATE.md
Schema doc SPEC-SCHEMA-MACHINE.md
CLAUDE.md separation CLAUDE-MD-SEPARATED-TEMPLATE.md

Lifecycle walkthrough: docs/DOCUMENTATION.md. Task schema: docs/TASKS.md.


3. Configuration & Tinkering

Everything below is reference material for when defaults don't fit.

Directory reference

.
├── .claude/                        # Harness: hooks + skills
│   ├── settings.json
│   ├── hooks/{preflight,bootstrap-gate,post-subagent-gate}.sh
│   └── skills/bootstrap/SKILL.md
├── .tasks/
│   ├── schema.json, spec-schema.json, config.json
│   ├── src/                        # TS validators
│   ├── test/
│   └── tracked/*.yaml              # Task definitions
├── docs/
│   ├── templates/, rfcs/, decisions/, logs/
│   └── DOCUMENTATION.md, TASKS.md
├── scripts/                        # tasks-cli.js, tasks-*.js
├── .github/workflows/tasks-drift-check.yml
├── AGENTS.example.md, BOOTSTRAP.md, CLAUDE.md, quality-gates.conf.example
└── package.json, README.md

.tasks/config.json

Centralized CLI and validator settings:

{
  "schemas": { "task": "schema.json", "spec": "spec-schema.json" },
  "directories": { "tracked": "tracked", "local": "local", "specifications": "../docs/product/specifications" },
  "validation": { "strict": true, "maxConcurrency": 10 },
  "output": { "format": "pretty", "colors": true },
  "exitCodes": { "success": 0, "validationError": 1, "driftDetected": 2 }
}

Environment variables

Variable Default Description
TASKS_PROJECT_ROOT cwd Project root
TASKS_BASE_DIR .tasks Tasks directory relative to the project root
SECTION_PARSING hierarchical Section parsing mode (hierarchical or flat)
LLM_TEMPLATE_DEV unset Set to 1 when developing this template itself — disables the bootstrap gate and preflight warnings

Custom paths

TASKS_BASE_DIR=my-tasks pnpm tasks:list
TASKS_PROJECT_ROOT=/path/to/project pnpm tasks:ready

All task CLI commands

# Unified form
pnpm tasks <check|list|ready|validate|drift|sync|verify-links> [flags]

# Scripted form (passes flags through pnpm with --)
pnpm tasks:validate
pnpm tasks:validate:ts
pnpm tasks:list -- --status pending --epic "Name"
pnpm tasks:ready -- --include-templates
pnpm tasks:check-drift
pnpm tasks:sync-docs -- --apply
pnpm tasks:verify-links

CI integration

The template ships .github/workflows/tasks-drift-check.yml which runs on PRs that touch .tasks/ or docs/.

For a custom pipeline:

- uses: pnpm/action-setup@v2
  with: { version: 9 }
- uses: actions/setup-node@v4
  with: { node-version: '20', cache: 'pnpm' }
- run: pnpm install --frozen-lockfile
- run: pnpm tasks:validate
- run: pnpm tasks:check-drift

Extending the task schema

  1. Edit .tasks/schema.json.
  2. If the new field needs processing, update scripts/tasks-utils.js.
  3. If it needs rich error messages, update the TS validators in .tasks/src/.
  4. Document it in docs/TASKS.md.

Validator architecture: .tasks/VALIDATION.md.

Developing this template itself

The bootstrap gate is active in every project including this repo — so iterating on the template requires the escape hatch:

export LLM_TEMPLATE_DEV=1

Both bootstrap-gate.sh and preflight.sh honor this variable and skip their behaviour. Cloned projects don't inherit it, so end users still get the full guardrails.


License

MIT