Imported from yexrob/bingo (
AGENTS.md). Install upstream withnpx skills add yexrob/bingo. Copyright stays with the author.
AGENTS.md — bingo
A local coding-agent harness in Rust: a minimal kernel, everything else a plugin, one ordered event stream that every surface (TUI, --print, JSON-RPC, ACP, IM channels) consumes as a client. Map: ARCHITECTURE.md (crate map), docs/adr/ (boundary decisions), docs/plans/ (one plan per milestone), docs/design/ (the design and research the plan came from).
Language and style
- Rust 2024,
thiserrorfor library errors,anyhowonly at the binary edge.unwrap/expectare lint errors outside tests;unsafeis forbidden. - Write code the way the surrounding code is written. Names carry meaning; comments say only why.
- One responsibility per function, one per module. A function does one thing at one level of abstraction: a match arm that grows a body becomes a function, a loop body that decides and acts becomes two. A module owns one noun; when it owns two, split it. Split eagerly — a small function with a good name costs nothing, a long one hides its second job.
scripts/check_discipline.shwarns at 60 lines per function and fails at 120. - Model-facing text, UI copy, docs, tests and commit messages are English.
- No new dependency without a line in the ADR or plan that justifies it and a
scripts/budget.shrun.cargo deny checkmust pass.
Architecture rules
- Layering
sdk ← core ← plugins/surfaces ← bin. The kernel never imports a plugin. No plugin imports another plugin except through a service trait registered via the sdk. No crate but the TUI surface depends on ratatui/crossterm.scripts/check_discipline.shasserts these (ADR-0001). - One event stream.
bingo_sdk::Eventis the only event type. Surfaces are clients: they fold frames withSessionState::applyand derive their views at render time. No private mirror enums (ADR-0002). - One fact, one representation. Never carry a value alongside the thing it derives from. If a fix requires "remember to update it everywhere", it is debt, not a fix; prefer the change that makes the mistake unrepresentable.
- Contracts first for anything consumed independently: a trait, a wire format, a persisted record gets its fixture or schema test before its implementation.
- Bricks first. Pure function → primitive → component → feature. A feature without a pure brick underneath is suspect.
- Subtract by default. Deleting needs no reason; adding does.
- Tool properties fail closed: an unknown tool is not concurrency-safe, not read-only, and not trusted. It has no say in what an interrupt does: one
escends the turn and every call in flight is dropped where it stands. - The kernel owns no feature nouns.
room,team,hire,task,experience,scheduledo not appear inbingo-sdkorbingo-core. - Every platform the release ships. Linux, macOS and Windows all build; the release matrix is the list. A platform-only API is
cfg-gated together with its counterpart, written in the same change — a process group on unix is a job object on Windows, and a signal a program may answer has no Windows spelling at all, so there it is a kill. The constant, the helper and the test that belong to one platform carry the same gate. - A machine is not the machine. Assume nothing a developer's box happens to provide: not that a signal exists, not that a wait status is POSIX, not that
TMPDIRis long, not that a core is free. A test that pins a wall clock, a path length or a scheduling order pins the machine it was written on, and CI is slower, has fewer cores and a shorter temporary path.
Verification
- Every change passes
cargo fmt --all -- --check,cargo check --workspace --all-targets --locked,cargo clippy --workspace --all-targets --locked -- -D warnings,cargo test --workspace --locked,scripts/check_discipline.sh,scripts/budget.sh. - User-visible CLI/RPC behaviour has black-box coverage (exit status, stdout purity, NDJSON validity). Terminal-byte changes have a
TestBackendtest and the PTY smoke. - A change that touches a process, a path, a signal or a clock is checked against the other platform before it is called done:
cargo check -p <crate> --all-targets --target x86_64-pc-windows-msvcfinds a unix-only API without a Windows machine. CI'swindowsjob is the backstop, not the first look. - A milestone is done when its plan's exit criteria are ticked with command output pasted. Unverified work is not called complete; failures are reported as they are.
Records
- ADR: one per boundary decision, ≤120 lines, template in
docs/adr/README.md. Bug fixes are commit bodies. - Plan:
docs/plans/M<n>-<slug>.md, ≤150 lines, written before code: Goal / Bricks / Files / Exit criteria / Non-goals / Risks; a Verified section is appended at the end. scripts/check_discipline.shwarns above either length and never fails on one: the records already written are history, and history is not rewritten to satisfy a check added after it.
Commits
Conventional Commits, imperative, subject ≤60 characters, English, no literary titles. Scopes are crate short names: sdk core provider-fake provider-anthropic provider-openai provider-acp tool-fs tool-bash tool-web print rpc tui permissions hooks store context persona skills mcp agents teams rooms tasks demo-ui experience plugin-rpc schedule acp channels bin ci docs adr. Body only when it carries information; footers Refs: ADR-0002, Plan: M0.
Pull requests
Target dev by default. Use main only when a change explicitly needs the release branch.
Forbidden
unsafe; unwrap/expect outside tests; a surface holding session state; a plugin importing another plugin or the kernel; a second representation of an existing fact; a feature noun in the kernel.
