Record the monorepo decision in the spec

Part H's repository-layout item is resolved: one repo, three packages.
Naming (S0), scope (S0.1), the step-10 extraction, and the repository
layout section are updated to match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
dongarandClaude Fable 5 committed 2026-09-04 22:13:45 +00:00
1 parent 94aa51135f
commit 69375c0da1
1 file changed
+25 -21
+25 -21
View File
@@ -26,15 +26,17 @@ overnight and expects to be treated well in return. Three artifacts:
| Sysadmin Agent | `nisse-ops` | Operates infrastructure (Part C) | | Sysadmin Agent | `nisse-ops` | Operates infrastructure (Part C) |
Throughout this document, **Dev Agent** and **Sysadmin Agent** name the *roles* in Throughout this document, **Dev Agent** and **Sysadmin Agent** name the *roles* in
conceptual discussion; `nisse-dev` and `nisse-ops` name the *artifacts* — repos, conceptual discussion; `nisse-dev` and `nisse-ops` name the *artifacts* — packages,
container images, VM hostnames, Matrix identities, and service accounts. Use the container images, VM hostnames, Matrix identities, and service accounts. Use the
same string across all of those: the VM, the container, the Caddy host, the Matrix same string across all of those: the VM, the container, the Caddy host, the Matrix
account, and the Bitwarden machine account for a given agent all share one name, so account, and the Bitwarden machine account for a given agent all share one name, so
that grepping the infrastructure for `nisse-ops` finds everything. that grepping the infrastructure for `nisse-ops` finds everything.
Published under a personal GitHub account rather than an org; `github.com/nisse` is The three artifacts live as three packages in **one repository, `nisse`** (decision
squatted and GitHub does not reclaim inactive usernames. The repo names carry the recorded in Part H). Directory and package names carry the identity. If mirrored to
identity. `nisse-core` is free on PyPI if packages are ever published. GitHub, it goes under a personal account rather than an org — `github.com/nisse` is
squatted and GitHub does not reclaim inactive usernames. `nisse-core` is free on
PyPI if packages are ever published.
--- ---
@@ -53,8 +55,9 @@ Both are thin applications over a shared **`nisse-core`** library. The library i
consumers that don't exist yet. Build the Dev Agent as if the library were internal, consumers that don't exist yet. Build the Dev Agent as if the library were internal,
then lift the seams that proved real. then lift the seams that proved real.
Whether the three artifacts live in one repository or three is **an open decision** The three artifacts live in **one repository** (decided — Part H), so the
(Part H). It changes what the extraction step in the build order concretely means. extraction step in the build order is a package split within one tree, not a repo
split.
### Guiding principles (apply to everything below) ### Guiding principles (apply to everything below)
@@ -712,12 +715,9 @@ each agent is built — not standing up the service itself.
10. **Extract `nisse-core`**; build the **Sysadmin Agent** (`nisse-ops`): policy 10. **Extract `nisse-core`**; build the **Sysadmin Agent** (`nisse-ops`): policy
engine (C2), SSO + scoped browser (A8/A6), secrets (A7), Vikunja control (C4), engine (C2), SSO + scoped browser (A8/A6), secrets (A7), Vikunja control (C4),
Outline runbooks (D), scheduled checks, alert intake. Outline runbooks (D), scheduled checks, alert intake.
- Under a monorepo, extraction is a **package split** within one tree: move code - With the monorepo layout (Part H, decided), extraction is a **package split**
behind a package boundary, no release machinery required. within one tree: move code behind a package boundary, no release machinery
- Under three repos, it is a **repo split plus a version-pinning contract**: required.
`nisse-core` gets tagged releases, and `nisse-dev` pins a version rather than
tracking `main`, or every core change becomes a coordinated two-repo bump.
This is the step the open repo-layout decision (Part H) actually bites on.
--- ---
@@ -744,12 +744,16 @@ each agent is built — not standing up the service itself.
The rest resolve when reached, not now. The rest resolve when reached, not now.
- **Repository layout:** one monorepo with three packages vs. three separate repos. - **Repository layout — decided: one monorepo, three packages.** For a solo
Three repos match the build order and give each artifact its own CI and release operator, three repos tripled the admin surface (tokens, CI, webhooks,
cadence, at the cost of version-pinning `nisse-core` from Gitea and coordinating permissions, backups) and imposed a version-pinning contract on `nisse-core` —
bumps every time the shared interface moves. A monorepo is less friction while coordinated bumps every time the shared interface moves — while buying nothing:
`nisse-core` is still being extracted from a working `nisse-dev` and its seams are the repo boundary was never a trust boundary in this design (the VM is), and
still moving. Splitting later is easy; merging later is not. Decide by step 10. independent release cadence is irrelevant solo. A monorepo is also less friction
while `nisse-core` is being extracted from a working `nisse-dev` and its seams
are still moving. One repo can still build both agent images via path-filtered
CI. Splitting later stays easy if a real need appears; merging later would not
have been.
- **Sysadmin browser access to network gear:** standing vs. per-task hand-off. The - **Sysadmin browser access to network gear:** standing vs. per-task hand-off. The
lock-yourself-out risk argues for per-task. lock-yourself-out risk argues for per-task.
- **Policy action taxonomy (C2):** the concrete list of which operations are - **Policy action taxonomy (C2):** the concrete list of which operations are
@@ -792,9 +796,9 @@ infra/ # (future) Terraform + cloud-init (Part F)
nisse-dev.tf | nisse-ops.tf | templates/ nisse-dev.tf | nisse-ops.tf | templates/
``` ```
Shown as three sibling trees. Under a monorepo they become three packages under one These are three packages under one repository root (`nisse`), plus `docs/` for this
root; under three repos, three checkouts. Either way the module boundaries are the specification (Part H, decided). The module boundaries are what matter; the package
same, which is the point of deciding this late (Part H). boundary is where the step-10 extraction lands.
`log/` carries the canonical event log and its renderer (A10); `delegation/` carries `log/` carries the canonical event log and its renderer (A10); `delegation/` carries
the delegation harness and `ask_expert` (A13/A14). the delegation harness and `ask_expert` (A13/A14).