Skip to content

Business Rules

BR-001: Non-Empty Project Name

Category: Policy

Statement: A project name must not be blank.

Rationale: The name is used in generated READMEs, CI/CD files, and MkDocs configuration; a blank name produces broken output.

Applies to: GenerationRequest

Violated when: --name is absent or contains only whitespace.

Error code: EMPTY_PROJECT_NAME — "project name must not be empty"

Valid Invalid
My Project ""
repo " "

BR-002: Non-Empty Project Description

Category: Policy

Statement: A project description must not be blank.

Rationale: The description appears in generated READMEs and MkDocs site metadata; a blank value produces incomplete documentation.

Applies to: GenerationRequest

Violated when: --description is absent or contains only whitespace.

Error code: EMPTY_PROJECT_DESCRIPTION — "project description must not be empty"

Valid Invalid
"Scaffolds new projects." ""

BR-003: Non-Empty Target Path

Category: Policy

Statement: The target path must not be blank.

Rationale: The generator writes all output into the target path; without it no file can be created.

Applies to: GenerationRequest

Violated when: --targetpath is absent or contains only whitespace.

Error code: EMPTY_TARGET_PATH — "target path must not be empty"

Valid Invalid
/home/user/repo ""
./my-repo " "

BR-004: Valid Language

Category: Policy

Statement: The target language must be one of cpp, go, java, or typescript.

Rationale: The generator only has template sets for these four languages.

Applies to: GenerationRequest

Violated when: --language is any value not in {cpp, go, java, typescript}.

Error code: INVALID_LANGUAGE — "invalid language: must be one of cpp, go, java, typescript"

Valid Invalid
go python
cpp rust
java ""
typescript

BR-005: Valid Project Type

Category: Policy

Statement: The project type must be one of embedded, library, service, tool, or frontend-react. embedded is reserved for a planned future C++ project type (e.g. STM32 targets) and has no template set yet — see BR-006/BR-007 for currently supported combinations. frontend-react is TypeScript-only.

Rationale: The generator has template sets for library, service, tool, and frontend-react; embedded is documented ahead of implementation.

Applies to: GenerationRequest

Violated when: --projecttype is any value not in {embedded, library, service, tool, frontend-react}.

Error code: INVALID_PROJECT_TYPE — "invalid type: must be one of embedded, library, service, tool, frontend-react"

Valid Invalid
service plugin
library framework
frontend-react

BR-006: Go Does Not Support Embedded Projects

Category: Invariant

Statement: The combination of language go and project type embedded is forbidden.

Rationale: Embedded and systems-level development in this domain targets C++ toolchains (AVR, ARM, etc.); Go has no applicable template set for this context.

Applies to: ProjectDescriptor

Violated when: Language is go AND ProjectType is embedded.

Error code: UNSUPPORTED_COMBINATION — "Go does not support embedded projects"

Valid Invalid
go + service go + embedded
cpp + embedded

BR-007: Java Supports Only Library and Service Projects

Category: Invariant

Statement: The language java is restricted to project types library and service.

Rationale: CLI tool and embedded templates do not exist for Java in this generator; generating them would produce incomplete scaffolding.

Applies to: ProjectDescriptor

Violated when: Language is java AND ProjectType is embedded or tool.

Error code: UNSUPPORTED_COMBINATION — "Java supports only library and service projects"

Valid Invalid
java + library java + tool
java + service java + embedded

BR-008: CI Type Is Inferred from Git Remote When Not Specified

Category: Policy

Statement: When --ci is not provided, the CI type is derived from the Git remote URL of the current repository.

Rationale: Avoids manual input for the common case where the remote URL unambiguously identifies the CI platform.

Applies to: GenerationRequest

Violated when: --ci is absent AND the Git remote is unreachable, missing, or does not contain github.com or gitlab.com.

Error code: CI_TYPE_UNRESOLVABLE — "could not determine CI type: pass --ci github or --ci gitlab explicitly"

Valid Invalid
Remote URL contains github.com No Git remote configured
Remote URL contains gitlab.com Remote URL from unknown host
--ci github passed explicitly

BR-009: Artifact Name Is Inferred from Git Remote When Not Specified

Category: Policy

Statement: When --artifactname is not provided, it is derived as the last path segment of the normalised Git remote URL.

Rationale: The remote repository slug is the natural artifact name, avoiding redundant manual input.

Applies to: GenerationRequest

Violated when: --artifactname is absent AND the Git remote is unreachable or unparseable.

Error code: ARTIFACT_NAME_UNRESOLVABLE — "could not determine technical artifact name: pass --artifactname explicitly"

