Skip to content

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
  • repoType is single or mono. A single repository has exactly one artifact; repo update refuses more.
  • An artifact's name is a slug. In a mono repository, it is also the artifact's directory.
  • modules is optional; without it, every module the artifact's profile offers is generated, except those marked "off" by default below.
  • documentation and requirements are optional; capability 010 describes them.
  • meta is 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 that repo update refreshes and links to that.
  • Rules are extracted from the guidelines' ## Directives sections 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 *.cpp and *.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.yaml reference 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

  1. 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.0 only.
  2. functional_design/ and technical_design/ stay. Capability Specifications state requirements; design documents that serve several capabilities need a place beside them. Existing repositories keep their paths.
  3. One configuration file with an explicit repository type. Single and mono-repositories share one structure; repoType decides, so a mono-repository may start with one artifact. A single repository carries a one-element list.
  4. The developer edits .repo.yaml; the generator does not guard it. The content fingerprint and the immutable content: block go away. repo add only saves typing an entry. A wrong edit shows up in git diff after repo update.
  5. No command-line options. Everything that shapes the result is in .repo.yaml and thus versioned; --dry-run becomes repo check.
  6. 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.
  7. Guidelines are not versioned per repository. A repository without module guidelines links to newer guidelines than its rules were extracted from, until the next repo update. Module guidelines makes a repository self-contained at the cost of a second copy.
  8. Gherkin lives in test/. Feature files are derived from acceptance criteria and reviewed through them; they no longer appear in the docs site.
  9. 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.
  10. 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.
  11. The generator applies the target picture to itself. Its own specs/ start anew with Capability Specifications; code and templates evolve on branches from main.

Out of Scope

  • Automatic migration of repositories generated with the previous approach; repo update refuses an old-format configuration with a message.
  • New languages or project types.