Custom agent imported from DirectedEdges/specs (
.github/agents/Specs.adr.create.agent.md). Copyright stays with the author.
Territory: schema. Before proceeding, read CLAUDE.md and ARCHITECTURE.md at the repo root if not already loaded this session — the Constitution digest and sync set there govern every ADR.
User Input
$ARGUMENTS
You MUST consider the user input before proceeding (if not empty).
Efficiency mandate
Ask first, explore later. This command MUST be fast and interactive. Do NOT read schema files, type files, or any source code until the user has described their proposed change. The user's description drives all subsequent exploration — never explore speculatively.
Use dedicated tools, not Bash. Use Read (not cat/head), Glob (not find/ls), and Grep (not grep/rg) for all file operations. Reserve Bash exclusively for git commands and running scripts.
Outline
-
Gather intent — collect all information from the user before doing any exploration. This step has two parts:
Step 1a — Detect release branch (silent, no user prompt) Before asking any questions, find the active release branch with
git branch -r --list 'origin/release/*'. InferRELEASE_BRANCH:- If exactly one
origin/release/*branch exists, use it asRELEASE_BRANCH. Do not cross-reference it againstpackage.jsonversion — the branch name reflects where the release started, not the final published version. - If multiple
origin/release/*branches exist, pick the most recently created one (latest commit date) as the default and surface it in Question 2 for confirmation. - If no
origin/release/*branch exists, fall back tomainand note this in Question 2 so the user can confirm or provide a branch.
Step 1b — Sync and determine next ADR number (silent, no user prompt) Run
git fetch originso every remote ref is current, and fast-forward the local release branch if behind (git pull origin $RELEASE_BRANCH).adr/INDEX.mdonmainis the register of claimed numbers — every ADR, drafted or accepted, has a row there, because step 7 cherry-picks the claim ontomainthe moment it is made. Read it and take the highest number, plus one:git show origin/main:adr/INDEX.md | grep -oE '^\| [0-9]{3} ' | grep -oE '[0-9]{3}' | sort -n | tail -1Do not infer claimed numbers from branch names. An ADR branch may be named anything (
adr/primitive-compositionholds ADRs 073–079), so a###-*pattern misses them and hands out a number already in use.Then verify the register is complete before trusting it — a missed cherry-pick is the one failure mode that makes it lie. List the ADR files on every remote branch and compare against the index:
for b in $(git branch -r --format='%(refname:short)' | grep -v '\->'); do git ls-tree --name-only "$b" adr/ 2>/dev/null | grep -oE 'adr/[0-9]{3}' done | grep -oE '[0-9]{3}' | sort -uIf any number there is absent from the index, stop and tell the user which numbers are unregistered and which branch holds them. Offer to add the missing rows (marked
(reserved, draft in PR #N)) and cherry-pick them ontomainper step 7 before continuing. Never claim a number until the register accounts for every number in use.Step 1c — Ask the user using VS Code's interactive question UI. Present ALL questions in a single prompt:
Question 1 — Describe the change
- Header:
Change - Question: "What change are you proposing? Describe the types/schema modification at a high level (e.g., 'Add structured border properties to replace flat per-side fields on Styles')."
- Allow free-form input. No predefined options.
Question 2 — Confirm release branch
- Header:
Release - Question: "Detected release branch:
[RELEASE_BRANCH]. Target this release?" - Options (single-select):
Yes, use [RELEASE_BRANCH]— keep the detected valueDifferent branch— allow free-form input to specify another branch
Question 3 — ADR file name
- Header:
ADR file - Question: "Next ADR number is
[NEXT_ADR_NUMBER]. What should the ADR be named? This becomesadr/[name].mdand the ADR branch[name]. Use the format###-short-description(e.g.[NEXT_ADR_NUMBER]-shadows)." - Allow free-form input. No predefined options.
Parse answers as
CHANGE_DESCRIPTION,RELEASE_BRANCH, andADR_NAME.- Derive
ADR_BRANCHas$ADR_NAME.
- If exactly one
-
Branch setup:
- If not already on
$ADR_BRANCH, check if it exists — switch to it or create it from$RELEASE_BRANCH. The branch must exist before runningcheck-prerequisites.sh(it validates the branch name pattern). - Run
scripts/check-prerequisites.sh --json --paths-onlyfrom the git repo root (the directory containing.git/). ParseREPO_ROOTfrom the JSON output. Do not guessREPO_ROOT— always derive it from the script output. - Verify
$RELEASE_BRANCHis synced with remote (already fetched and fast-forwarded in Step 1b). - Set
SPEC_FILE=$REPO_ROOT/adr/$ADR_NAME.md. Theadr/directory is at the repo root, not inside any package subdirectory. - If
$SPEC_FILEexists, read it and continue editing rather than overwriting. - All paths must be absolute.
- If not already on
-
Load context: Read
packages/schema/CONSTITUTION.mdandadr/adr-template.md(the output template). -
Targeted exploration: Using
CHANGE_DESCRIPTIONas your guide, read only the specific type and schema files relevant to the proposed change. Do not scan directories broadly. If the user said "border properties on Styles", readtypes/Styles.tsandschema/Styles.yaml— not everything intypes/andschema/. Determine:- Which schema files in
schema/are affected - Which types in
types/are affected (added, removed, renamed fields) - Whether the change is MAJOR (breaking), MINOR (additive), or PATCH (non-semantic) per the constitution
- Which schema files in
-
Evaluate options (skip if the decision is already made):
- If the user's description or context indicates the decision is pre-decided (e.g., "record and implement this decision"), omit this step and mark the Options Considered section as (Pre-decided — no alternatives evaluated).
- First, list the independent decisions in scope. Schema shape, authoring surface and semantics, and vocabulary are separate decisions. Each gets its own Options section, titled by the decision it resolves, with its own selected and rejected alternatives. Never bundle two decisions into one option — a "Selected" option carrying both forces an all-or-nothing verdict and hides one of them from evaluation entirely.
- If a decision is out of scope for this ADR, say so explicitly in Context and point to where it is taken. Do not resolve it in passing.
- Within each Options section, identify at least two alternative approaches, assess each against the constitution's Decision Drivers, and state which is selected with rationale.
-
Draft the ADR: Fill
adr-template.mdand write to$SPEC_FILE:- Branch:
ADR_NAME - Status:
DRAFT - Context: Current state of the relevant types/schema and what gap or opportunity this addresses
- Decision Drivers: Enumerate the constraints from the constitution that apply
- Options Considered: At least two options with pros/cons relative to the drivers
- Decision: Precise list of type and schema changes (file, field, modification type)
- Type ↔ Schema Impact: Confirm symmetry or document justified asymmetry
- Downstream Impact: All affected consumers (
specs-cli,specs-from-figma,specs-plugin-2) — see Key rules below - Semver Decision: the target version read from the affected package's
package.jsonon the activerelease/nextbranch — the branch name carries no version, by design — plus the change class (MAJOR / MINOR / PATCH) with justification citing the constitution. Never propose a version bump — an ADR ships inside a release that already has a version, so0.30.0 → 0.31.0invents a version the release process never asked for and conflicts with the branch it merges into. - Consequences: What becomes true after acceptance
- Branch:
-
Claim ADR number in INDEX (mandatory — the index is the register step 1b reads, and skipping this hands the next author a number already in use): Update
adr/INDEX.mdto reserve the ADR number and prevent collisions.- On the current ADR branch, add a row to the Draft table (descending by number) with the ADR number and title but no highlight (leave the Highlights cell empty).
- Commit this INDEX update on the ADR branch.
- Then cherry-pick the INDEX change onto
main(and$RELEASE_BRANCHif it differs frommain):git stashany uncommitted work (if needed).git checkout main && git cherry-pick <commit> && git push origin main- If
$RELEASE_BRANCH≠main:git checkout $RELEASE_BRANCH && git cherry-pick <commit> && git push origin $RELEASE_BRANCH git checkout $ADR_BRANCHto return to the working branch.
- This ensures other ADR authors see the claimed number immediately.
-
Report: Output
$SPEC_FILEpath, the$ADR_BRANCHname, the target$RELEASE_BRANCH, and a one-paragraph summary of the decision.
Formatting rules (apply when drafting the ADR)
- Examples over prose: Wherever a type shape, schema property, or field change is described, include a YAML example showing the before/after or the new structure. Prefer this over sentences explaining the same idea in abstract terms.
- Bullets over enumeration: Use bullet lists for Decision Drivers, Consequences, and any list of more than two items. Do not write "X, Y, and Z" as a sentence when a list would be clearer.
- Backticks for terms: All type names, field names, file names, and schema property paths MUST be in backtick format (e.g.,
Config,license,types/Config.ts,#/properties/license). - Types and schema only: The ADR MUST describe only changes to
types/andschema/within this package. Do NOT reference implementation classes, internal files, or processing logic from downstream packages (specs-from-figma,specs-plugin-2,specs-cli). Downstream impact is described in terms of the observable API surface — what types or schema keys change — not how those packages implement consumption.
Key rules
- Status MUST be
DRAFT— never set toACCEPTEDin this command. - The Semver section states the release branch's version and the change class. It MUST NOT contain a bump arrow.
- One decision per Options section. The Decision section only records what the option sets above already resolved — if a choice appears there for the first time, it needs its own Options section.
- The ADR describes what will change and why. It does not contain type or schema file content — those changes are applied directly by
/specs.adr.implement. - Downstream Impact table: Include rows for all consumers affected by the change:
specs-cli,specs-from-figma, andspecs-plugin-2. Describe impact and required action in general terms (e.g., "Update value mapping", "Recompile") — do not reference internal classes, methods, or implementation details of those packages. - If the change clearly violates a constitution gate (e.g., adds runtime logic), state the violation explicitly in the ADR and halt rather than proceeding without justification.
- Use absolute paths for all file operations.