Valid Invalid
Remote gitlab.com/user/my-toolmy-tool No Git remote configured
--artifactname my-tool passed explicitly

BR-010: Go Module Path Is Inferred from Git Remote When Not Specified

Category: Policy

Statement: When --modulepath is not provided, it is derived as the normalised host/org/repo path of the Git remote URL.

Rationale: The remote URL is the canonical Go module path for hosted repositories, avoiding redundant manual input.

Applies to: GenerationRequest

Violated when: --modulepath is absent AND the Git remote is unreachable or unparseable.

Error code: MODULE_PATH_UNRESOLVABLE — "could not determine Go module path: pass --modulepath explicitly"

Valid Invalid
Remote git@gitlab.com:user/proj.git -> gitlab.com/user/proj No Git remote configured
--modulepath gitlab.com/user/proj passed explicitly

BR-011: Universal Guidelines Are Always Generated

Category: Invariant

Statement: Every generated project must include the full set of universal guidelines regardless of language or project type.

Rationale: These guidelines encode the non-negotiable quality baseline for all projects produced by this generator.

Applies to: GeneratedProject

Violated when: Any of bash_coding, ci_cd, data_modeling, error_handling, general_coding, library_design, refactoring, security, or testing is absent from the output.

Error code: MISSING_UNIVERSAL_GUIDELINE — "universal guideline missing from output"

Valid Invalid
All 9 guidelines present in specs/guidelines/ Any guideline missing from output

BR-012: C++ Artifact Names Are Sanitised to Valid Identifiers

Category: Invariant

Statement: Hyphens in the artifact name are replaced with underscores when used as a C++ namespace or include-directory name.

Rationale: Hyphens are not valid in C++ identifiers; using them verbatim would produce uncompilable code.

Applies to: ProjectDescriptor (C++ projects only)

Violated when: A C++ namespace or include path contains a hyphen character.

Error code: INVALID_CPP_NAMESPACE — "C++ namespace must not contain hyphens"

Valid Invalid
artifact my-lib → namespace my_lib namespace my-lib
artifact mylib → namespace mylib

BR-013: Coverage Reports

Category: Invariant

Statement: All coverage reports, independent of programming language or artifact type, are stored in test_reports/coverage/. Coverage reports are in Cobertura format.

Rationale: Always clear where to find reports. Prominent format used by many tools. Folder can be provided for Download as a CI build artifact.

Applies to: All generated projects.

Violated when: never

Error code: not applicable


BR-015: Service Guidelines Are Generated for Service Projects

Category: Invariant

Statement: Every generated service project must include the full set of service-specific guidelines in addition to the universal guidelines.

Rationale: These guidelines encode quality standards that are specific to services — API contracts, process design, logging, monitoring, and cloud-native design — and are not applicable to libraries or CLI tools.

Applies to: GeneratedProject (project type service)

Violated when: Any of api_design, business_process_design, logging, monitoring, or service_design is absent from the output of a service project.

Error code: MISSING_SERVICE_GUIDELINE — "service guideline missing from output"

Valid Invalid
All 5 service guidelines present in specs/guidelines/ Any guideline missing from service output

BR-014: Unit Test Reports

Category: Invariant

Statement: All unit test reports, independent of programming language or artifact type, are stored in test_reports/test/. Reports are in JUnit XML format.

Rationale: Always clear where to find reports. Prominent format used by many tools. Folder can be provided for Download as a CI build artifact.

Applies to: All generated projects.

Violated when: never

Error code: not applicable


BR-016: No-Scaffolding Skips CI, Build Tooling, and Prescriptive ADRs

Category: Invariant

Statement: When --no-scaffolding is set, the generated project must include the full set of guidelines and AI-assistant support, but must not include any CI workflow file, build-tool file (Makefile, language build configuration), language scaffold tree, or prescriptive ADR — a single worked ADR example is generated instead.

Rationale: Lets a developer adopt this generator's guidelines and Claude Code integration while choosing their own CI system and build tool, without receiving files that presume a specific choice.

Applies to: GeneratedProject (when --no-scaffolding/-s is set)

Violated when: Any CI workflow file, Makefile, language scaffold file, or a prescriptive ADR is present in the output, or any guideline or the sample ADR is missing.

Error code: not applicable

Valid Invalid
--no-scaffolding output has guidelines + .claude/ + ADR-001-example-decision.md, no Makefile/.gitlab-ci.yml --no-scaffolding output still contains Makefile or .gitlab-ci.yml

BR-017: Container Registry Is Inferred from Module Path and CI Type When Not Specified

Category: Policy

