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

10 KiB

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

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
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.