@davidbalzan/groundwork
v0.4.19
Published
Groundwork — an installable AI development workflow (skills + doc methodology) you bolt onto any repo.
Maintainers
Readme
Groundwork
An installable AI development workflow you bolt onto any repo. It gives your AI assistant persistent project context, a phase-based process, and deterministic helper scripts — working identically across Claude Code, Cursor, and VS Code Copilot from a single source.
It's a small CLI that installs the workflow into any repo — new or existing — and re-syncs in place as it improves. (A bolt-on, not a template you fork.)
npm i -g @davidbalzan/groundwork
groundwork init # full workflow into the current repo
groundwork init . --minimal # just the core 6 skillsSource lives in the groundwork-kit monorepo (
packages/groundwork); the olddavidbalzan/groundworkremote is frozen.
One-time per machine (only if you use
/remember): point Groundwork at your central knowledge repo —groundwork knowledge link <path>(orexport GROUNDWORK_KNOWLEDGE=<path>in your shell profile). This is separate frominitand machine-local — it doesn't travel. See Cross-project knowledge.
Mental model
Groundwork is two separable pieces:
| | What it is | Where it lives |
| --- | --- | --- |
| The workflow | Skills + doc methodology + scripts | This repo — installed by groundwork init |
| The starter (optional) | A generic React/Hono monorepo to scaffold from | A separate starter repo; not required |
Repo shape: works anywhere, monorepos recommended. The Groundwork tool is a single flat npm package (no workspaces, no build, zero runtime deps) and installs into any repo — monorepo, single package, or split repos.
But in practice agents work noticeably better in a monorepo: one source tree to reason
over, shared types/contracts in one place, atomic cross-package changes, and — for swarms —
a single coordination bus and one worktree space. Split repos are supported, but you'd
run a coord-mcp bus per module, which adds coordination overhead and makes cross-repo
changes harder for agents to get right. So a monorepo isn't required, it's recommended —
which is why the methodology's apps/web + apps/api layout is the default shape.
Design principles
These emerged from real use and shape every decision:
- Harness-agnostic first. The value lives in portable markdown skills + a plain
node/npxCLI — not harness-specific glue like session-start hooks. So it behaves identically across Claude Code, Cursor, and parallel multi-agent / multi-harness runs. - Single source → generated. Anything that would otherwise be duplicated is generated
from one source: IDE mirrors from
SKILL.md,ARTIFACTS.mdfrom a manifest, versions fromSTACK_MAP. Drift is prevented by construction, not discipline. - Deterministic where the model is weak. Counting, version checks, and drift detection
run as scripts/CLI (
check-task,groundwork status,doctor) — not LLM guesswork. - Spec-first, minimal tests. Rigor lives in the docs/spec; tests are an opt-in tripwire, not a default (see methodology §4b — and its caveat for human handover).
The flow
┌─────────────────────────── one-time ───────────────────────────┐
groundwork init ──▶ │ /create-prd ──▶ /kickstart ──▶ /check-versions ──▶ /plan-phase 1 │
└──────────────────────────────────────────────────────┬──────────┘
│
┌──────────────────────────── per session / per stream ───────────────────┘
▼
/start-session ─▶ …code… ─▶ /check-task ─▶ /update-workstreams ─▶ /log-decision (progress: `groundwork status`)
▲
external coordinator ┘ (reads QUEUE, writes WORKSTREAMS + DONE)initdrops skills, IDE mirrors, docs, and scripts into the repo./create-prdis the first step — the single product-discovery interview (problem, users, goals, scope, requirements, high-level phases) →docs/PRD.md./kickstartconsumes the PRD to scaffold the project docs (tech stack, architecture, roadmap, phases, WORKSTREAMS, QUEUE/DONE) — it does not re-ask what the PRD already covered./check-versionspins the stack to latest stable soSTACK_MAP.mdstarts honest./plan-phase Nturns each phase into a checkbox task file and aQUEUE.mditem.- Work loop:
/start-sessionloads context;/check-taskmarks tasks done andgroundwork statusreports progress deterministically;/update-workstreamsrecords live parallel work;/log-decisioncaptures ADRs.
The skills
min = installed by --minimal · opt = optional (add with groundwork add <name>).
mode is how the VS Code mirror is generated: ask = read-only, edit = can modify files.
| Skill | min/opt | mode | What it does |
| ----- | ------- | ---- | ------------ |
| kickstart | min | edit | Scaffold all project docs from the PRD (tech stack, roadmap, phases, WORKSTREAMS, QUEUE/DONE) — no re-interview |
| next | min | ask | Flow coach — inspects project state and recommends the single best next step |
| plan-phase | min | edit | Turn a phase goal into a detailed task file + add it to QUEUE |
| start-session | min | ask | Load current context: active phase, recent decisions, next backlog item |
| check-task | min | edit | Mark a task done and recompute progress (uses a deterministic script) |
| update-workstreams | min | edit | Update WORKSTREAMS.md — live state of every parallel stream |
| create-prd | opt | edit | Guided 6-stage Product Requirements Document |
| domain-model | opt | edit | Build the ubiquitous-language glossary (CONTEXT.md) + bounded-context map |
| log-decision | opt | edit | Append an Architectural Decision Record to DECISIONS.md |
| check-versions | opt | edit | Audit dependencies vs latest stable; flag drift; refresh STACK_MAP.md |
| add-data-layer | opt | edit | Add an optional Drizzle + PostgreSQL data layer (DB is opt-in) |
| remember | opt | edit | Capture a cross-project lesson in the central git knowledge repo — quick note, or a formal ADR with --adr |
All twelve are authored once as SKILL.md; the Cursor and VS Code variants are
generated (see below).
Auto-execution
Every skill is agent-invocable by default — the assistant runs the right one on its
own when a skill's description matches the situation (e.g. it reaches for next when
you ask "what should I do now?"). You can still call any of them explicitly with
/<name>. None set disable-model-invocation, so nothing is locked to manual-only. The
quality of each description is what makes auto-selection accurate — keep them
action-oriented when you add skills.
What gets installed
your-repo/
├── .claude/skills/<name>/SKILL.md # canonical skills (Claude Code)
├── .cursor/commands/<name>.md # generated mirror (Cursor)
├── .vscode/prompts/<name>.prompt.md # generated mirror (VS Code Copilot)
└── docs/
├── GROUNDWORK_METHODOLOGY.md # the full methodology
├── STACK_MAP.md # single source of truth for versions
├── COMMANDS.md, _INDEX.md # command guide + Obsidian map of content
├── WORKSTREAMS.md # live parallel-work state
├── templates/ # doc templates /kickstart fills in
├── phases/ # phase structure + task templates
└── .groundwork/
├── VERSION # installed Groundwork version
└── scripts/ # deterministic helpers (below)Project-specific docs (TECH_STACK.md, PRODUCTION_ROADMAP.md, PHASE*_TASKS.md,
QUEUE.md, …) are generated by the skills, not by init.
Helper scripts (deterministic, not LLM-guessed)
Shipped to docs/.groundwork/scripts/ and preferred by the matching skills:
| Script | Backs | Does |
| ------ | ----- | ---- |
| check-task.mjs | /check-task | Flip a checkbox, recompute Overall Progress, print % |
| phase-status.mjs | groundwork status / on-demand | Count checkboxes per phase, render progress bars |
| check-versions.mjs | /check-versions | npm view each stack dep, report pinned vs latest, exit non-zero if behind |
Upgrading: nothing migrates your content
groundwork update never rewrites your work. It refreshes the files Groundwork
installed and leaves everything else alone. There is no auto-migration, and that is a
decision rather than a gap — an auto-migrating skill was considered and rejected, because
the failure mode is silent data loss in the one place you would not look for it.
What that means in practice:
- A doc you edited is KEPT and named in the summary, not overwritten. Taking an
upstream version is a deliberate act:
--force-skillsor--force-docs. - An older board grammar keeps parsing as itself. A 5-column Active Streams table is
read as
workstreams.lanes-v0— it is not upgraded, not rewritten, and not treated as broken. You move to the 6-columnworkstreams.v1grammar when you choose to, by editing the table. - Nothing reformats a file to normalise it. If a table renders, it stays as written.
One honest exception, and it is narrow. A file installed before Groundwork recorded
install baselines has no recorded hash to compare against, so update cannot tell an
edited file from an untouched one. Those used to be kept forever — which quietly meant a
card could stay two weeks stale while update reported success. Now, if git says the
file is tracked and has no uncommitted changes, it is refreshed and listed under
"Refreshed N pre-baseline file(s)" — because git can give it back (git checkout --
<path>), so the refresh costs a command rather than a fact. If the file is untracked,
uncommitted, or the project is not a git repo, it is still kept.
If you want to see what would change before it does, groundwork update --dry-run reports
the same decisions without writing.
Versions stay honest
Two mechanisms keep dependency versions from rotting:
- One source of truth — every version number lives only in
docs/STACK_MAP.md(pinned, latest-stable, and which files to touch when bumping). No other doc restates a version; they link to it. Drift becomes impossible by construction. - A check baked into bootstrap —
/kickstartruns/check-versions, which queries the registry and flags anything a major behind. Re-run it anytime; it updatesSTACK_MAP.mdand the audit date. Major bumps are recommended as their own workstream (branch + build/test verify), never inline with feature work.
Docs stay honest (doctor)
Living docs are only worth trusting if they can't quietly lie. groundwork doctor is a
deterministic, offline lint for doc↔reality drift:
- orphaned
[[wikilinks]](alias-aware — respects each note's frontmatteraliases:), - phases 100%-done in tasks but not marked complete,
- PRDs missing core sections, phase dirs with no tasks file,
- a stale
VERSIONmarker orSTACK_MAPaudit, - ADR tripwire — an Accepted ADR whose rejected alternative (its "Alternatives Considered"
rows) now appears as a dependency in any
package.jsonor as a top-level/workspace directory (react-native/expo/ios/after "PWA over native",bcryptafter "magic link over password", …). Either supersede the ADR or record a factadr-NNN-accepted-deviationinFACTS.mdto silence it. Field case: two ADRs silently reversed in one week and stayed Accepted for five months — the docs agents read every session were wrong.
It exits non-zero on issues, so it drops straight into a pre-commit hook or CI. It's the
enforcement third of a loop: the manifest keeps the doc list single-sourced,
update --docs refreshes the generic docs, and doctor flags what drifted.
Honest boundary: doctor catches structural / consistency drift, not whether prose
matches the running code — that still needs you or the agent (or the optional test tripwire).
The ADR tripwire is keyword-based (src/lib/adr-tripwire.mjs ALIASES maps alternative names
to package/dir tokens — extend it); it catches the reversal that shows up as a dependency or a
folder, not one that is pure code. Tokens that also appear in the ADR title / Decision / Context
(alias-expanded) are the accepted path and are not hits; generic project-wide paths (docs/,
templates/) are not hits.
Data layer is opt-in
The starter ships no database — it stays generic. When a feature actually needs
persistence, run /add-data-layer (Drizzle ORM + PostgreSQL by default; MySQL/SQLite
supported). It wires the client, schema, migrations, env, docker service, and scripts,
pins to latest stable, and records an ADR. Until then, nothing about a DB clutters the
project.
Cross-project knowledge
Lessons that outlive a single project live in a central git knowledge repo — one per user, not bundled with Groundwork. Set yours up once:
groundwork knowledge init # scaffold ~/groundwork-knowledge + save the path
# or point at an existing clone:
groundwork knowledge link ~/path/to/your-knowledge-repo
groundwork knowledge sync [--push] # pull latest from origin (and optionally push)
groundwork knowledge path # show what's resolvedSync behaviour: /remember pulls from origin before writing and
pushes after — so the log stays current across machines and the swarm, and you never
write onto stale state. Run groundwork knowledge sync yourself to freshen a clone (e.g.
when you start on a new machine — init installs the project workflow, it does not touch
your separate knowledge repo).
The location resolves per user, in order: $GROUNDWORK_KNOWLEDGE → the saved user
config (~/.config/groundwork/config.json) → otherwise the skills tell you to run the
setup above. There is no hardcoded/shared default — your ADRs go in your repo.
/rememberappends a dated note (notes/lessons.md), commits, pushes./remember --adrpromotes a lesson into a formal ADR (adr/NNNN-*.md) and updates the index — for decisions that are hard-to-reverse, surprising, and a real trade-off.
Both are tool-agnostic (git + markdown), so the swarm and any assistant share one log.
Project-specific decisions still go in that project's docs/DECISIONS.md via /log-decision.
Multi-agent seam (optional)
Groundwork runs solo out of the box — a one-row WORKSTREAMS.md, no coordinator. When
you want a swarm, it hands off via a file contract split by writer, without absorbing the orchestration:
QUEUE.md— the inbound queue./plan-phaseand you write it (and nobody else); one item per phase.WORKSTREAMS.md— the live state. The coordinator/workers (and/update-workstreams) write it as work proceeds.DONE.md— the completion log. The executor appends one line per completed item (its only write in the queue seam).
One-way dependency: the coordinator depends on Groundwork's seam, never the reverse —
Groundwork has no knowledge of any coordinator and works fully without one. The reference
implementation is coord-mcp, an MCP-based coordination server (harness-agnostic, same
principle as Groundwork) that's an optional layer on top. Any orchestrator honouring the two
files drops in just as well — rooms, worktrees, and messaging stay entirely outside Groundwork.
Supported harnesses
One init installs the same workflow into three AI coding harnesses, each in its native
location:
| Harness | Skills installed to | Format |
| ------- | ------------------- | ------ |
| Claude Code | .claude/skills/<name>/SKILL.md | canonical source (frontmatter + body) |
| Cursor | .cursor/commands/<name>.md | generated mirror (skill body, no frontmatter) |
| VS Code Copilot | .vscode/prompts/<name>.prompt.md | generated mirror (mode: ask/edit) |
The CLI itself is plain node/npx and the docs are portable markdown, so the workflow also
runs unchanged in any other agent or in parallel multi-agent / multi-harness setups — those
three are the harnesses with first-class generated skill mirrors.
How the IDE mirrors stay in sync
SKILL.md (Claude Code) is the only hand-edited source. init, update, and add regenerate:
- Cursor (
.cursor/commands/*.md) — the skill body, no frontmatter. - VS Code (
.vscode/prompts/*.prompt.md) —mode: askwhen the skill'sallowed-toolsare read-only (Read, Glob, Grep), elsemode: edit.
Both carry a GENERATED … do not edit by hand banner. Edit the skill, run
groundwork update, and all three harnesses move together.
Commands
| Command | Purpose |
| ------- | ------- |
| groundwork init [dir] | Install skills + IDE mirrors + docs + scripts (--minimal, --force) |
| groundwork update [dir] | Upgrade skills + mirrors + helper scripts in place (leaves your project docs alone). --all installs skills added upstream; --docs refreshes the generic reference docs (methodology, COMMANDS, _INDEX, ARTIFACTS) |
| groundwork artifacts [dir] | Regenerate docs/ARTIFACTS.md from the manifest |
| groundwork add <skill> [dir] | Add one optional skill and its mirrors |
| groundwork list [dir] | List skills with install state, minimal/optional, and mode |
| groundwork status [dir] | Live workstreams + next backlog item + phase progress |
| groundwork doctor [dir] | Flag doc↔reality drift: orphaned wikilinks, phases 100%-done but not marked, stale version marker / versions audit |
| groundwork knowledge <init\|link\|path> | Configure your per-user central ADR/lessons repo |
| groundwork help / version | Usage / version |
This repo's structure
src/cli.mjs # entry + command dispatch
src/commands/*.mjs # init · update · add · list · status · doctor · artifacts · knowledge
src/lib/*.mjs # skills (parse + mirror gen) · artifacts (manifest) · fs · paths · progress · config · log
payload/skills/ # the 12 canonical SKILL.md files (the single source)
payload/doc-templates/ # docs scaffold (methodology, STACK_MAP, templates, phases, WORKSTREAMS)
payload/scripts/ # project-side deterministic helpers
docs/DECISIONS.md # ADRs about Groundwork itself
MIGRATION_PLAN.md # how/why it became a bolt-onPlain Node ESM (>=20), zero runtime dependencies, no build step. To add a skill: drop
a SKILL.md in payload/skills/<name>/, then groundwork update any project to pull it.
License
MIT © David Balzan
