Commit Graph
111 Commits
Author SHA1 Message Date
dongarandClaude Opus 5.5 3dbfbc8cf0 Name the site domains the identifiers are stems of
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 54s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 02:00:43 +00:00
dongarandClaude Opus 5.5 cdc3881deb Fold the MCP deployment amendment into the spec
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 1m4s
Part F is restructured around rules that now apply to every agent:

- F1: every agent gets its own VM, for inter-agent isolation and
  per-agent credential attribution
- F2: a declared, per-instance default-deny egress allowlist that
  covers MCP servers' reach, with the tailnet's 100.64.0.0/10 called
  out
- F3: MCP servers per agent VM and per (service, site, privilege),
  plus the rejected routed-meta-tools alternative
- F4: the existing image pipeline, with third-party MCP images
  digest-pinned and excluded from Watchtower

Consequences land where they belong: site identifiers in Part 0, a
machine account per MCP server instance in A7, B3 and C5 recast as
instances of F1/F2, plan approval required for every write in C2, MCP
as the primary infrastructure path in C3, the network-gear browser
item narrowed to fallback access, and stateful-server relocation
parked in Part H.

The standalone amendment is removed now that its content lives here,
as with the Tiered Inference amendment; it remains in the previous
commit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 01:56:30 +00:00
dongarandClaude Opus 5.5 31bef59151 Add the MCP deployment amendment
Records a design session on MCP server deployment as a standalone
amendment, ahead of folding it into the spec:

- Every agent gets its own VM, justified by inter-agent isolation and
  per-agent credential attribution; Docker-in-Docker stays as an extra
  Dev Agent reason rather than the rule's foundation
- Egress is a declared, per-agent-instance default-deny allowlist,
  covering what MCP servers reach on the agent's behalf, with the
  tailnet's 100.64.0.0/10 called out as outside RFC1918
- MCP servers run per agent VM, one instance per (service, site,
  privilege), with site in the server identity rather than a tool
  argument
- Third-party MCP images are digest-pinned and excluded from Watchtower
- Routed meta-tools rejected; stateful-server relocation parked

Two consequences settled with the operator while drafting: each MCP
server instance gets its own Vaultwarden machine account (A7), and any
write, reversible or not, requires an approved plan (C2).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 01:55:31 +00:00
dongarandClaude Opus 5 2352a84004 Map A17 onto Outline's actual primitives, and record the MCP decision
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 58s
Observed rather than assumed, after checking the running instance:
collections carry per-user permissions in three tiers and permissions
are collection-scoped, not per-document. So one collection per writing
principal, with read membership for everyone else.

- States precisely what that enforces: no other agent can write a
  given agent's world model. It does not enforce operator-versus-agent
  exclusion, since the operator holds manager on their own wiki; that
  half is procedural, via the break-glass routine that stops the
  agents first. Two different strengths, so the spec no longer implies
  one guarantee covers both
- Per-user grants, not groups: Outline groups are not federated with
  LLDAP, so using them would put membership somewhere nothing syncs.
  Three principals make the manual mapping trivial
- Outline API keys are per-user, so each agent's token must belong to
  that agent's own Outline user. A token minted from an admin account
  voids every boundary above while appearing to work — the same shape
  as the Gitea permission surprise
- Collections identified by ID from config, documents by ID recorded
  in the state store, which also makes writes idempotent across a
  retry
- The conditional-write requirement softens to a revision *read*:
  break-glass stops the agents, so compare-and-swap is unnecessary and
  only divergence detection is needed for A3

Also records Outline's MCP server as considered and deferred. A17's
enforcement depends on this library sitting between the model and the
store; MCP's purpose is direct model access, and a procedure the model
may decline to fetch does not constrain it. Still a candidate for the
discretionary search tool, with two things to verify first.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 19:36:39 +00:00
dongarandClaude Opus 5 9362a134c9 Give A17 its canonical event, and point Part G at the contract
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 58s
Two loose ends in the A17 amendment, both found by asking whether the
build order needed changing:

- A17 requires retrieved content to be snapshotted into the canonical
  log, but A10's event table — the authoritative list — had no row for
  it, so an implementer reading A10 would never know to add one.
  knowledge_retrieved now carries the text as read, the document ID,
  its revision, and when it was read
- Part G step 10 already scheduled Outline, so the ordering does not
  change; it now names A17 rather than only Part D, and says which
  half arrives first — the world model, with operator procedures
  waiting on the C2 taxonomy they bind to

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 19:23:17 +00:00
dongarandClaude Opus 5 b8ba683595 Add A17, the knowledge store contract (Outline)
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 1m3s
Part D said what Outline is for but never how to build against it —
the only external integration with no A-series component, while
Transport, LLM, Browser, Secrets, SSO and Logging all have one. A17
supplies the contract.

Settled here:

- Sharing is read access, never write access. Every document has
  exactly one writer, so concurrent writers never exist and Part D's
  last-write-wins objection disposes of itself. Default shared
  membership is operator + nisse-ops; nisse-dev gets private space
  only, since B3 seals it from the LAN and a shared network map is a
  map of what it is sealed from
- Agent-owned knowledge is always a cache, never authority: rely on
  it to know what exists and where to look, verify a specific fact
  against the live system before acting on it
- Enforcement is structural, because a prompt is not enforcement. A
  model cannot be stopped from believing what it reads, so the
  enforceable goal is narrower — an unverified belief must not become
  an irreversible action — and four mechanisms carry it, leaning
  hardest on surfacing provenance at the human gate that C2 already
  requires
- Never an instruction channel and never an approval channel, stated
  both here and in A4 where approvals are specified
- Corrections flow through transport rather than direct edits, which
  is better provenance: a hand edit is invisible to the agent's
  record, an instruction is authenticated, logged, and reconcilable.
  Break-glass reuses Part F's idle flag
- Retrieved content is snapshotted into the canonical log, since A10
  forbids a mutable provider handle being the only reference — with
  the A3 consequence that boot must re-fetch snapshots for resumed
  tasks
- Outage posture is asymmetric: write failures never block, but a
  failed read of a procedure bound to a confirm-first action gates,
  because proceeding is acting unconstrained on exactly the operation
  someone wrote a procedure for

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 19:20:43 +00:00
dongarandClaude Opus 5 846e5494ca Record default-branch protection as a B2 requirement
CI / checks (pull_request) Successful in 39s
CI / checks (push) Successful in 32s
B2 specified the service account and its scoped token but never said
the project repo's default branch must be protected — which turns out
to be the load-bearing part of the PR gate.

In Gitea, write access includes merging pull requests, and repository
ownership does not restrict merging either. So an agent with the
access it needs to push branches can also merge its own PR, and the
review gate holds only because the agent's code does not call the
merge endpoint. That is the advisory guarantee A4 exists to rule out.

Verified rather than assumed: before protection was configured, the
agent's own token merged its own PR (HTTP 200). With protection it is
refused (405), as is a direct push to the default branch. The
amendment says to assert both, so relaxing the protection later fails
a test instead of silently removing the gate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 22:48:42 +00:00
dongarandClaude Fable 5 41e103c35d Amend A9 with state-change log conventions (issue #3)
CI / checks (push) Successful in 7s
CI / checks (pull_request) Successful in 7s
Every durable mutation emits one JSON-lines event, emitted by the
state store itself immediately after the commit returns, with a fixed
envelope (ts, agent, event, task_id correlation ID, cause) and a
dotted event taxonomy covering transitions, intents, gates, boot
reconciliation, and migrations. Logs stay diagnostic-only, never
load-bearing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-05 19:29:27 +00:00
dongarandClaude Fable 5 69375c0da1 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>
2026-09-04 22:13:45 +00:00
dongarandClaude Opus 5 bafe4cc9e6 Drop reference to nonexistent Architecture.md
The companion rationale document was never written; this spec stands alone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 21:57:11 +00:00
dongarandClaude Opus 5 be04c28542 Add Nisse build specification
Seeds nisse-core as the home for system-level design documentation. The
spec covers the shared library (Part A), both agents (Parts B and C), and
the supporting services, build order, and open decisions.

nisse-core holds this because the document describes the shared design
rather than either agent's implementation; the repo gains code later, at
the extraction step in the build order.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 21:56:23 +00:00