The one contract for every coding agent in this repository. CLAUDE.md and
GEMINI.md are symlinks to this file, and
tests/citadel/test_agent_contract_is_one_file.py keeps them that way.
They used to be separate files with almost disjoint content, which meant each agent was held to a different contract: Claude never saw the release rules or the bounded-diagnostics wrapper, and Codex never saw the code style or the invariants. Nobody chose that -- the files simply grew apart, and nothing was comparing them.
Prioritize implementation. During routine development run only the smallest TDD regression and checks needed for the changed behavior. Do not run broad workspace, contract, VM, install, or benchmark suites after every edit or commit. Qualify the complete result at the end of each major phase and before merge or release. Keep implementation progress separate from qualification status; pending broad proof must not prevent independent coding on later phases.
just doctor # Check tools (first time)
just doctor fix # Install prerequisites and materialize missing VM assets
just shell # Build + boot VM (~10s)
just fast-test # Incomplete source feedback; prints the next supported rails
just focus-test functional # Rerun one named functional owner
source_commit=$(git rev-parse HEAD)
just test "$source_commit" # Required before merge and release; exact repeats reuse its journal.
# Optional hands-on local testing; never a release prerequisite
just install
# Release only the exact commit whose `just test` passed (see Releases below)
just release-binaries nightly "$source_commit"
just release-assets nightly "$source_commit"See /dev-just for the full recipe reference and dependency chains.
crates/capsem-foundation/ Low-level paths, UDS, logging, polling, and IPC handshake
crates/capsem-cache/ Bounded cache primitives, freshness publication, and cache telemetry
crates/capsem-crypto/ Accelerated hashes, randomness, TLS keys, JWT verification, secrets
crates/capsem-archive/ Block-compressed body archive for session ledgers (pure Rust)
crates/capsem-ledger/ Confined session-ledger worker and archive codec executor
crates/capsem-telemetry/ Every metrics-facade metric name, kind, unit, and description
crates/capsem-assets/ Asset manifest compatibility, resolution, download, and verification
crates/capsem-api/ Gateway wire types and OpenAPI contract shared by clients
sdk/rust/ capsem-sdk: async HTTP gateway clients sharing capsem-api DTOs
crates/capsem-config/ Product config types, parsing, validation, and provider/MCP identity
crates/capsem-credentials/ Credential provider contracts and durable credential store
crates/capsem-core/ VM, hypervisor, security engine, and host network runtime
crates/capsem-service/ Daemon service (axum HTTP over UDS, VM lifecycle)
crates/capsem-process/ Per-VM process (boots VM, bridges vsock, job store)
crates/capsem-proxy/ Confined HTTP/DNS proxy worker for VM and standalone traffic
crates/capsem/ CLI client (create, shell, exec, list, install, assets, update)
crates/capsem-tui/ Terminal control UI (reads and drives state via the gateway)
crates/capsem-admin/ Runtime image/asset/release administration (validate, materialize, publish)
crates/capsem-gateway/ TCP-to-UDS HTTP gateway (frontend + tray + remote auth)
mcp/typescript/ SDK-backed npm host MCP server for AI agents (stdio, authenticated gateway HTTP)
crates/capsem-router/ Confined TCP publication companion (data descriptors only)
crates/capsem-network/ Host end of a guest tun0: smoltcp over a framed VSOCK packet stream
crates/capsem-mcp-transport/ Connected HTTP capabilities and native MCP role bootstrap
crates/capsem-mcp-aggregator/ Low-privilege subprocess: connects to external MCP servers
crates/capsem-mcp-builtin/ Stdio MCP server for built-in tools (HTTP)
crates/capsem-agent/ Guest PTY agent + net-proxy + dns-proxy + mcp-server + sysutil + tun pump (musl)
crates/capsem-app/ Thin Tauri desktop shell (points at gateway)
crates/capsem-tray/ System tray (polls gateway, quick actions)
crates/capsem-proto/ Shared protocol types (host-guest, service-process IPC)
crates/capsem-logger/ Session DB schema, queries, async writer
crates/capsem-guard/ Companion lifecycle primitives (parent-watch + flock singleton)
crates/capsem-bench/ Benchmark harness, ships as capsem-bench-rs (guest musl + host)
crates/capsem-mock-server/ Hermetic mock upstream (HTTP/TLS/WS) for tests and benchmarks
web/app/ Astro 7 + Svelte 5 + Tailwind v4 + owned semantic CSS
web/marketing/ Marketing website (Astro + Svelte 5)
web/docs/ Documentation site (Astro Starlight)
build_system/builder/ capsem-builder backend and gate implementation
build_system/release_site/ Release channel site generator (Astro, writes cache/target/release/distribution/)
build_system/scripts/ Thin functional command boundaries for build and release tooling
config/ Runtime product config source -- never developer skills (see Skills)
config/docker/image/ VM runtime build inputs (runtime_apt_packages, kernel and rootfs config)
images/ Application OCI images and their catalog (catalog.toml); applications are not part of the VM runtime
guest/artifacts/ Guest scripts and diagnostics (capsem-init, bashrc, tests)
cache/target/assets/ Built VM assets (gitignored, per-arch: cache/target/assets/{arch}/)
web/graphics/ Brand icons and Tauri app icons (source of truth)
skills/ Shared AI agent skills (SKILL.md format)
tests/ Cross-crate suites (ironbank/ black-box gates, citadel/ guards)
citadel/ is source-level and runs in the fast phase: a
recorded mistake must fail before the expensive work, and
each guard carries the reason in its failure message
cache/target/gate-runs/DIGEST.md is the state of the build across recent runs: what
the last run did, which steps keep failing, where the time goes, and what to do
about it. Every gate run regenerates it; uv run --project build_system --frozen capsem-gate runs digest
rebuilds it on demand and uv run --project build_system --frozen capsem-gate runs trend --step <label> follows
one step run by run.
Read it before starting work and before reporting that anything passes. One green run says nothing about a step that fails one time in four, and an intermittent failure is the most expensive kind here precisely because each sighting looks like bad luck.
Skills live in skills/ at the project root. This is the canonical checked-in
developer skill library. Agent-specific discovery may symlink or copy from this
path; runtime product config must not mirror developer skills under config/.
skills/<name>/SKILL.md One skill per directory
Prefix-based grouping: dev-*, build-*, release-*, site-*, frontend-*, meta-*. asset-pipeline covers the build-to-boot asset flow. See /meta-organize-skills for conventions.
Do not put skill source files in .claude/, .codex/, .gemini/, or
config/skills/. Those roots are agent-local settings or product config, not
the developer skill source.
Before code changes, load the relevant project skill from skills/. For tests
and release gates, load /dev-testing and /ironbank. For debugging, load
/dev-debugging. For architecture changes, load /site-architecture.
Skills contain hard-won lessons and project-specific patterns. Before writing or modifying code, load the relevant skill. Skipping skills leads to repeated bugs (e.g., blocking async, serde_json::Value on hot paths, missing VM tests).
| Area | Skill | When to load |
|---|---|---|
| Overview | /dev-capsem |
Orienting on any task, finding which skill to use |
| Quick start | /dev-start |
First-time bootstrap, onboarding |
| Dev setup | /dev-setup |
Environment setup, tool install, troubleshooting |
| Rust patterns | /dev-rust-patterns |
Writing any Rust code in capsem-core/app/agent |
| MITM proxy | /dev-mitm-proxy |
TLS, HTTP inspection, SSE parsing, ai_traffic |
| MCP | /dev-mcp |
capsem-mcp server, MCP gateway, aggregator, builtin, tool routing |
| Use Capsem | /use-capsem |
Agent-facing MCP VM tasks, input/output transfer, static file triage |
| Testing | /dev-testing |
Running or writing tests, TDD, coverage |
| VM testing | /dev-testing-vm |
In-VM diagnostics, capsem-doctor, session DB |
| Hypervisor testing | /dev-testing-hypervisor |
Apple VZ / KVM, VirtioFS, vsock tests |
| Frontend testing | /dev-testing-frontend |
vitest, svelte-check, visual verification |
| Python testing | /dev-testing-python |
capsem-builder pytest, coverage, golden fixtures |
| Session DB | /dev-session-debug |
Inspecting session.db, correlating events |
| Benchmarking | /dev-benchmark |
capsem-bench, performance regression |
| capsem-doctor | /dev-capsem-doctor |
In-VM diagnostic suite, adding new tests |
| Frontend | /frontend-design |
UI components, Svelte 5 runes, Tailwind, owned semantic CSS |
| Build images | /build-images |
capsem-builder, guest config, rootfs, kernel |
| Initrd repack | /build-initrd |
Guest binary changes, fast iteration loop |
| Asset pipeline | /asset-pipeline |
Asset manifest, hash verification, boot-time resolution |
| Just recipes | /dev-just |
Which just command to run for a given task |
| Build/release gate | /dev-gate |
Adding or changing a capsem-gate command; boundary, primitive, or contention guard failures |
| Citadel guards | /citadel |
Adding a guard, a linter, or a source surface; a citadel test failing |
| Debugging | /dev-debugging |
Bug investigation, reproduce-first workflow |
| CI triage | /dev-ci |
Red gates, pr-gate failures, rerun decisions, stop-the-line policy |
| Cache control | /dev-cache |
Cache inventory, retention, reuse, cleanup, or disk/Docker/Colima/Tart cache changes |
| Sprints | /dev-sprint |
Running a multi-step feature sprint |
| Release | /release-process |
CI, signing, notarization, changelog |
| Release gate proof | /ironbank |
Black-box acceptance proof for VM, network, MCP, security, or release-gate behavior |
| Bug queue | /dev-bug-review |
Working a queue of bug reports one-by-one (confirm, push back, fix, commit) |
| Installation | /dev-installation |
Setup wizard, service registration, self-update, install tests |
| Architecture | /site-architecture |
System design, service architecture, vsock, key files |
| Docs site | /site-infra |
Writing/editing docs, Starlight, sidebar, release pages |
| Marketing site | /site-marketing |
Marketing website (capsem.org), copy, components, theme |
| Skills system | /dev-skills |
How skills work, naming, discovery |
| Skills layout | /meta-organize-skills |
Skills directory conventions, symlinks |
| Skill discovery | /meta-find-skills |
Finding or installing skills from the ecosystem |
| Skill authoring | /meta-skill-creation |
Creating, improving, or evaluating skills |
- Thin Tauri webview shell -- only IPC commands are
log_frontend,open_url,dump_frontend_logs, andget_gateway_connection. No VM logic, no capsem-core dep. All UI state flows through the gateway. Desktop IPC pairs its strict loopback origin and bearer from privategateway.port/gateway.tokenfiles under the selected runtime directory (installed default port 19222). - The frontend is embedded in the Rust binary at cargo build time via
tauri::generate_context!(). Runningpnpm run buildalone does nothing to a compiled binary. After any frontend change meant for the desktop app, runjust build(frontend build +cargo build -p capsem-app). The toolbar showsbuild <timestamp>-- if it's stale, you forgot to rebuild the Rust binary. - Iframe
srcfor bundled pages must be explicit (/vm/terminal/index.html). The Tauri custom protocol on macOS does not auto-appendindex.htmlthe way dev servers do.
- Warnings are errors. Fix every compiler/linter warning before considering code done. Never leave warnings. Frontend:
pnpm run checkuses--fail-on-warnings. Rust: the rootCargo.tomlsets[workspace.lints.rust] warnings = "deny"and every crate inherits it via[lints] workspace = true-- clippy and rustc warnings are build failures. New-stable clippy fallout is absorbed by documented allows in[workspace.lints.clippy], not per-file attributes. - Reuse over reinvention. Check
capsem-corefirst. Extend existing abstractions. - Minimize code. Delete dead code, inline single-use helpers. Every line must earn its place.
- Zero-copy first. Move or borrow existing buffers; do not clone, stringify, reparse or re-encode payloads for forwarding. Encode directly into one bounded final frame and derive its length there. Enforce limits during encoding and before receive allocation, without a separate sizing pass. This applies to terminal, graphical, gateway, guest and ledger paths. Preserve ownership and safety; document and measure any unavoidable payload copy.
- Hashing and JSON require a documented reason. Internal data transport is
typed binary MessagePack. Never expand binary bytes into JSON for admission,
sizing, hashing or internal IPC. A hash must name the actual integrity,
authentication, deduplication or compatibility contract it proves; a checksum
supplied by the same potentially compromised owner is not independent proof.
JSON needs an external protocol, documented persisted format or another
concrete requirement. Record the reason beside the owning implementation and
exercise that contract. Convenience, debugging and speculative tamper detection
do not justify adding work to a hot path. See
/dev-rust-patterns. capsem-coreis the shared library. Service, process, CLI, and agent crates are thin shells. Business logic lives in core.- One way to do things. Don't introduce a second pattern when one exists.
- Rust tests live in a sibling
tests.rs. In the parent module declare#[cfg(test)] mod tests;and put all#[test]functions intests.rsnext to it. Never append an inlinemod tests { ... }block at the bottom of a production file -- it buries prod code under scroll-past test fixtures and doubles the file size for every Read and grep. See/dev-testing.
Capsem's quality, security and performance are the responsibility of every coding agent working in it, not of whoever owns the area. They are P0, not something to trade for a smaller diff. See something, say something, do something.
When the work turns up a defect -- a bug, a lint or type violation, a failing guard, a stale path, a vulnerable dependency the audit flags -- fix it and commit it in the same session, in its own well-scoped commit. Do not stop to ask permission for a routine, low-risk, behavior-preserving fix, and do not route it to a follow-up ticket by default: a green gate is the bar, and the agent that found the problem is the one to fix it. This holds even when the defect predates your change or sits just outside the immediate task; the gate runs the whole tree, so the whole tree is your responsibility once you are in it.
The same holds for improvements you notice while coding, not just outright
defects: a fragile path, a small refactor that makes the code clearer, a way
to make it faster or more reliable. Do not walk past it as not your problem.
If it is small, fix it test-first (a failing test, then the change -- see
/dev-testing). If it is too big to fold into the current change, say so and
open a GitHub bug (or ask to) with enough detail to act on, rather than
dropping it silently.
A vulnerability is the strongest case of this rule, not an exception to it.
When you find one -- a guest-to-host path, an auth or policy bypass, a leak,
a missing no-follow -- fix it now, in this session, test-first, as its own
security: commit, even when it sits outside the task you were given. Do not
park it waiting for a decision, and do not describe an unfixed vulnerability
in a public issue: the fix, its test and the CHANGELOG entry are the report.
Tell the user what you found and what you changed while you do it.
Stop and ask only when the fix is genuinely a judgment call: it changes user-visible behavior, would weaken a security boundary (closing one is never a reason to wait), forces a real scope expansion, or picks between options a maintainer should choose (for example a dependency major-version bump, or suppressing an advisory instead of upgrading). The one advisory exception that needs no approval is RELEASE.md's time-boxed rule: no patched release exists anywhere, the package is build-time only in a dependency we do not control, and the entry expires within 30 days. State the finding and your recommendation, then act on the answer. A trivial patch bump, a lint fix, a stale-literal cleanup: just do it and say what you did.
Everything is ephemeral unless asked otherwise. VMs are temporary by default. Named VMs (capsem create -n <name>) are persistent -- workspace and rootfs overlay survive stops. capsem create is always detached; capsem run is the one-shot that destroys its VM on exit; capsem shell opens the TUI over existing sessions and creates nothing.
VirtioFS mode (default): fresh workspace + sparse rootfs.img per session. Persistent VMs store their session in ~/.capsem/run/persistent/.
Block mode (legacy): mke2fs unconditional at boot. Overlay upper is always tmpfs.
All guest binaries deployed chmod 555 (read-only). Rootfs mounted read-only. Guest cannot modify its own binaries.
The binary must be codesigned with com.apple.security.virtualization or VZ calls crash. The justfile handles this.
Any direct development command that can block, build, launch children, or wait on input must run through:
python3 build_system/scripts/ci/run-bounded-command.py --timeout-seconds <finite> -- <command>
The wrapper closes stdin and owns a process group so timeout or interruption
cannot leave a Docker client, compiler, test runner, or helper behind. Do not
use it around just test or either release command: the gate's config-owned
timeouts, journal, resource teardown, and resumable graph remain authoritative.
Routine bounded commands do not acquire the global machine lock. Keep finite
timeouts and process-tree cleanup, use Cargo's own build coordination, and
continue writing code while focused checks run. Do not wait behind a broad gate
for ordinary compilation or local TDD. The wrapper's --machine-lease option
is reserved for an explicitly selected isolated measurement or qualification
fixture; it is not the default development path. Complete qualification and
release commands retain their own locking and exact-source isolation.
Release authority is RELEASE.md. Start there, then load
/release-process for operational routing and hard-won implementation lessons.
The public entrypoints are:
just release-binaries <channel> <source-commit>
just release-assets <channel> <source-commit>
Agents use these entrypoints rather than dispatching release workflows or authoring manifests directly.
A release is one branch, proven locally, then shipped. Every fix for a
release goes on one branch (release/<version>) as its own commit, with the
CHANGELOG updated in those commits. Run just test <branch-head> on this
machine and keep fixing on the branch until it passes. Only then fast-forward
main to that exact commit and run the release command on it. Never dispatch
a release to find out what is broken: the hosted lane takes hours per attempt
and stops at the first failure, so it finds one bug per attempt. The 0.6.4
stable release spent four dispatches, one per bug, that a local run catches in
minutes. Nothing runs in CI that just test has not run locally first.
The one escape is the release command's force argument, which the user
asks for explicitly: it waives the local journal, never the citadel guards,
release contracts, live advisory audit or hosted qualification.
A proof covers the tested commit and any commit with the identical Git tree.
Fast-forward main to the tested commit (or merge only when the merge commit's
tree equals it); anything else merged in needs its own proof, so do not merge
anything else into main while its proof runs. Low-impact repeats are refused before expensive work and routed
to focused owners; just test <source-commit> force "<reason>" is the audited
exception and cannot be used twice consecutively. Direct release commands and just test own their timeouts,
journal, teardown, and network boundary; do not wrap or nest them.
Implementation-specific invariants belong beside their executable tests and in
the routed release references. If prose here disagrees with RELEASE.md, fix
the routing instead of creating another release model.
Telemetry and security ledgers are database-owned.
- Service routes, UI handlers, MCP helpers, and benchmark harnesses must not
call
rusqlite::Connection::openorDbReader::opendirectly. - They must not create service-owned logged-data projection caches.
- Whether a ledger changed is the DB object's answer (
read_cache_epoch, the reader'sdata_versionsync), never the file's size or mtime: a WAL-only commit changes neither, and a route once served stale rows for months on that fingerprint.tests/citadel/test_db_freshness_boundary.pyholds it. - They may own query intent, but the logger DB object owns query execution.
capsem-loggerowns SQLite connection threads,mem/disk table layout, batching, flushing, WAL tuning, and future FTS5/search.- Do not hardcode route-specific query helpers in
DbWriteras a substitute for this boundary. The DB object is an execution/storage owner, not a route semantics registry. write(event).awaitmeans the event was accepted into the DB-owned producer buffer. Tests that need read-after-write visibility must use the DB flush barrier or shutdown/reopen; route code must not sleep, poll, or build a projection cache to make ledger rows appear.- Empty table means empty result. Missing table or column means broken schema and must fail loudly; do not add compatibility branches that treat missing ledger shape as empty data.
Every change touching logged data needs tests that guard this boundary.
Every first-party Rust cryptographic operation goes through capsem-crypto,
including build scripts, tests, and SDK code. Do not depend on or import raw
hash, random, certificate, JWT, signature, constant-time or secret-erasure
providers elsewhere. TLS configuration may use rustls transport types, while
provider selection and key operations belong to capsem-crypto::tls.
Use BLAKE3 for new internal content fingerprints. Preserve SHA-256 wherever
OCI, OAuth, release manifests or existing persisted identities require it;
the owner supplies CPU-dispatched AWS-LC rather than a per-caller SHA backend.
An algorithm identity change is a format migration, not a performance patch.
Benchmark candidates on the actual CPU and I/O path before changing defaults.
tests/citadel/test_crypto_boundary.py rejects direct providers and renamed
dependencies, and the hot-build guard keeps hashing optimized in dev builds.
Every host syscall, file-descriptor operation and guest-writable filesystem
access goes through capsem_foundation::unix. It is the one testable surface
between Capsem and the kernel, so it is where no-follow, CLOEXEC, EINTR and
errno handling are proven once instead of re-derived at each call site.
- Application crates never call
nixorlibc. If foundation lacks a primitive, add it there, with tests, and call it. - Anything a guest can write -- the VirtioFS share, a workspace, a system
image -- is reached through
unix::contained::ContainedDirdescriptors, never by path. A path is followed at open time, and a guest can swap any entry for a symlink between a check and a use. - Inside foundation,
nixmakes the syscall. A rawlibc::call is kept only wherenixcannot express it, with the reason recorded.
tests/citadel/test_unix_boundary.py holds all three: an exact inventory of
raw references outside foundation, an exact inventory of raw calls inside it,
and adversarial cases for the spellings that used to slip through. Load
/dev-rust-patterns before touching either.
The justfile dispatches; src/capsem/gate/ decides. No recipe carries a shell
body and none exceeds five lines, both held by contract tests rather than
convention.
Checked-in first-party scripts have the same architectural backstop. New
scripts may not exceed [boundary.scripts].max_lines; larger historical files
are an exact line-count debt ratchet, not an exemption list. Split growth before
merging, and lower or remove a ratchet whenever a script shrinks. The guard
only inventories Git-tracked program sources under the configured first-party
roots, so generated outputs and vendored dependencies are outside its scope by
rule.
just test is one process, one machine lock, one workspace, one plan.
Its dry run reports the current totals; conditional asset staging makes a
checked-in count depend on machine state. A passing run for the exact commit
is required before that commit is released.
Six rules, each with a guard:
- A plan action may never invoke
justor anothercapsem-gatecommand.GuardedRunnerrefuses it at runtime. The machine lock is not reentrant, so every such call was a child waiting out its 7200-second timeout for the lock its own parent held. Compose the other command'sfragmentinstead. - Work is composed from primitives.
actionsandfileactionsare the only modules that touch the machine, alongside the four that own one piece of machine state as their whole purpose. Anything else going around them is work the dry run cannot show and the run log cannot time. - Ordering is declared, then derived. A step names what it must follow;
graphlibdecides the sequence. A cycle fails before any step runs. Never sequence by writing oneplan.addabove another. - Contention is declared in
[execution.exclusives], with the reason. Two steps can be independent and still unable to share the machine. - Teardown is
held(...)-- acquired in order, released in reverse, evidence preserved before release. Afinallythat removes a directory is aResourcethat was not written. - Every value lives in
config/gate.toml. No path, filename, architecture or channel name in code.
Two more, which follow from the first:
- A plan describes; it does not act.
plan()is built with the machine sealed, so--dry-runcannot touch it -- and inspection is answered before any re-exec, or asking becomes doing. - Anything that writes takes the machine lock.
[execution.exclusives]entries arethreading.Locks: they order steps inside one plan and coordinate nothing between twocapsem-gateprocesses.
One gate runs per machine, enforced by flock rather than a pidfile, and every
run is recorded under cache/target/gate-runs/ and bounded by the
stages.gate-runs cache contract. The run log
is written by the runner rather than by call sites, so nothing can be forgotten
into invisibility.
Read /dev-gate before changing any of it.
- glowup = installed-package release proof owned by
just test: Linux runsbuild_system/scripts/release/local-release-glowup.pyin Docker/systemd; macOS installs the signed exact package in Tart and boots it through physical Apple VZ. - winterfell = service session-ledger lifecycle fixtures in
crates/capsem-service/src/tests.rs; AGENTS.md's gate list refers to these. just testwrites benchmark recordings undercache/target/tests/benchmarks/; intentional historical publication uses the owning benchmark command and explicit review.- Rust is pinned to 1.97.1 in
rust-toolchain.toml, bootstrap, CI, and Docker. Bump every surface together in a deliberate monthly toolchain PR and handle new-lint fallout there. - Bare
python3on macOS is 3.9 and gives wrong answers (phantom syntax errors, silently dead hooks). Run repository Python withuv run --project build_system --frozen python. - Never
cdinto a subdirectory in an agent shell. The working directory persists across calls, and a worktree session cannot move it back: onecd crates/.../srconce left every later shell call, subagents included, failing its PreToolUse hook. Use absolute paths,git -C, or(cd dir && ...)in a subshell. Agent hooks in.claude/settings.jsonrun underuvfor the same reason, and resolve their scripts fromgit rev-parse --show-toplevel-- the checkout the session works in -- not$CLAUDE_PROJECT_DIRalone: in a worktree session that names the main checkout, and when it sat on an older commit without the hook script every Bash call failed until restart. - A same-size mutation of a Python test file can be served from a stale
.pyc. Cleartests/__pycache__before trusting a mutation-and-restore check. - Processes under any Seatbelt profile cannot exec setuid binaries:
/bin/psfails. Use syscalls, and prove sandbox fixes undersandbox-exec. - A failing
kingslandingtest reproduces in about two minutes by running its one pytest file in the latestcache/worktrees/<run>; re-sign rebuilt binaries ad hoc with the virtualization entitlement. - Red CI is usually per-job provisioning, not code. Check the environment before changing source.
tokio-unix-ipccloses a descriptor before deregistering it, which lost IPC replies under churn (#209). Write the churn stress test before believing an IPC hypothesis.
How to spend effort and the shared machine. Each one is a mistake that already happened.
- Write code, verify locally, qualify by phase. During implementation use TDD and only the focused tests, formatting, type or lint checks necessary for the changed files and behavior. Do not run whole crates, workspace/Citadel suites, VM/install lanes or benchmarks as a routine per-commit ritual. At each major phase boundary qualify its complete outcome; before merge or release run the authoritative final proof on the exact source. Iterate on failures with the smallest reproducer. Record incomplete proof honestly and keep independent implementation moving.
- Use the most focused lens that proves the change. A handful of VM tests run directly with pytest in the latest
cache/worktrees/<run>, against the assets that run already built (minutes). A subsystem uses itsfocus-test <owner>(kingslandingfor containers,assetsfor a guest rebuild).focus-test functional --slowruns once, on the final head; a two-hour lane between five-line changes is how a sprint stops moving. If no owner fits, ask the user before adding one. - A narrow suite is not verification.
tests/test_gate_*.pyalone misses what the contract suites catch; the final run is the whole suite. - A guard must not fake what it guards. Stubbing the input under test makes the test green by construction.
- Measure before and after, twice. Establish the noise floor by running the unchanged code twice before blaming a difference on a change. Performance work reports both runs side by side.
- Polled API reads stay in milliseconds. Info, stats and status routes are what the TUI, tray and web poll. A memory or disk fix never buys itself a slower poll: record the reader benches before and after, keep an idle poll well under 1 ms, and index a slow query instead of caching it in RAM.
- Check real exit codes. Use
pipefailand$?; never judge a run throughgrep-filtered output. - Shared builds, local checks. Every checkout builds into the main checkout's
cache/target/cargo. Run Cargo through the bounded wrapper for timeout and cleanup, without a routine machine lease. Do not set a privateCARGO_TARGET_DIR; retain cross-checkout reuse. Do not diagnose build contention by restarting sccache or serializing agents through chat. - Never kill by pattern.
pkill -fwith options parsed as extra patterns once killed every user process. Process control is a tested Python module acting on exact pids. - Work in your assigned worktree. Editing the main checkout once killed a running release at
source.verify. One agent commits in a worktree at a time. - Never
git stashto inspect. Read old content withgit show <rev>:<path>; a stash pulls uncommitted work out from under running builds. - One crate per commit, paths staged explicitly.
- Follow-ups are GitHub issues with file references and a fix sketch, never notes left in an agent's scratch space.
- Update
CHANGELOG.mdin the same commit when the change is user-visible. Refactors, test-only changes and internal cleanups do not need an entry. This used to read "every commit", which 39 of the last 100 did not do -- a rule nobody follows teaches that the neighbouring rules are advisory too, and the neighbours here are the DB boundary and the release contract. - Stage files explicitly (no
git add -A) - Conventional subject,
type(scope): summary. In use:feat,fix,refactor,perf,test,docs,chore,style,security,merge. - Author: Elie Bursztein github@elie.net
- No
Co-Authored-Bytrailers
Boot sequence instrumented with tracing spans. RUST_LOG=capsem=debug for full timing, RUST_LOG=capsem=info for top-level.