Statement: When --containerregistry is not provided, it is derived from the Go module path's host/org segment and the CI type: ghcr.io/<org> for GitHub, registry.gitlab.com/<org> for GitLab.

Rationale: The module path's org segment is each platform's natural built-in registry namespace. This avoids redundant manual input for the common case.

Applies to: GenerationRequest

Violated when: never. Unlike BR-008/BR-009/BR-010, an unresolvable module path does not fail generation. It falls back to the placeholder registry.example.com/TODO for the developer to replace later.

Error code: not applicable

Input Resulting registry
Module path gitlab.com/hzahnlei/my-project, --ci gitlab registry.gitlab.com/hzahnlei
Module path github.com/myorg/my-project, --ci github ghcr.io/myorg
--containerregistry registry.example.com/team passed explicitly registry.example.com/team
No module path resolvable and no --containerregistry passed registry.example.com/TODO

BR-018: Mono-Repo Manifest Must Contain At Least One Repo Entry

Category: Invariant

Statement: A .mono-repo.yaml manifest's repos: list must contain at least one entry.

Rationale: A mono-repo manifest with zero entries would generate nothing, which is never a valid outcome for repo init.

Applies to: MonoRepoConfig

Violated when: repos: is absent, null, or an empty list.

Error code: EMPTY_MONO_REPO_MANIFEST — "mono-repo manifest must contain at least one repo entry"

Valid Invalid
repos: with 1+ entries repos: []
repos: key absent

BR-019: Each Repo Entry Is Validated Like a Single-Repo Spec

Category: Policy

Statement: Every entry in a .mono-repo.yaml manifest's repos: list is validated with the exact same rules as a standalone .repo.yaml: non-empty name (BR-001), non-empty description (BR-002), valid language (BR-004), valid project type (BR-005), and valid language/project-type combination (BR-006, BR-007).

Rationale: A manifest entry is structurally a RepoConfig (plus authors); reusing the same validation avoids a second, divergent set of rules for what is otherwise the same data shape.

Applies to: Each item of MonoRepoConfig.Repos

Violated when: Any entry fails a rule it would fail as a standalone .repo.yaml (BR-001, BR-002, BR-004, BR-005, BR-006, or BR-007).

Error code: same error code as the violated single-repo rule, prefixed with the entry's index or artifact name so the offending entry is identifiable

Valid Invalid
Entry with language: java, type: service, non-empty name/description.brief Entry with language: go, type: embedded (BR-006)
Entry with blank name (BR-001)

BR-020: Artifact Names Must Be Unique Within a Mono-Repo Manifest

Category: Invariant

Statement: The artifact.name of every entry in a .mono-repo.yaml manifest's repos: list must be unique within that manifest.

Rationale: Each entry's artifact.name becomes its target subdirectory name directly under the mono-repo root; a duplicate would cause two entries to generate into the same directory.

Applies to: MonoRepoConfig

Violated when: Two or more entries share the same artifact.name.

Error code: DUPLICATE_ARTIFACT_NAME — "duplicate artifact name in mono-repo manifest"

Valid Invalid
flight-booking, trip-booking-frontend flight-booking, flight-booking

BR-021: Mono-Repo Generation Refuses Existing Target Subdirectories

Category: Invariant

Statement: For each entry in a .mono-repo.yaml manifest, generation refuses to run if <targetpath>/<artifact.name> already exists.

Rationale: Mirrors the existing single-repo guard (GEN-S03 in cmd/init.go) that refuses to overwrite an already-populated directory; applied per entry since each entry generates into its own sibling subdirectory.

Applies to: Each item of MonoRepoConfig.Repos

Violated when: The subdirectory named after an entry's artifact.name already exists under --targetpath.

Error code: TARGET_SUBDIRECTORY_EXISTS — "target subdirectory already exists: remove it or run repo update there instead"

Valid Invalid
<targetpath>/flight-booking does not yet exist <targetpath>/flight-booking already exists

BR-022: Mono-Repo Children Use Artifact-Scoped CI Namespacing

Category: Invariant

Statement: For each entry in a .mono-repo.yaml manifest, the generated CI configuration uses an artifact-scoped namespace instead of the bare form a standalone repo would use: the registry image path gains a /<artifact.name> segment, and the release Git tag pattern becomes <artifact.name>-vX.Y.Z. The changelog file itself stays a plain CHANGELOG.md — the artifact's own subdirectory already disambiguates it — but every changelog CI job command (git cliff -o, git add, commit, artifacts: paths:) is scoped with a <artifact.name>/ working-directory prefix, the same pattern used for every other job, and git cliff itself is additionally scoped via --include-path <artifact.name>/**. A standalone (non-mono) repo keeps today's unprefixed forms ($CI_REGISTRY_IMAGE/ghcr.io/<repo>, vX.Y.Z) unchanged; it always had a plain CHANGELOG.md at its own root, mono-repo or not.

