Target Picture¶
Status: Accepted
Context¶
repo scaffolds repositories for spec-driven development with AI coding assistants. The generated
repositories organize specs by document type: requirements, business rules, domain model, use
cases, feature files, ADRs, guidelines. Every feature therefore spreads over five to eight files,
and each sentence has to be classified first. That classification costs the developer time and is
where assistants make mistakes. Rules and guidelines grow with every correction and are loaded
into every session, which makes each single rule less reliable.
A lean alternative was tried on real repositories: one Capability Specification per capability,
from which the assistant derives only what is machine-readable or shared. This document describes
the generator that supports that approach. The previous approach stays available under the Git tag
v1.5.0.
Development Workflow¶
Workflow describes the development steps, the kinds of documents, and the documentation modes.
Capability Specification¶
Sections, in this order; every section is present, and one without content says None.:
| Section | Content |
|---|---|
| Status | Draft or Accepted |
| Context | Why the capability exists; links to the mission statement |
| References | Interfaces and documents the capability relies on |
| Details (project specific) | Content that fits the capability better than prose, e.g. tables that relate input to output |
| Functional Requirements | Numbered |
| Non-Functional Requirements | Numbered, each measurable |
| Technical Requirements | Numbered; constraints on the solution space, e.g. target hardware or interrupt context |
| Error Handling | Numbered |
| Out of Scope | What the capability deliberately does not do |
| Acceptance Criteria | Numbered; with test vectors where values matter; each verified automatically unless it refers to a manual test |
| Decisions | Numbered; each with its consequence |
Guidance that the template carries:
- Phrase a negative acceptance criterion by the capability's own output ("no Motor Status"), not by everything ("no CAN message"); otherwise a later capability refutes it.
- An acceptance criterion that no automated test can check refers to the manual test in
test/manual/that verifies it. For electronics projects, this is the rule rather than the exception. - Refer to an earlier capability instead of repeating it ("as for capability 003").
- Links point to earlier capabilities only.
Manual Test¶
A manual test describes how to verify acceptance criteria that no automated test can check. One
file per test setup in test/manual/, because the setup is the expensive part and usually serves
several capabilities. Sections, in this order:
| Section | Content |
|---|---|
| Scope | Capabilities and acceptance criteria verified |
| Safety | Hazards and protective measures, e.g. battery, motors, mains voltage |
| Equipment | Instruments, tools, firmware versions |
| Setup | Assembly and wiring, preferably with a sketch or photo |
| Preconditions | Initial state, flashing |
| Procedure | Table: step, action, expected result with tolerance, acceptance criterion |
Test records (date, tester, hardware revision, result) do not belong in the file; they are attached to a release or merge request.
Generated Repository¶
Single Repository¶
.repo.yaml
CLAUDE.md, .claude/ # module ai
Makefile, devbox.json, … # module scaffold
.gitlab-ci.yml | .github/ # module ci
mkdocs.yml # module specs
guidelines/ # module guidelines
specs/ # module specs
index.md
mission_statement.md
inputs/ # README only
capabilities/
functional_design/
glossary.md
domain_model.md # module domain-model
technical_design/
system_context.md
ADRs/ # README with the template only
APIs/provided/, APIs/consumed/
src/, test/ # module scaffold
test/bdd/features/ # module bdd
test/manual/ # module manual-test
docs/ # module specs; README only
The developer adds own design documents to functional_design/ and technical_design/.
Mono-Repository¶
The root holds .repo.yaml, the composed CI pipeline, the combined docs site, the root
CLAUDE.md, guidelines/, specs/mission_statement.md, cross-artifact ADRs, and interfaces shared
by several artifacts, such as a DBC file. Each artifact directory holds the single-repository
layout without .repo.yaml, guidelines/, mission_statement.md, and CI pipeline. An artifact
refers to a shared interface by specs/technical_design/APIs/provided/*.path.txt or
specs/technical_design/APIs/consumed/*.path.txt.
Not Generated¶
specs/requirements/- Derived Documents; with
documentation: extended, only their templates (capability 010) - ADRs that justify the generator's own choices
Configuration¶
One .repo.yaml at the repository root controls generation, for single and mono-repositories
alike. The developer owns and edits it; repo update applies it.
name: Example Robot
description: Three-wheeled omni-drive robot.
repository: gitlab.com/<group>/<project>
repoType: mono
ci: gitlab
assistants: [claude]
artifacts:
- name: motor-controller-bridge
title: Motor Controller Bridge
description: Relays drive messages between CAN and the motor controller boards.
language: cpp
type: firmware-stm32
modules: [scaffold, ci, specs, bdd, ai, can]
meta:
generatorVersion: 2.0.0
repoTypeissingleormono. Asinglerepository has exactly one artifact;repo updaterefuses more.- An artifact's
nameis a slug. In amonorepository, it is also the artifact's directory. modulesis optional; without it, every module the artifact's profile offers is generated, except those marked "off" by default below.documentationandrequirementsare optional; capability 010 describes them.metais written by the generator only.
Modules¶
Standard modules:
| Module | Generates | Default |
|---|---|---|
scaffold |
Directory tree, build files, Makefile, Devbox, lint configuration |
on |
ci |
CI job of the artifact | on |
specs |
specs/ tree, Capability Specification template, docs site |
on |
domain-model |
specs/functional_design/domain_model.md |
on for services, off otherwise |
bdd |
BDD harness and test/bdd/ |
on where automated tests exist, i.e. not for electronics |
manual-test |
test/manual/ with the manual test template |
on for firmware and electronics, off otherwise |
ai |
CLAUDE.md, .claude/ rules, skills, hooks; Copilot files per assistants |
on |
guidelines |
All guidelines in guidelines/ at the repository root, included in the docs site |
off |
Interface modules each add one interface description format with its lint tool and, optionally, a
code generator. Examples: can (DBC files, cantools 41.3.1, make dbc-check, CAN rules),
openapi, asyncapi, grpc. An interface module is on only if selected.
A module that needs another one fails generation with a message naming the missing module; the
generator never adds it on its own. Repository-level files exist as soon as one artifact selects
the module that needs them: the root pipeline with ci, the combined docs site with specs,
the root CLAUDE.md with ai, guidelines/ with guidelines.
Commands¶
| Command | Effect |
|---|---|
repo init |
Writes a commented .repo.yaml template with repoType: single |
repo init-mono |
Writes a commented .repo.yaml template with repoType: mono and two example artifacts |
repo add |
Appends a commented, empty artifact entry to a mono .repo.yaml; generates nothing |
repo update |
Generates or refreshes all generator-owned files from .repo.yaml |
repo check |
Exits non-zero if repo update would change a file; for CI drift detection |
repo version |
Prints the generator version |
Commands take no options and work on the current directory. repo init and repo init-mono
refuse to overwrite an existing .repo.yaml; repo add refuses a single repository.
repo update requires a clean working tree apart from .repo.yaml, writes developer-owned
files only when their module is new, and never deletes a file: when a module or artifact is
removed from .repo.yaml, it lists the files it no longer generates. For a new artifact, it
prints the Next Steps: the manual steps without which a make target or the pipeline fails.
Rules, Guidelines, and Tools¶
- Guidelines live in the generator's docs site, for all languages and project types at once.
The site shows the latest release; the latest guidelines apply. A generated repository links to
them, or, with module
guidelines, carries a copy thatrepo updaterefreshes and links to that. - Rules are extracted from the guidelines'
## Directivessections into.claude/rules/and the Copilot instructions: - one core rule file, always loaded
- path-scoped rules (
paths:front matter) that load only for matching files, e.g. C++ rules for*.cppand*.hpp - a word budget per rule file, checked by the generator's CI
- Tools enforce whatever is checkable, instead of a rule: clang-tidy, golangci-lint, shellcheck for every shell script, markdownlint, and the lint tools of the interface modules.
- ADRs of a generated repository start empty. The rationale for the generated structure and pipelines is documented once per profile in the generator's docs site.
Generator Docs Site¶
- Usage:
.repo.yamlreference and commands - Workflow: the development workflow, with diagrams, e.g. PlantUML, Mermaid, or draw.io
- Capability Specification template with guidance
- Design per profile (language × project type): structure, build, pipeline, and their rationale
- Assistant support: what Claude Code and GitHub Copilot each receive, and Copilot's limits
- Guidelines
Decisions¶
- The capability approach replaces the document-type structure; there is no option to keep
it. Two structures side by side would double the templates. The old one is reachable by the
tag
v1.5.0only. functional_design/andtechnical_design/stay. Capability Specifications state requirements; design documents that serve several capabilities need a place beside them. Existing repositories keep their paths.- One configuration file with an explicit repository type. Single and mono-repositories share
one structure;
repoTypedecides, so a mono-repository may start with one artifact. A single repository carries a one-element list. - The developer edits
.repo.yaml; the generator does not guard it. The content fingerprint and the immutablecontent:block go away.repo addonly saves typing an entry. A wrong edit shows up ingit diffafterrepo update. - No command-line options. Everything that shapes the result is in
.repo.yamland thus versioned;--dry-runbecomesrepo check. - Modules are coarse. Every combination has to be tested; a handful of modules keeps that feasible. Finer selection is not possible. Interface modules are added only when a project needs them.
- Guidelines are not versioned per repository. A repository without module
guidelineslinks to newer guidelines than its rules were extracted from, until the nextrepo update. Moduleguidelinesmakes a repository self-contained at the cost of a second copy. - Gherkin lives in
test/. Feature files are derived from acceptance criteria and reviewed through them; they no longer appear in the docs site. - Manual tests are free text by template, not Gherkin. Without automation, Gherkin keeps only its form, which fits instruments, tolerances, and safety notes poorly. The template keeps the quality of manual tests comparable; the acceptance criterion column keeps them traceable.
- Modules group the generator's fine-grained units of generation. The developer selects modules only; the units, such as one guideline or one CI workflow, stay internal. They no longer carry the name "capability", which belongs to Capability Specification.
- The generator applies the target picture to itself. Its own
specs/start anew with Capability Specifications; code and templates evolve on branches frommain.
Out of Scope¶
- Automatic migration of repositories generated with the previous approach;
repo updaterefuses an old-format configuration with a message. - New languages or project types.