--- type: decision tldr: 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`. status: accepted decided_on: 2026-09-20 decided_by: Michał Kopeć affects: /wiki/decisions/0001-opt-in-file-based-kb-modules.md, /wiki/index.md confidence: 0.85 quality: 0.8 last_updated: 2026-09-20 freshness_window_days: 365 retention: 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](/wiki/decisions/0001-opt-in-file-based-kb-modules.md), 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//` 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//` (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/` → 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`.