Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Agent skills

### Issue tracker

Issues live in GitHub Issues (thoughtbot/belt), via the `gh` CLI. See `docs/agents/issue-tracker.md`.

### Triage labels

Default vocabulary — needs-triage, needs-info, ready-for-agent, ready-for-human, wontfix. See `docs/agents/triage-labels.md`.

### Domain docs

Single-context: `CONTEXT.md` + `docs/adr/` at the repo root. See `docs/agents/domain.md`.
29 changes: 29 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Belt

A React Native Expo project starter and generator CLI. Belt creates new apps and adds features to existing ones — deterministically via templates today, and via agent-executed feature skills going forward.

## Language

**Feature**:
A discrete capability Belt can add to a React Native Expo app (e.g. notifications, state management). Exposed as `belt add <feature>` (deterministic) or `belt agent add <feature>` (feature skill).
_Avoid_: module, addon, generator

**Feature skill**:
A versioned, thoughtbot-authored agent skill (`SKILL.md` plus supporting files) that Belt emits into a target repo under `.claude/skills/`. It contains the detailed instructions a coding agent follows to scaffold one feature. Belt emits it; Belt never executes it.
_Avoid_: playbook, recipe, instruction markdown, prompt

**Variant**:
One of a small, thoughtbot-curated set of library choices within a single feature (e.g. Zustand vs Redux Toolkit for state management). The user picks a variant in Belt's prompt at emit time; the emitted feature skill contains only that variant.
_Avoid_: option, flavor

**Reference file**:
A thoughtbot-authored, byte-exact source file bundled inside a feature skill. The coding agent copies it verbatim into the target repo; only the wiring around it is left to the agent's judgment.
_Avoid_: template (reserved for the eta templates used by deterministic features)

**Coding agent**:
The user's AI tool (Claude Code, Cursor, etc.) that reads a feature skill and performs the actual code changes in the target repo. Lives entirely outside Belt; the `belt agent` command namespace is named after it because those commands end in a handoff to it.
_Avoid_: LLM, AI (when referring to the executor)

**Target repo**:
The user's React Native Expo app that Belt operates on.
_Avoid_: project, app (when ambiguity with Belt itself is possible)
14 changes: 14 additions & 0 deletions docs/adr/0001-belt-emits-feature-skills-agents-execute.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Belt emits feature skills; coding agents execute them

Future Belt features are delivered as feature skills: curated, versioned markdown instruction packages (agent skill format, `.claude/skills/belt-add-<feature>/SKILL.md`) that Belt copies into the target repo. Belt itself stays deterministic and offline — it makes no LLM calls and does not invoke an agent. The user's own coding agent (Claude Code via `/belt-add-<feature>`, or any agent pointed at the skill) executes the instructions and adapts them to the target codebase.

## Considered Options

- **Belt invokes the agent itself** (`claude -p`): one-command UX, rejected because Belt would take on a dependency on which agent the user has installed, their auth, and mid-scaffold failure handling.
- **Belt generates instructions via LLM at runtime**: most adaptive to the target codebase, rejected because it requires API keys, output varies per run, and thoughtbot could no longer QA the exact instructions shipped.
- **Neutral playbook format** (`.belt/playbooks/` + AGENTS.md pointer): more agent-agnostic, rejected because the skill format is emerging as a cross-agent standard and gives slash-command ergonomics in Claude Code.

## Consequences

- Adaptive behavior that today lives in TypeScript (patch fallbacks, idempotency checks) moves into skill prose executed by an agent — QA shifts from unit tests to verifying agent outcomes.
- Belt requires no API keys and works offline; the AI cost and capability ceiling belong to the user's agent.
3 changes: 3 additions & 0 deletions docs/adr/0002-new-features-only-ship-as-feature-skills.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# New features only ship as feature skills

Existing deterministic features (`create`, `add env`, `add notifications`) stay as hand-written TypeScript with templates and `patchFile` — they are not migrated. Only new features are delivered as feature skills (see ADR-0001). The two models deliberately coexist: `copyTemplate`/`patchFile` remain permanent infrastructure for the existing commands, and the skill model is proven on greenfield features before any migration is considered. Migrate an existing feature only if its deterministic implementation becomes painful to maintain.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Feature skills bundle reference files plus prose wiring instructions

A feature skill is not pure prose. Invariant code (utility modules, config blocks, tests that are identical for every user) ships as byte-exact reference files inside the skill, which the coding agent copies verbatim. Only the genuinely adaptive parts — wiring into the user's root component, navigation, or API layer, where codebases drift — are described as prose instructions for the agent to apply with judgment.

## Considered Options

- **Pure prose**: simplest authoring, rejected because every user would get slightly different code even for invariant parts, and thoughtbot could no longer QA exact outputs.
- **Exact diff spec** (full contents + precise anchors, agent as smart applier): most predictable, rejected because it forfeits the adaptivity that motivated the agent approach and is as rigid to author as templates.

