ckb/wiki/decisions/0002-software-module-design.md
Michał Kopeć 0c06cb64ab Restore point before wiki reset
Commit all in-flight work — ckb-module and ckb-reset skills, the
.agents/modules/ scaffold, OPENSPEC docs, decision records D-0001 and
D-0002, graph edges and workload summaries — so the reset that follows
is fully recoverable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 17:56:41 +02:00

5.7 KiB

type tldr status decided_on decided_by affects confidence quality last_updated freshness_window_days retention
decision The `software` module keeps code as gitignored plain clones in `src/`, runs OpenSpec at both KB-root and per-repo level with a hybrid vendor/depend split, and links the two spec levels with `implements`/`implemented_by`. accepted 2026-09-20 Michał Kopeć /wiki/decisions/0001-opt-in-file-based-kb-modules.md, /wiki/index.md 0.85 0.8 2026-09-20 365 high

D-0002 — Design of the opt-in software module

Status: Accepted · Decided: 2026-09-20 · Deciders: Michał Kopeć

Context

Some knowledge bases document software the user is actively building. In that case the source code lives in src/, usually as one or more independent git repositories with their own remotes — a git repo inside a git repo. The user also wants OpenSpec-driven iterative development available in that mode.

This is the first concrete module under D-0001 / D-0001, and four sub-questions had to be settled: how code is hosted, where specs live, whether OpenSpec's own workflow instructions are vendored or depended on, and how two spec levels avoid becoming two sources of truth.

Decision

Code hosting. src/<repo>/ holds plain clones, gitignored (src/*, as libs/* already is). No submodules. Because the code may be absent from a fresh clone, each repo also gets a durable type: repository entity page in wiki/ recording its remote URL, default branch, language, build command, src/ path, and owner — that page, not the clone, is the durable artifact.

src/ is not a cascade layer. It is primary evidence, like raw/archive/: ckb-retrieve may open and cite it when verifying a claim, but it never answers "what is entity X", and ckb-ingest does not treat code as inbox material.

Spec location — both levels. OpenSpec runs at the KB root (cross-cutting capabilities spanning multiple src/ repos) and inside each src/<repo>/ (implementation specs that travel with the code in its own repo).

Vendoring — hybrid. The KB-root spec layer is served by a module-owned skill, because a KB-root openspec/ is not a normal OpenSpec repo install (no code beneath it, no single repo it governs) and the module must own instructions for it regardless. The per-src-repo layer delegates to OpenSpec's own native install and instructions, and the module reports plainly when OpenSpec is missing rather than substituting its own workflow. The module additionally owns the bridge in both directions: an archived OpenSpec change becomes a wiki/decisions/NNNN-*.md record, and current specs sync into type: spec entity pages.

Drift rule. KB-level specs state what and why across repos; src-level specs state how a given repo implements it. The two are linked by implements: / implemented_by: frontmatter, which becomes graph edges. ckb-lint gains checks for KB-level specs with no implementer and src-level specs whose parent was archived or superseded.

Rationale

Gitignored clones avoid embedded-repo warnings and keep code out of KB history, while each repo keeps pushing to its own origin; submodules would pin commits that go stale against daily work in src/. Specs at both levels reflect a real distinction — cross-repo contracts genuinely differ from per-repo implementation — and the hybrid vendoring split follows from that same distinction rather than splitting the difference: only the level OpenSpec doesn't natively serve is owned locally. The implements/implemented_by link exists specifically so the two-level arrangement produces a lint signal when the levels disagree, instead of two silently divergent truths.

Consequences

  • .gitignore gains src/* rules.
  • New frontmatter types repository, component, spec, and optional repo:, commit:, spec_id:, implements:, implemented_by: fields — a kb_schema_version bump to 1.5, additive only.
  • Module skills needed: a code-mapping skill (src/<repo> → entity pages, with a recorded commit hash so staleness is detectable) and a KB-root OpenSpec + bridge skill.
  • ckb-sync-changes must never git add under src/, and should report each src/ repo's dirty/ahead state separately.
  • ckb-retrieve gains code as a verification source; ckb-lint gains the src and spec-drift checks; OKF and Starlight exports exclude src/.
  • The module is unusable at the src/ level until OpenSpec is installed separately — it is not on PATH as of this decision.

Alternatives considered

  • Git submodules for src/ — code travels with the KB and is pinned to a commit, which is genuinely attractive for "what did the wiki describe at that point". Rejected for submodule friction on every sync and pins going stale.
  • Specs only inside each src/ repo — OpenSpec's native case, nothing to own locally, but no home for contracts spanning several repos.
  • Specs only at KB root — one place to look, but specs stop travelling with the code they govern and fall out of the repo's own PR flow.
  • Vendoring OpenSpec's workflow wholesale — self-contained, works with nothing installed, tailorable to KB conventions. Rejected: it means maintaining a fork of an external workflow, and ckb-upgrade would have two upstreams to track.
  • Depending on OpenSpec at both levels — nothing to maintain, but leaves the KB-root layer with no instructions at all, since OpenSpec doesn't serve that case.

Sources

Chat conversation, 2026-09-20 — design evaluation of a source-code/software KB mode, including the user's explicit choices on mechanism, code hosting, spec location, and vendoring. See workload/2026-09-20_summary.md.