Rationale: Without artifact-scoped namespacing, every entry in a mono-repo would compute the identical registry push target and match the identical release tag pattern, silently colliding. The registry/tag namespacing mirrors the convention already proven in the build-images repository (<image>-vX.Y.Z tags); the changelog, by contrast, does not mirror build-images' CHANGELOG-<image>.md naming — build-images is a flat, non-mono-repo layout where that suffix disambiguates, whereas each mono-repo artifact here already has its own subdirectory, making a suffix redundant (see ADR-014).

Applies to: Each item of MonoRepoConfig.Repos, at CI-file generation time

Violated when: Two or more entries' generated CI configuration resolve to the same registry image path or the same release tag pattern.

Error code: not applicable (prevented by construction — the namespace is always derived from each entry's own artifact.name, which BR-020 already guarantees is unique within the manifest)

Valid Invalid
flight-booking-v1.0.0 and trip-booking-frontend-v1.0.0 as separate tag patterns Both entries matching a shared bare v1.0.0 tag

BR-023: Mono-Repo Root CI Only Runs an Entry's Pipeline When Its Subdirectory Changed

Category: Policy

Statement: The mono-repo root's generated CI configuration triggers a given entry's pipeline only when that entry's own subdirectory changed (GitLab: rules: changes: ['<artifact.name>/**'] gating a child-pipeline trigger job; GitHub: paths: ['<artifact.name>/**'] on that entry's own workflow's push/pull_request triggers). An entry's release/tag trigger is scoped by its artifact-prefixed tag pattern (BR-022) instead, not by path, since the release tier never rebuilds anything (see ADR-006).

Rationale: Avoids running every artifact's full CI pipeline on every push when only one artifact actually changed — mirrors the per-image rules: changes: gating already used in the build-images repository.

Applies to: Each item of MonoRepoConfig.Repos, at CI-file generation time

Violated when: An entry's Pre-Check/Build/Test tier pipeline runs on a push or merge request that touched no file under that entry's own subdirectory.

Error code: not applicable

Valid Invalid
Only flight-booking/** changed → only flight-booking's pipeline runs flight-booking's pipeline runs on a push that only touched trip-booking-frontend/**

BR-024: Mono-Repo Generation Scaffolds Root-Level System-Wide Specs

Category: Invariant

Statement: Generating from a .mono-repo.yaml manifest additionally writes a root-level specs/architecture/ADRs/README.md, specs/domain/business_rules.md, and specs/index.md for content that spans more than one artifact — alongside, not instead of, each entry's own full specs/ tree in its own subdirectory.

Rationale: Cross-artifact architecture decisions and invariants (e.g. which technology orchestrates a saga across services) don't belong to any single artifact's own specs/; without a fixed home they end up undocumented or duplicated into one artifact's specs by habit. See ADR-013.

Applies to: MonoRepoConfig, at generation time

Violated when: A mono-repo is generated without a root-level specs/architecture/ADRs/, specs/domain/business_rules.md, or specs/index.md.

Error code: not applicable

Valid Invalid
Root specs/architecture/ADRs/README.md and specs/domain/business_rules.md present after repo init from a manifest Root specs/ absent or only present under an entry's own subdirectory

BR-025: Java Mono-Repo Entries Must Specify a Module Path

Category: Invariant

Statement: A .mono-repo.yaml entry with language: java must specify a non-empty artifact.module.

Rationale: The Java package name is derived from artifact.module (see deriveJavaPackage in presentation_model.go). Go's toolchain refuses to build without a real go.mod module path, so an empty value is caught immediately and obviously — but Java compiles fine with none at all, silently falling back to the placeholder package com.example.app. Left unnoticed, a whole service ships under a placeholder namespace instead of a real one. Catching this at generation time, with a clear error naming the offending entry, is cheaper than discovering it after implementation and having to rename the package, every import, and the Maven groupId retroactively.

Applies to: Each item of MonoRepoConfig.Repos where language is java

Violated when: entry.language is java (case-insensitive) and entry.artifact.module is empty or blank.

Error code: not applicable — a formatted error naming the entry's artifact.name and suggesting a reverse-DNS-style module path

Valid Invalid
language: java, artifact.module: example.org/myteam/my-service language: java, artifact.module absent or blank
language: go, artifact.module absent (Go's own toolchain enforces this separately)