## Consequences

- Reference files are QA'd via manual agent runs (ADR-0008), not static analysis — like today's eta templates, they are excluded from the Belt repo's eslint/tsc runs because they only make sense in the context of a target repo.
- Skill authoring guidelines must be explicit about the boundary: if a file's content doesn't depend on the target repo, it belongs in `reference/`, not in prose.
13 changes: 13 additions & 0 deletions docs/adr/0004-separate-agent-namespace-for-skill-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Skill-based features live under a separate `belt agent` namespace

Skill-based features are invoked as `belt agent add <feature>`, not overloaded onto `belt add`. The two commands make different promises: `belt add <feature>` is done when it exits; `belt agent add <feature>` emits a feature skill and hands off — the user's coding agent finishes the job. The namespace is named after the executor (`agent`) to signal that handoff at the point of invocation.

## Considered Options

- **Same verb** (`belt add` for both): one catalog, but silently changes the contract of an existing command — a user who ran `add env` expects `add analytics` to finish the work, not emit instructions.
- **`belt skill add`**: names the artifact (matches the glossary term "feature skill"), rejected in favor of naming the actor the user must go to next.

## Consequences

- The feature catalog is split across two help screens; docs must explain which features live where.
- Room for sibling commands under the namespace later (`belt agent list`, `belt agent update`).
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Feature skills are persistent and idempotent

An emitted feature skill stays committed in the target repo after the coding agent has executed it — it is not deleted or emitted outside the repo. Because a lingering skill can be re-invoked (accidentally or deliberately), every feature skill MUST be authored idempotently: it opens by detecting whether the feature is already installed, and if so verifies/repairs the wiring instead of re-scaffolding. Re-runs are harmless repairs, the skill doubles as living documentation of how the feature is wired, and a future `belt agent update` can refresh the skill in place.

## Consequences

- Authoring discipline: a skill without a defined already-installed behavior is incomplete.
- The skill's installed copy is frozen at the Belt version that emitted it; refreshing it is a separate concern (update/drift story).
3 changes: 3 additions & 0 deletions docs/adr/0006-skill-frontmatter-carries-version-metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Feature skill frontmatter carries version metadata; re-add is the refresh path

Every emitted SKILL.md is stamped with the Belt version that emitted it, the skill's own version, and the Expo SDK range it was written for. Refreshing a stale skill is just re-running `belt agent add <feature>`, which overwrites the installed copy (confirming when versions differ); the idempotent skill (ADR-0005) then reconciles the actual wiring on next invocation. No dedicated `belt agent update` command ships in v1 — but the metadata is mandatory from the first skill, because retrofitting frontmatter into skills already in the wild is not possible, while adding an update command later is easy.
3 changes: 3 additions & 0 deletions docs/adr/0007-skills-verify-but-do-not-commit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Feature skills verify but do not commit

Every feature skill ends with a mandatory verification block — run the target repo's lint, typecheck, and test suite, and fix failures before declaring the feature scaffolded — but does NOT instruct the agent to commit. This deliberately breaks parity with the deterministic features (`add env`, `add notifications` auto-commit): agent-applied changes are less deterministic than template output, so they stay in the working tree for human review before landing in history. Do not "fix" skill prose to add a commit step for consistency with the older commands — the asymmetry is intentional.
3 changes: 3 additions & 0 deletions docs/adr/0008-skills-are-qad-by-manual-agent-runs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Feature skills are QA'd by manual agent runs, not CI

Each feature skill ships with a QA script (formalizing the manual sync workflow already described in `CONTRIBUTING.md`): create a fresh boilerplate app, run `belt agent add <feature>`, execute the skill with a real coding agent, confirm the verification block passes, review the diff, and run the skill a second time to prove idempotency (ADR-0005). There is no automated agent E2E in CI for now — headless agent runs would cost API tokens, add flake, and require agent auth in CI before the authoring process has stabilized. Revisit once there are enough skills that manual QA per release becomes the bottleneck.
8 changes: 8 additions & 0 deletions docs/adr/0009-variants-are-chosen-at-emit-time.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Variants are chosen at emit time via Belt's prompt

Features with multiple library choices (e.g. state management: Zustand vs Redux Toolkit) offer a small thoughtbot-curated menu — 2–3 variants, never dynamic. The user picks in Belt's interactive prompt when running `belt agent add <feature>` (same inquirer pattern as `create`'s package-manager prompt; `--no-interactive` takes the thoughtbot default). Belt then emits a skill containing only the chosen variant's reference files and prose, with the variant recorded in frontmatter. Choosing differently later means re-running the command.

## Considered Options

- **Agent asks at execution time**: one emitted skill bundling all variants; rejected because every target repo would carry 2–3× reference files and the choice would live in a chat conversation instead of a deterministic prompt.
- **One feature per library** (`belt agent add zustand`): no variant machinery; rejected because the catalog sprawls and cross-cutting guidance duplicates across skills.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# SKILL.md frontmatter is stamped via gray-matter, not eta

