- JavaScript 68.4%
- TypeScript 28.4%
- Shell 3.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
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> |
||
| .claude | ||
| .github/workflows | ||
| .tasks | ||
| assets | ||
| docs | ||
| scripts | ||
| .gitignore | ||
| AGENTS.example.md | ||
| BOOTSTRAP.md | ||
| CLAUDE.md | ||
| LICENSE | ||
| package.json | ||
| pnpm-lock.yaml | ||
| quality-gates.conf.example | ||
| README.md | ||
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:
- Getting started — clone, install, bootstrap.
- How the harness is meant to be used — the LLM + human loop it's designed around.
- 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:
- Detects your stack (Node / Python / Rust / Go) and — for Node — the monorepo flavour (pnpm workspaces / Nx / Turborepo / npm workspaces).
- Confirms
LINT,TYPECHECK, andTESTcommands with you. - Writes
quality-gates.confandAGENTS.mdat the repo root. - Personalises the
code-searchskill with stack-specific guidance. - If a TS monorepo is detected, offers to wire the
ts-morph-readonlyMCP end-to-end (pinned npm devDependency +tsconfig.tsmorph.json+.mcp.json, mirrored intoopencode.json). Declined by default in non-interactive mode. - For every stack, writes
opencode.jsonand.pi/settings.jsonskill pointers so opencode and pi pick up the same.claude/skillsdirectory as Claude Code. - Drops a
.bootstrappedmarker.
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 runpnpm tasksagainst 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
- Edit
.tasks/schema.json. - If the new field needs processing, update
scripts/tasks-utils.js. - If it needs rich error messages, update the TS validators in
.tasks/src/. - 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.
Related Documentation
- CLAUDE.md — Main-agent context
- BOOTSTRAP.md — First-turn LLM bootstrap instructions
- AGENTS.example.md — Subagent context template
- .claude/skills/bootstrap/SKILL.md — Bootstrap skill definition
- docs/DOCUMENTATION.md — Documentation lifecycle
- docs/TASKS.md — Task schema guide
- .tasks/README.md — Task CLI quick reference
- .tasks/VALIDATION.md — Validator architecture
License
MIT