Appendix: Workspace Scaffold
This is the whole of panoptes-control at a glance — every file, what creates it, and which dependencies each crate pulls in. The verified reference workspace (38 tests, clippy clean) lives at github.com/tbar4/panoptes_control. Use this page as the map when a build chapter says "add a crate" and you want to see where it sits.
The annotated tree
Each file is tagged with the chapter that creates it.
panoptes_control/
├── Cargo.toml # workspace manifest — Part I (Phase 0)
├── crates/
│ ├── control-core/ # the seams: everything depends on this
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs # module wiring + re-exports
│ │ ├── ids.rs # RunId/JobId newtypes — Part II · build-domain
│ │ ├── domain.rs # Run, Job, EvalJob, … — Part II · build-domain
│ │ ├── error.rs # ControlError + is_retryable — Part II · build-seam
│ │ ├── worker.rs # WorkerHandle trait (the seam)— Part II · build-seam
│ │ ├── proto.rs # Message wire enum — Part II · build-seam
│ │ └── codec.rs # MessageStream framed codec — Part VIII · build-codec
│ ├── control-eval/ # the eval workload + file contract
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs
│ │ ├── client.rs # ModelClient + HttpModelClient — Part III · build-eval
│ │ ├── eval.rs # run_eval — Part III · build-eval
│ │ └── contract.rs # manifest + JSONL records — Part III · build-contract
│ ├── control-store/ # sqlx / SQLite persistence
│ │ ├── Cargo.toml
│ │ ├── migrations/
│ │ │ └── 0001_init.sql # runs + jobs tables — Part IV · build-store
│ │ └── src/
│ │ └── lib.rs # Store: claim, record, usage — Part IV · build-store/build-claim
│ ├── panoptes-control/ # the coordinator binary (lib + main)
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs # axum API + telemetry + /stats — Part V · build-api, Part VII
│ │ ├── worker.rs # LocalWorker — Part VI · build-scheduler
│ │ ├── scheduler.rs # Scheduler, plan_jobs, retry — Part VI · build-scheduler
│ │ ├── remote.rs # RemoteWorker, SharedPool, actor— Part VIII · build-remote
│ │ ├── main.rs # serve + shutdown + worker port — Part VI/VIII · build-runloop
│ │ └── tests/
│ │ └── distributed.rs # kill-a-worker capstone — Part VIII · build-capstone
│ └── panoptes-worker/ # the networked worker binary
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs # run_session / serve_worker — Part VIII · build-remote
│ └── main.rs # clap + reconnect loop — Part VIII · build-remote
The workspace manifest
Dependencies are declared once in [workspace.dependencies] and each crate opts in with { workspace = true }. One version, chosen once, for the whole tree.
[workspace]
resolver = "2"
members = ["crates/control-core", "crates/control-eval", "crates/control-store", "crates/panoptes-control", "crates/panoptes-worker"]
[workspace.dependencies]
serde = { version = "1", features = ["derive"] } # derive-based (de)serialization
serde_json = "1" # JSON on the wire and in JSONL logs
chrono = { version = "0.4", features = ["serde"] } # timestamps on runs
uuid = { version = "1", features = ["v4", "serde"] } # RunId/JobId inner type
thiserror = "2" # the ControlError enum
anyhow = "1" # binaries' top-level errors
async-trait = "0.1" # async methods in WorkerHandle/ModelClient
tokio = { version = "1", features = ["full"] } # the async runtime
tokio-util = { version = "0.7", features = ["codec"] }# LengthDelimitedCodec framing
futures = "0.3" # buffer_unordered, Sink/Stream ext
axum = "0.7" # the coordinator HTTP API
tower = "0.5" # service middleware plumbing
tower-http = { version = "0.6", features = ["trace"] }# request tracing layer
sqlx = { version = "0.8", features = ["runtime-tokio", "sqlite", "macros", "migrate", "chrono", "uuid"] } # persistence
clap = { version = "4", features = ["derive"] } # the binaries' CLIs
reqwest = { version = "0.12", features = ["json"] } # HttpModelClient's HTTP calls
tracing = "0.1" # spans + events
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } # subscriber
bytes = "1" # frame buffers
# dev
wiremock = "0.6" # mock the model API in tests
pretty_assertions = "1" # readable assert_eq diffs
Per-crate dependency matrix
Which crate pulls what. core = control-core. Everything points at control-core; only the two binaries name concrete transports.
| Crate | Workspace deps |
|---|---|
| control-core | serde, serde_json, chrono, uuid, thiserror, async-trait, tokio, tokio-util, futures, bytes |
| control-eval | control-core, serde, serde_json, async-trait, reqwest, tokio · dev: wiremock, pretty_assertions, tokio |
| control-store | control-core, sqlx, serde, serde_json, chrono, uuid, tokio · dev: pretty_assertions |
| panoptes-control | control-core, control-eval, control-store, axum, tower, tower-http, tracing, tracing-subscriber, serde, serde_json, chrono, uuid, tokio, futures, async-trait, clap, anyhow · dev: wiremock, reqwest, pretty_assertions |
| panoptes-worker | control-core, control-eval, tokio, clap, anyhow, tracing, tracing-subscriber · dev: async-trait, pretty_assertions |
Expected test progression
Each part adds tests. When you finish a part, cargo test across the workspace should reach the running total below.
| Part | Crate(s) touched | Adds | Workspace total |
|---|---|---|---|
| II — Core | control-core | ids, domain, error, worker, proto | 12 |
| III — Eval | control-eval | client, eval, contract | 17 |
| IV — Persistence | control-store | store CRUD, claim, record, idempotency | 22 |
| V — Service | panoptes-control | API handlers (spawn on port 0) | 26 |
| VI — Scheduler | panoptes-control | plan/retry/tick, LocalWorker | 30 |
| VII — Telemetry | panoptes-control, control-store | /stats + usage_by_model | 33 |
| VIII — Cluster | control-core, control-store, panoptes-control, panoptes-worker | codec, remote, heartbeat, worker, capstone | 38 |
Note: exact per-crate counts — control-core 12, control-eval 5, control-store 5, panoptes-control 15 (14 unit + 1 integration), panoptes-worker 1 — sum to 38. The table's "workspace total" column tracks the cumulative figure as you build each arc in order.