Every other Belt feature templates its output through `eta` (`copyTemplate`/`copyTemplateDirectory`), rendering `.eta` source files with variables. `SKILL.md` deliberately does not follow this convention: its source in the Belt repo is authored as plain markdown, and Belt stamps version metadata (ADR-0006: Belt version, skill version, Expo SDK range) into only the YAML frontmatter block, programmatically, via `gray-matter`, after copying. The prose body is never passed through a template renderer.

## Considered Options

- **Author `SKILL.md` as an `.eta` file, reuse `copyTemplateDirectory` as-is**: zero new plumbing, consistent with every other feature. Rejected because it mixes templating syntax into the frontmatter of a file whose entire body is meant to be stable, agent-read prose (ADR-0003) — and a skill author typing `<%=` anywhere in the instructions would silently break rendering.

## Consequences

- New dependency (`gray-matter`) and a new util scoped to frontmatter stamping — this is intentionally not `copyTemplate`.
- `SKILL.md` source files in the Belt repo are pure markdown; nothing about them hints at templating, unlike every `.eta` file elsewhere in `templates/`. Don't "fix" this for consistency — the split is deliberate.
42 changes: 42 additions & 0 deletions docs/agents/domain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Domain Docs

How the engineering skills should consume this repo's domain documentation when exploring the codebase.

## Before exploring, read these

- **`CONTEXT.md`** at the repo root, or
- **`CONTEXT-MAP.md`** at the repo root if it exists — it points at one `CONTEXT.md` per context. Read each one relevant to the topic.
- **`docs/adr/`** — read ADRs that touch the area you're about to work in. In multi-context repos, also check `src/<context>/docs/adr/` for context-scoped decisions.

If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The producer skill (`/grill-with-docs`) creates them lazily when terms or decisions actually get resolved.

## File structure

This is a single-context repo:

```
/
├── CLAUDE.md
├── CONTEXT.md
├── Proposal.md
├── docs/
│ ├── adr/
│ │ ├── 0001-belt-emits-feature-skills-agents-execute.md
│ │ ├── ...
│ │ └── 0010-skill-md-frontmatter-stamped-via-gray-matter-not-eta.md
│ ├── agents/
│ └── the-future-of-belt.md
└── src/
```

## Use the glossary's vocabulary

When your output names a domain concept (in an issue title, a refactor proposal, a hypothesis, a test name), use the term as defined in `CONTEXT.md`. Don't drift to synonyms the glossary explicitly avoids.

If the concept you need isn't in the glossary yet, that's a signal — either you're inventing language the project doesn't use (reconsider) or there's a real gap (note it for `/grill-with-docs`).

## Flag ADR conflicts

If your output contradicts an existing ADR, surface it explicitly rather than silently overriding:

> _Contradicts ADR-0007 (skills verify but do not commit) — but worth reopening because…_
22 changes: 22 additions & 0 deletions docs/agents/issue-tracker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Issue tracker: GitHub

Issues and PRDs for this repo live as GitHub issues. Use the `gh` CLI for all operations.

## Conventions

- **Create an issue**: `gh issue create --title "..." --body "..."`. Use a heredoc for multi-line bodies.
- **Read an issue**: `gh issue view <number> --comments`, filtering comments by `jq` and also fetching labels.
- **List issues**: `gh issue list --state open --json number,title,body,labels,comments --jq '[.[] | {number, title, body, labels: [.labels[].name], comments: [.comments[].body]}]'` with appropriate `--label` and `--state` filters.
- **Comment on an issue**: `gh issue comment <number> --body "..."`
- **Apply / remove labels**: `gh issue edit <number> --add-label "..."` / `--remove-label "..."`
- **Close**: `gh issue close <number> --comment "..."`

Infer the repo from `git remote -v` — `gh` does this automatically when run inside a clone. This repo has an `origin` remote (`thoughtbot/belt`) and a `church001` fork remote; issues live on `origin`.

## When a skill says "publish to the issue tracker"

Create a GitHub issue.

## When a skill says "fetch the relevant ticket"

Run `gh issue view <number> --comments`.
15 changes: 15 additions & 0 deletions docs/agents/triage-labels.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Triage Labels

The skills speak in terms of five canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker.

| Label in mattpocock/skills | Label in our tracker | Meaning |
| --------------------------- | --------------------- | ----------------------------------------- |
| `needs-triage` | `needs-triage` | Maintainer needs to evaluate this issue |
| `needs-info` | `needs-info` | Waiting on reporter for more information |
| `ready-for-agent` | `ready-for-agent` | Fully specified, ready for an AFK agent |
| `ready-for-human` | `ready-for-human` | Requires human implementation |
| `wontfix` | `wontfix` | Will not be actioned |

When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table.

Edit the right-hand column to match whatever vocabulary you actually use.
Loading
Loading