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

6.5 KiB

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.
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:
[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:
[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):

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:
# Dependencies

Every external crate has a row here. `scripts/check-dep-docs.sh` enforces it.

| Crate | Version | Used by | Why |
|---|---|---|---|

docs/egress.md:

# 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:

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.