nisse-core records each model call of every agent into a file beside its
state store (<state>.calls.db), for the status page (L7, X6):
- the request body exactly as sent (never headers), the raw response with
its reasoning, the model asked and the one that answered, time, tokens
and llama-server's own prompt reuse (timings.cache_n);
- its work item, role, run and purpose: Driver.run and nisse-dev's
delegation loop open runs, nested; compaction, expert consults, the
classifier and the go-ahead reader label their calls;
- provenance, worked out in BudgetedClient by comparing the events at
each stage: each event sent with its log id and content as sent, which
a compaction replaced, which fitting shortened (by how much) and
dropped.
Content is stored once by hash, compressed. It is diagnostic only: the
agent never reads it, a failed write is logged once and recording stops
while the call goes on, and the file is deleted when the agent starts,
so its layout never migrates; CallReader refuses a layout it doesn't
know. While recording, the system prompt ends with one sentence saying
so. `call_record: false` in either agent's YAML turns it off.
The benchmark records each run beside that run's own state store, and
`--keep-runs DIR` keeps both for the page.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
What isn't the dev agent's moves to nisse-core, unchanged in behaviour,
with its tests: canonical, render, render_anthropic, llm, catalog, probe,
context, views, state, reconcile, worker, cancel, dump, transport, matrix,
execution, testing, vault, memory, oplog, envfile and gitea (whole).
- nisse_core.state.StateStore holds the tables every agent has; an
agent's subclass adds its tables (version, migrations), roles and
views. nisse_dev.state.StateStore adds the build VM blocks (v5).
- views.project takes what each role is shown, rather than a fixed table.
- Vault takes the agent's name (agent=), for provenance.
- A test that nisse_core never imports an agent.
- The loop, config, git, delegation, expert, tools and evals stay in
nisse-dev until nisse-ops has a loop to share.
Docs: the Development Plan marks M7.1 done and notes that Phase 6 waits on
the agent host and Terraform; Architecture Part L names the package.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
What the fast path calls unknown is judged by an independent model call
on the item's classifier role (L4), before it runs.
- nisse_dev.loop.classifier: it sees the action and the agreed scope
(project, repository, issue number, the restatement the operator said
go to), built in code; never the transcript, the issue's text, tool
output or the driver's reasoning. Its verdict is a tool call: safe
runs; in_scope runs and is reported in the thread; needs_discussion
asks, as a dangerous action does. An error, no verdict or an unknown
one fails closed. Verdicts are cached per item, agreed revision and
action. A helper is refused what needs discussion.
- action_verdict gains source, model and the classifier's exact input;
details shows the source. An allow after the classifier asked is an
override. scripts/classifier-evals.py exports the judgements from a
store, read-only; tests/integration/classifier_cases.yaml is the seed
set, run per model with --capability-models.
- The fast path's delete rule: deleting on the build VM is contained;
only what breaks the host (system and home directories) stays
dangerous, since in tests the build VM is the test machine.
- The classifier role is the local model in the example config.
- The property walk gains a classifier answering at random, junk and
failures included; dangerous_only_when_allowed now covers its
verdicts (checked against a mutant that runs them all).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE