Files
boxmaker/docs/plans/M1/01-workspace-and-gate.md
T
kyleandClaude Fable 5.1 3e26c2e3c0 Add M1 plan, given tests and fixtures, AGENTS.md and implementer log
Seven task files for the implementing model under docs/plans/M1/, with
the test files, byte-exact fixtures, Makefile, deny.toml and gate-script
self-test they copy into place. All of it was verified against a private
reference implementation: the gate passes after every task in order.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 01:22:43 -07:00

186 lines
6.5 KiB
Markdown

# M1 task 01: workspace and gate
**Branch:** `m1` (create it: `git switch -c m1`)
**Commit subject:** `Add Cargo workspace, crate skeletons and the gate`
## Goal
Create the Cargo workspace with seven empty crates, and the gate that every later task must pass.
At the end `make gate` prints `gate: ok`.
## Context
From the design brief: "Rust stable, Cargo workspace. Crates: `proto` (shared types), `loopd`,
`brokerd`, `gatewayd`, `inferproxy`, `toolkit` (tool container entrypoints), `bxctl` (owner CLI).
No source file over 500 lines. No crate depends on another role's crate, only on `proto`.
Dependencies are few and justified in `docs/dependencies.md`. No outbound call not listed in
`docs/egress.md`."
Every crate except `proto` is a library with a thin `main.rs`, so that doctests can run later.
## Files
- Copy (never edit afterwards): `Makefile`, `deny.toml`, `scripts/test-gate-scripts.sh`
- Create: `Cargo.toml`, `Cargo.lock` (generated), `crates/<name>/Cargo.toml` for all seven crates,
`crates/<name>/src/lib.rs` for all seven, `crates/<name>/src/main.rs` for the six that are not
`proto`
- Create: `scripts/check-lines.sh`, `scripts/check-crate-deps.sh`, `scripts/check-dep-docs.sh`
- Create: `docs/dependencies.md`, `docs/egress.md`
- Modify: `docs/implementer-log.md`
## Steps
- [ ] **1. Branch and copy the given files.**
```sh
git switch -c m1
mkdir -p scripts
cp docs/plans/M1/files/Makefile docs/plans/M1/files/deny.toml .
cp docs/plans/M1/files/scripts/test-gate-scripts.sh scripts/
```
Read `Makefile` and `scripts/test-gate-scripts.sh`. The second one is the test for the three
scripts you write in step 4: it shows exactly which inputs must pass and which must fail.
- [ ] **2. Write the root `Cargo.toml`** with exactly this content:
```toml
[workspace]
resolver = "3"
members = [
"crates/proto",
"crates/loopd",
"crates/brokerd",
"crates/gatewayd",
"crates/inferproxy",
"crates/toolkit",
"crates/bxctl",
]
[workspace.package]
edition = "2024"
rust-version = "1.95"
publish = false
[workspace.lints.rust]
unsafe_code = "forbid"
[workspace.dependencies]
proto = { path = "crates/proto" }
```
- [ ] **3. Write the seven crates.** `crates/loopd/Cargo.toml` is:
```toml
[package]
name = "loopd"
version = "0.1.0"
edition.workspace = true
rust-version.workspace = true
publish.workspace = true
[lints]
workspace = true
[dependencies]
proto.workspace = true
```
The other five role crates are the same with their own `name`. `crates/proto/Cargo.toml` is the
same with `name = "proto"` and an empty `[dependencies]` section.
Each `src/lib.rs` is one doc comment line and nothing else:
| Crate | `src/lib.rs` |
|---|---|
| `proto` | `//! Shared data types and the frame codec for Boxmaker. No policy and no I/O beyond frames.` |
| `loopd` | `//! The agent loop: sessions, prompt assembly and memory. It holds no authority.` |
| `brokerd` | `//! The broker: the only role that holds authority.` |
| `gatewayd` | `//! The Mattermost channel. Outbound connections only.` |
| `inferproxy` | ``//! Forwards bytes between `infer.sock` and the llama-server router. It logs nothing.`` |
| `toolkit` | `//! Entry points that run inside tool containers.` |
| `bxctl` | `//! The owner's command-line tool.` |
Each `src/main.rs` (not for `proto`) follows this pattern, with its own name and milestone
(`loopd` M2, `brokerd` M3, `gatewayd` M4, `inferproxy` M2, `toolkit` M3, `bxctl` M2):
```rust
fn main() {
eprintln!("loopd: not implemented until M2");
std::process::exit(2);
}
```
Run `cargo build`. Expected: it finishes without warnings and creates `Cargo.lock`.
- [ ] **4. Write the three gate scripts.** POSIX `sh` only: no bash features, no Python, no `jq`.
Each takes an optional `ROOT` argument that defaults to `.`, prints one line per problem to stderr
starting with the script's name, and exits 1 if there was any problem, 0 otherwise.
- `scripts/check-lines.sh [ROOT]`: fails if any `*.rs` file under `ROOT/crates` has more than 500
lines. Files under any `target/` directory are ignored. Test files count.
- `scripts/check-crate-deps.sh [ROOT]`: the workspace crates are the directories in `ROOT/crates`.
Fails if `proto` depends on any workspace crate, or if any other crate depends on a workspace
crate other than `proto`. Look at every manifest section whose name contains `dependencies`
(so `[dev-dependencies]` counts). A dependency is any key in such a section, however it is
written: `x.workspace = true`, `x = { path = "…" }`, `x = "1"`.
- `scripts/check-dep-docs.sh [ROOT]`: fails if a key in `[workspace.dependencies]` of
`ROOT/Cargo.toml` that is not a workspace crate has no table row starting ``| `name` |`` in
`ROOT/docs/dependencies.md`. It also fails if any dependency line in any
`ROOT/crates/*/Cargo.toml` lacks `workspace = true`.
Run `sh scripts/test-gate-scripts.sh`. Expected: `test-gate-scripts: ok`. If it reports failures,
fix your scripts, never the test.
- [ ] **5. Write the two documents.** `docs/dependencies.md`:
```markdown
# Dependencies
Every external crate has a row here. `scripts/check-dep-docs.sh` enforces it.
| Crate | Version | Used by | Why |
|---|---|---|---|
```
`docs/egress.md`:
```markdown
# Egress
Every outbound network call the project makes, at run time or in development. Nothing else is
allowed.
| When | From | To | What |
|---|---|---|---|
| Development | `cargo` | crates.io | Downloading the crates listed in `docs/dependencies.md` |
| Development | `make audit` | github.com/rustsec/advisory-db | The RustSec advisory database, fetched by `cargo deny check advisories` |
```
- [ ] **6. Run the gate.** `make gate`. Expected last line: `gate: ok`. At this stage `cargo deny`
prints `license-not-encountered` warnings, because there are no dependencies yet. They are
expected and they go away in task 02. Do not edit `deny.toml`.
- [ ] **7. Log and commit.** Add your row to `docs/implementer-log.md`, then:
```sh
git add Cargo.toml Cargo.lock Makefile deny.toml crates scripts docs/dependencies.md docs/egress.md docs/implementer-log.md
git status --short
git commit
```
`git status --short` must show nothing untracked except ignored files. Use the commit subject at
the top of this file and the trailer from `AGENTS.md`.
## Done when
- `make gate` prints `gate: ok`.
- `cmp Makefile docs/plans/M1/files/Makefile` and the same for `deny.toml` and
`scripts/test-gate-scripts.sh` print nothing.
- One new commit on `m1`.
## Stop and report if
- `cargo deny` is not installed (`cargo deny --version` fails).
- `make gate` fails in a step that is not one of your scripts and you cannot see why.