Files
2026-09-27 22:33:18 -07:00

100 lines
10 KiB
Markdown

# Boxmaker milestones and session prompts
One session per milestone. The design brief is `docs/design.md`.
## Milestones
| # | Milestone | Proves | Verified by |
|---|---|---|---|
| M0 | Measurement spike | The cache and tool-call assumptions hold on straylight | Numbers in `docs/inference-contract.md` |
| M1 | Workspace, `proto`, gate | The type-level authority model compiles | `make gate` |
| M2 | `loopd` core + `bxctl chat` | Append-only loop, baseline ≤ 3k tokens, self-test, runaway control, with one fake in-process tool | Prefix-extension property test; turn-2 cache hit on straylight |
| M3a | `brokerd` decisions | Grants, deny by default, taint, hash-chained audit, `ask` approvals through `bxctl`, two sockets, `loopd`'s broker port; tools do not run yet | Tests for every deny path; audit tampering suite; a denial reaches Ornith on straylight as a tool result |
| M3b | `brokerd` runner | Rootless container runner, four tools (read file, write file, sandboxed shell, HTTP fetch with host allowlist), egress proxy | A container with no network grant cannot reach the network; fetch refused for hosts outside the grant |
| M4a | `gatewayd` + Mattermost conversations | Bot connection over TLS, user-ID allowlist, threads as sessions, bursts as one turn, typing while working, catching up after downtime, the secret store, no listening port | A direct message answered on the real server; a non-allowlisted user gets no response |
| M4b | Approvals over Mattermost | `gateway.sock`, approval posts, answers by `!approve`/`!deny` in the thread, approvers list, long approvals in parts | An `ask` call approved and refused from Mattermost; the audit log names the post |
| M5a | Local memory | `memoryd` without a network: the three memory files served to `loopd` once per epoch, the `memory` tool (`note`, and add, replace, remove, `consolidate` for identity) without questions and its check, `memory/notes.md`, the journal and `bxctl memory log`/`undo`, FTS5 `recall` over session logs and notes with source tags, `recall` hit counts, `bxctl reindex` | A fact from one session is recalled in another; an entry moved by `consolidate` is found by `recall`; a write from a session that read untrusted content becomes an untrusted note, never identity; a memory edit changes the prompt only in the next session (next epoch once M5c adds epochs); the baseline with the owner's files stays under 3,000 tokens |
| M5b | Hardening | The sanitizer for memory writes, from the prompt-injection research of 2026-09-24: refuse only bytes that are never legitimate (invisible and format characters, bidirectional overrides, tag characters, private use, noncharacters, controls other than newline and tab) and known-prefix secrets; flag attack-shaped text (an identity write becomes a note, the reason journalled); chat-template tags neutralised to a visible look-alike wherever text enters the model's context or memory, the list checked against the tokenizer by the self-test; image links escaped in what `gatewayd` posts; a reason in invalid-arguments refusals; the secret store (systemd credential, environment, owner-only file) out of `gatewayd`, so every role can load its secrets at startup, failing closed | A tag in a fetched page reaches the model escaped; a write holding an invisible character or a key is refused; an identity write shaped like an attack becomes a note; a memory about code (a hash, a path, a fence, a command) is written unchanged; an image link in a reply is posted as text; a role whose secret is missing or readable by others does not start, and says which |
| M5c | Honcho | `memoryd` syncs finished turns through `roncho` to two workspaces of its own: the speaker's message and the agent's final reply, to the trusted workspace while the session is clean and at most `private` at the turn's end (asked of `brokerd` over a socket), to the untrusted one otherwise, never for a `secret` session; every trusted memory write mirrored as a conclusion at once; untrusted notes to the fleet workspace, as messages; `recall` over the local index, other agents' trusted workspaces and the fleet; `ask_memory` over named workspaces in parallel; keys from the secret store. Planned and run in two halves: the write path, then the read path (spec `docs/specs/2026-09-27-m5c-honcho.md`) | A turn from a tainted session never reaches the trusted workspace, and a `secret` session's reaches none; a result from an untrusted workspace taints the session; `recall` still answers from the local index when Honcho is down; a memory write is in Honcho at once, and undoing it removes it |
| M5d | Scheduler and compaction | Heartbeat and cron on their own slot in isolated sessions; compaction at idle, starting a new epoch from the baseline and a summary; summaries of tool output for the tools that opt in (a web fetch, say), indexed with the output's label; the tiering job, which decides what stays at which tier | A scheduled run leaves the main slot's cache intact; a fact from epoch 1 is recalled in epoch 2, and a memory edit reaches the next epoch; the tiering job promotes only trusted notes into identity, and its writes are journalled like any other |
| M6 | Subagents + cloud consult | Subagents on their slot returning summaries; consult tool gated by data-class grants with full payload log | A tainted session is refused; payload log matches what was sent |
| M7 | Split deployment | Each role in its own rootless container; `loopd` with no network; socket volume permissions; egress proxy for tools; host ACL policy in `deploy/` | From inside the `loopd` container, requests to the internet, the tailnet and the host all fail; a tool container without a host grant cannot reach the tailnet |
## Per-milestone prompt template
```text
Read AGENTS.md, docs/design.md and docs/inference-contract.md. This session delivers milestone
M<n>: <one-line goal from the table>.
Scope: <bullets>. Out of scope: everything else, including later milestones.
Start by restating the acceptance checks from the milestone table as tests or scripted checks.
Write a plan, show it to me, then execute it with subagents, tests first. Verify external APIs
from their documentation before use. Finish with `make gate` and the on-device verification
named in the table; report exit status, last lines, and what you observed on straylight.
If the design brief turns out to be wrong, stop and propose the change to docs/design.md as its
own commit before building on it.
```
## Session 1 prompt (M0 spike + M1 skeleton)
As written in the kickoff pack, kept for the record. It is superseded: M0 is done
(`docs/inference-contract.md`), and M1 is planned in `docs/plans/M1/` from
`docs/specs/2026-09-17-pre-m1-design.md`.
```text
```text
You are starting a new Rust project: Boxmaker, a sovereign personal agent harness. Read docs/design.md
first; it is the design brief and it is binding. If anything in it looks wrong or contradicts
what you measure, stop and tell me rather than working around it.
This session has two deliverables, in order.
DELIVERABLE 1 — M0 measurement spike (throwaway code, kept findings)
The inference host is `straylight` (Strix Halo, llama.cpp llama-server, Ornith-1.5-35B-A3B,
~128k context). Before any architecture is built, measure what the design assumes. Ask me for
the server URL and how you can reach it; if you cannot reach it, stop and say exactly what is
missing.
Fetch the llama-server README for the build running on straylight and the model card before
using any endpoint or parameter. Do not rely on memory for request fields. Then measure and
record in docs/inference-contract.md:
a. Prompt-processing and generation throughput at depth 0 and ~32k (llama-bench or timed
requests; say which).
b. A 3-turn conversation with 4 tool schemas and thinking enabled: tokens processed versus
tokens reused from cache on each turn. Show the raw timing fields.
c. Whether tool calls come back correctly parsed through the chat-completions endpoint with
the model's shipped template. Run 20 trials across 4 tools and report the failure count.
d. Whether requests can be pinned to a slot, and whether a second session on another slot
leaves the first slot's cache intact.
e. What happens to the cache when an earlier assistant turn contained a thinking block.
f. The exact launch flags in use, and the flags you recommend, with reasons.
g. Whether llama-server can listen on a Unix socket, and whether it runs on the same host as
the harness containers. This decides whether `inferproxy` is needed.
Spike code goes in spike/ and is labelled throwaway. Conclude with a recommendation on the open
question in the brief: server-side chat-completions, or in-process template rendering.
Stop after M0 and show me the findings before starting M1.
DELIVERABLE 2 — M1 workspace skeleton
- AGENTS.md at the repo root: project standards drawn from docs/design.md "Code constraints",
plus how to run the gate and how to verify against straylight.
- Cargo workspace with the crates named in the brief. `proto` gets the real shared types:
session log records, tool request and result, data-class labels, grant, decision, audit
record. Other crates are minimal binaries that compile.
- Makefile with `make gate`: cargo fmt --check, clippy with warnings denied, cargo test,
cargo-deny, and a check that fails on any source file over 500 lines.
- docs/dependencies.md and docs/egress.md, initially short and accurate.
- Unit tests for `proto` serialization round trips and for the rule that a `Decision` cannot
be constructed outside the policy module (a compile-fail test is acceptable).
Working rules
- Verify every external crate's current API on docs.rs before using it, and check its
maintenance status and license. If you cannot fetch documentation, say so; do not guess.
- Write a short plan before M1 and execute it with subagents. Tests first.
- Run `make gate` before declaring anything done. Report the exit status and last lines.
- One logical change per commit. Never commit runtime data, secrets, or spike output that
contains conversation content.
- Keep it small. If a feature is not in the brief, do not add it. Propose it instead.
```