Compare commits

...
4 Commits
Author SHA1 Message Date
dev-agent 91d1c582ad Merge pull request 'Docs: the status page and the call record (#109)' (#178) from ui-spec into main
CI / e2e (push) Canceled after 0s
CI / checks (push) Canceled after 59s
2026-10-24 13:09:30 +00:00
dongarandClaude Opus 5.5 cba35eb7d4 Docs: runs going in circles end; agents are told they're recorded
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 2m47s
CI / e2e (pull_request) Successful in 4m30s
A run that repeats itself, or keeps getting the same correction, ends in
code as escalated instead of running to its turn cap (L2, M7.8), and the
page flags such runs (X6). While the call record is on, each system
prompt says so.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
2026-10-24 06:14:15 +00:00
dongarandClaude Opus 5.5 5045faefad Docs: the call record is off per agent; the page exports nothing
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
2026-10-24 06:11:25 +00:00
dongarandClaude Opus 5.5 d44581539b Docs: the status page and the call record (#109)
nisse-ui (X6) shows the operator each agent's work and, per item, a
walkthrough down to every model request and response, for studying how
context, compaction and memory work. It reads each agent's state store,
call record and memory folder through read-only mounts, so agent code is
unchanged and each agent stays the only writer of its state; it is
released with the agents and tested against stores their own code wrote.

The call record (L7) is new in nisse-core: every request as sent, the raw
response with its reasoning, timing, tokens, prompt reuse and each
message's provenance. It is diagnostic only, never read by the agent, and
deleted at start, so it never migrates.

Commands from the page, including a hold on a task or a whole agent, are
an open question (Part Q). The shared database first proposed in #109 is
dropped. The plan gets M6.6.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
2026-10-24 06:07:11 +00:00
2 changed files with 104 additions and 4 deletions

No files matched your search

+78 -4
View File
@@ -21,6 +21,7 @@ overnight and expects to be treated well in return.
| Dev Agent | `nisse-dev` | Designs and builds software projects (Part D) | | Dev Agent | `nisse-dev` | Designs and builds software projects (Part D) |
| Review Agent | `nisse-review` | Reviews pull requests (Part R) | | Review Agent | `nisse-review` | Reviews pull requests (Part R) |
| Sysadmin Agent | `nisse-ops` | Operates infrastructure (Part O) | | Sysadmin Agent | `nisse-ops` | Operates infrastructure (Part O) |
| Status page | `nisse-ui` | Shows the operator what the agents are doing and how (X6); not an agent |
More agents are planned (3D design work, video-file management), each another More agents are planned (3D design work, video-file management), each another
application over `nisse-core`. One string names all of an agent's artifacts application over `nisse-core`. One string names all of an agent's artifacts
@@ -220,6 +221,10 @@ again after a restart), permissions (L3), and work in progress as intents (L8).
next tool boundary, unmounts elevated credentials, and asks what next. next tool boundary, unmounts elevated credentials, and asks what next.
- **`abandon` ends a work item** from any waiting point, closing its record and - **`abandon` ends a work item** from any waiting point, closing its record and
any open PRs with a note and aborting its unresolved intents. any open PRs with a note and aborting its unresolved intents.
- **A run going in circles ends** rather than running to its turn cap: turns that
repeat near-identically, or one correction (such as "reply with a tool call")
given again and again, end it in code, escalated with what it was doing. A loop
the model can't leave is the harness's to fix, not the model's to push through.
- **Every action passes through the three layers** (P4). - **Every action passes through the three layers** (P4).
### L3. Authority: scope and approvals ### L3. Authority: scope and approvals
@@ -278,7 +283,8 @@ executes nothing, so it runs on the agent host.
**Matrix is the conversation channel:** a self-hosted homeserver, one identity and **Matrix is the conversation channel:** a self-hosted homeserver, one identity and
room per agent, behind a `Transport` interface so another chat system is one new room per agent, behind a `Transport` interface so another chat system is one new
class. Existing Matrix clients are the UI. class. Existing Matrix clients are the UI for conversation and commands; a
read-only page shows each agent's work, and how it went, in detail (X6).
**A thread per work item.** Each item's conversation is a Matrix thread, and the **A thread per work item.** Each item's conversation is a Matrix thread, and the
thread is how the agent knows which item a message is about. thread is how the agent knows which item a message is about.
@@ -332,7 +338,8 @@ logs the outage; interrupted outbound effects are covered by intents (L8).
### L6. Context and memory ### L6. Context and memory
**1. The working context of one model call** is rendered from the log at call time **1. The working context of one model call** is rendered from the log at call time
for one role, fitted to that model's window, and never stored. for one role, fitted to that model's window, and never stored as state. A copy
goes into the call record (L7) for the operator to study; nothing reads it back.
- **A long run is compacted:** well before the window fills, the model's own - **A long run is compacted:** well before the window fills, the model's own
notes replace the middle of its run in one step (a `compaction` event, L7), notes replace the middle of its run in one step (a `compaction` event, L7),
keeping word for word what started the work and its last few turns. Rare, keeping word for word what started the work and its last few turns. Rare,
@@ -411,6 +418,30 @@ call time.
delegation that produced it. delegation that produced it.
- **The log is never edited;** corrections and compactions are new events. - **The log is never edited;** corrections and compactions are new events.
**The call record** is a second store beside the log, for study only: `nisse-core`
writes it for every model call of every agent, into its own file on the agent's
volume.
- **What each call was:** the request exactly as sent (system prompt, tools,
messages, `tool_choice`, output limit; never headers, so no credential), the raw
response with its reasoning, the model asked and the one that answered, time,
tokens, the server's own count of prompt reuse, and what fitting cut. A failed
call is recorded with its error.
- **Where it came from:** its work item, role and run (a driver run, a consult, a
compaction, a classification), and for each message, the log events it was
rendered from and what rendering did to them (unchanged, labelled, narrated,
compacted, shortened and by how much), with what was dropped. So a request reads
against the log it was made from (L6).
- **Content is stored once,** by hash: a long, growing conversation costs about one
copy of itself.
- **It is never load-bearing:** nothing in the agent reads it, a failed write is
logged and the call goes ahead, and it is deleted when the agent starts. Its
layout never migrates; it carries its version for the page (X6).
- **Agents are told:** while it records, each system prompt says in one sentence
that the agent's calls are recorded for the operator's study.
- **On by default, off per agent** in its configuration: an agent that handles
other people's lives (a household's presence, conversations, cameras) records
nothing unless they know.
### L8. Durability and recovery ### L8. Durability and recovery
**The state store** (SQLite) holds each work item's position, permissions, pending **The state store** (SQLite) holds each work item's position, permissions, pending
@@ -1078,8 +1109,9 @@ template with a trigger, rate limit and expiry, for a routine fix).
**One agent host,** stable and long-lived. Each agent is a container on it with its **One agent host,** stable and long-lived. Each agent is a container on it with its
own volume (state, transcripts), secrets (L12) and network; no agent can reach own volume (state, transcripts), secrets (L12) and network; no agent can reach
another's. Its MCP servers run beside it (X3). The vault lives here (L10). **It never another's, and only the status page reads their volumes, read-only (X6). Its MCP
runs a command a model chose** (L13), which is what makes sharing it safe. servers run beside it (X3). The vault lives here (L10). **It never runs a command
a model chose** (L13), which is what makes sharing it safe.
**Tool VMs** are where model-chosen commands run, reached only over SSH from the **Tool VMs** are where model-chosen commands run, reached only over SSH from the
agent host, each built from a template plus recorded installs and disposable: agent host, each built from a template plus recorded installs and disposable:
@@ -1135,10 +1167,52 @@ Vaultwarden, Samba AD with Authelia, and SilverBullet for the operator's view of
the vault. Each agent has its own account, token and room in each; nothing is the vault. Each agent has its own account, token and room in each; nothing is
shared between agents. shared between agents.
### X6. The status page
**`nisse-ui`** is the operator's view of the agents: what each is doing, and how it
did it in full detail. It is for understanding the system (how context, compaction
and memory work in practice), more than for daily use.
- **What it shows:** per agent, the active item, what's queued, parked and blocked
and why, recent closed items, with links to issue, PR and thread; and per item, a
walkthrough: its steps (runs, and the orchestrator's facts and gates between
them), each run's turns, and each turn's request and response from the call
record (L7), readable: where each message came from and what was done to it,
what changed since the previous turn and where prompt reuse stopped, the
reasoning, and the raw JSON. Memory appears as the log records it: the index
when it was shown, each note read or written. Work from before the agent's last
start has its steps but no requests.
- **Loops are flagged:** near-identical turns, repeated apologies, one correction
given again and again, so they're seen and fixed (L2).
- **It reads, never writes:** each agent's state store and call record through a
read-only mount, opened read-only in short transactions, and the agent's memory
folder read-only, as SilverBullet does (L10). Each agent stays the only writer
of its state (L8), and agent code doesn't change for the page. It runs no
model, holds no credentials and reaches nothing but the mounts and Caddy.
- **Versions:** it is released with the agents, from the same tag. It reads the
state store's schema versions it knows and says so for any other, rather than
guessing; it reads item data tolerantly (defaults for missing fields, raw names
for unknown states), for the gap while one container updates before another.
CI tests it against stores written by the agents' own code, so a change that
would break it fails in the same PR.
- **Any recorded run opens,** not only a live agent's: bring-up, end-to-end and
benchmark runs leave the same two files.
- **Everything it shows is untrusted text** (L11): it is escaped, and the page
allows no script it didn't ship.
- **Access** is through Caddy behind Authelia, the operator's group only: it shows
everything the models saw, including what other people wrote (peers, issue
authors, whatever an agent handles). Nothing is exported from it.
- **Commands come later** (Part Q), never by writing an agent's files: as another
`Transport` (L5), so a button sends what Matrix would, with the same rules and
record.
--- ---
## Part Q — Open questions ## Part Q — Open questions
- **Commands from the status page** (X6): how they reach each agent and show who
sent them (a per-agent inbox only the page writes, or signed requests). The
first are `stop`, priority ("do #N next"), and a **hold**: a task, or a whole
agent, does nothing until released. A hold is a new command, in Matrix too.
- **The classifier's model,** and how its verdicts are calibrated against overrides. - **The classifier's model,** and how its verdicts are calibrated against overrides.
- **Recognising questions:** an explicit marker or classification; a misread asks. - **Recognising questions:** an explicit marker or classification; a misread asks.
- **How far the local driver goes,** measured on real work (P7). - **How far the local driver goes,** measured on real work (P7).
+26
View File
@@ -578,6 +578,23 @@ Samba AD principal (L12).
**M6.5 The browser tool.** *Pre-approved.* On the internal test network (D7). **M6.5 The browser tool.** *Pre-approved.* On the internal test network (D7).
**M6.6 The status page.** *Pre-approved (design agreed 2026-10-24, #109).*
`nisse-ui` (X6), for studying how the agents work: context, compaction, memory.
Slices a–c are built on this box before the agent host is ready, against
bring-up, end-to-end and benchmark runs; only d waits for M6.1.
- **a. The call record** (L7) in `nisse-core`: written by the shared model client
and `Driver.run`, with each message's provenance from the per-role view and
fitting; wired in each agent's build; deleted at start. Each system prompt
says the calls are recorded, while they are.
- **b. The walkthrough:** an item's steps, each run's turns, and each request read
against the log it was made from; runs going in circles flagged.
- **c. The overview:** each agent's active, queued, parked and blocked items.
- **d. Deployment:** its image, the read-only mounts and a Caddy route behind
Authelia (with #166).
Commands wait (Part Q). The shared database #109 first proposed is dropped: each
agent keeps its own store.
### Phase 7 — `nisse-core` and `nisse-review` ### Phase 7 — `nisse-core` and `nisse-review`
`nisse-review` (Part R) comes before `nisse-ops`: it writes only comments, so it `nisse-review` (Part R) comes before `nisse-ops`: it writes only comments, so it
@@ -780,6 +797,13 @@ publishes `gitea.dongar.net/dev/nisse-review` beside `nisse-dev`, and
**M7.7 Deployment.** *Waits for the agent host (Phase 6).* Its container on the **M7.7 Deployment.** *Waits for the agent host (Phase 6).* Its container on the
agent host, Gitea account and secrets (R5). agent host, Gitea account and secrets (R5).
**M7.8 Runs that go in circles end** (L2). *Pre-approved.* In `Driver.run`, for
every agent. Seen 2026-10-24 on Flash-Next: invented tool names met with the
prose reminder turn after turn, and a no-thinking run posting the same apology
comment about 20 times until the turn cap. Repeated near-identical turns, or the
same correction given too often, end the run as escalated, with what it was
doing; the limits are tuning.
### Phase 8 — `nisse-ops` ### Phase 8 — `nisse-ops`
**M8.1 MCP servers** (#37). Settled so far: redaction scrubs each instance's own **M8.1 MCP servers** (#37). Settled so far: redaction scrubs each instance's own
@@ -796,6 +820,7 @@ the Terraform the operator is writing now. **M8.4 The ops tool VM and deployment
From the architecture's open questions and older issues: filing issues from From the architecture's open questions and older issues: filing issues from
conversation; stacked PRs; releases; `nisse-ops` issuing credentials; a server conversation; stacked PRs; releases; `nisse-ops` issuing credentials; a server
database; recovering the agent host (an ops issue); more than one active work item; database; recovering the agent host (an ops issue); more than one active work item;
commands from the status page, with a hold on a task or agent (X6);
vision; one local model for every agent; several forges (#26); a room per project vision; one local model for every agent; several forges (#26); a room per project
(#28). (#28).
@@ -816,6 +841,7 @@ vision; one local model for every agent; several forges (#26); a room per projec
| #69 inline review comments | M2.1 | | #69 inline review comments | M2.1 |
| #70 watch stall | M2.1 | | #70 watch stall | M2.1 |
| #77 conversational agent | M2.3 (questions), M2.7 | | #77 conversational agent | M2.3 (questions), M2.7 |
| #109 a UI for every agent's status (no shared database) | M6.6 |
| #137 block on an unreachable build VM | M4.4 | | #137 block on an unreachable build VM | M4.4 |
| #144 redact secrets an MCP server returns | After M8.1 | | #144 redact secrets an MCP server returns | After M8.1 |