This file provides guidance specifically for AI agents (and humans) working on this codebase. Read AGENTS.md first for full architecture, project structure, and design principles. This file supplements it with practical details, gotchas, and quick references.
make build # Debug build (fast, use for iterating)
make test # Run all tests
make lint # Check formatting + clippy (CI runs this)
make fix # Auto-fix formatting + clippy issuesAlways run make lint before submitting changes. CI will reject PRs that fail lint.
- Edition: Rust 2024 (
edition = "2024"in all Cargo.toml files) - MSRV: 1.91 (set in all three package Cargo.toml files)
- No rust-toolchain.toml - uses whatever stable/beta toolchain the developer has installed
- Note:
CONTRIBUTING.mdsays "Rust 1.90 (nightly)" — this is outdated. The actual MSRV is 1.91 from Cargo.toml.
Cargo.toml # Workspace root (resolver = "2")
packages/
orb-cli/ # Binary: `orb` (publish = false)
orb-client/ # Library (publish = false, designed as standalone)
orb-mockhttp/ # Mock server library (publish = true)
orb-client must NEVER import from or depend on orb-cli. This is the most important architectural constraint.
- Adding verbose output? Add a new
ClientEventvariant inpackages/orb-client/src/events.rs, then handle it inpackages/orb-cli/src/verbose_events.rs. - Adding error handling? Use
OrbErrorvariants inorb-client, map to user-friendly messages viafatal!inorb-cli. - Never use
fatal!inorb-client— it's a CLI macro. UseOrbErrorand propagate with?.
Both orb-client and orb-mockhttp use aws-lc-rs as the TLS crypto provider:
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();The let _ = is intentional — subsequent calls return Err if already installed, which is fine. Never .unwrap() this call.
Test dev-dependencies use ring for the HTTP/3 test server (quinn with ring feature). This is an intentional mismatch — don't try to "fix" it.
The fatal! macro uses eprintln!, which adds \n. All test assertions against stderr must include the trailing newline:
assert_eq!(stderr, "Failed to read CA certificate 'bad.pem': No such file...\n");
// ^^Any test using TestServerBuilder::new().with_tls().build() needs --insecure on the orb command (or the test must provide the server's self-signed cert via server.cert_pem()).
orb-client defaults to use_system_cert_store: false (uses bundled Mozilla roots). The CLI always sets use_system_cert_store(true) in request.rs. Be aware of this difference when writing library-level vs CLI-level tests.
RequestBuilder::send() internally calls HttpClient::builder().build() each time. This is by design for the CLI (one request per invocation). Don't assume connection pooling.
Every TestServerBuilder::new().build() binds to port 0 (OS-assigned random port). Never hardcode ports. Use server.port() and the {PORT} placeholder pattern for test_case.
Error messages from the OS differ between platforms. Use normalize_os_error() from testutils/mod.rs when testing error output that includes OS-level errors.
The project uses inline snapshots (not .snap files):
use insta::assert_snapshot;
assert_snapshot!(sanitize_output(&output), @r"
GET / HTTP/1.1
accept: */*
user-agent: orb/0.1.0
host: 127.0.0.1:<PORT>
");Set INSTA_UPDATE=always to auto-update snapshots during development.
When following redirects cross-host (different scheme, host, or port), these headers are stripped unless --location-trusted is used:
AuthorizationCookieProxy-Authorization
Status codes 307/308 preserve method and body; 301/302/303 downgrade to GET with empty body.
The CookieJar uses the psl (Public Suffix List) crate to:
- Reject cookies with public-suffix domains (e.g.,
.com,.co.uk) - Reject IP address domain attributes
- Require response origin to match cookie domain
The same PSL check runs in headers.rs when loading cookies from file.
--insecuremode usesInsecureServerCertVerifier(accepts all certs)TlsCapturingConnectorwraps the TLS connector to emitTlsHandshakeCompletedevents- Client cert and CA cert validation happens in CLI layer (
cli.rsvalidation functions)
Triggers on changes to packages/**, Cargo.toml, Cargo.lock, or the workflow file itself.
Jobs:
- Test: Matrix of
{ubuntu, macos, windows}x{stable}+ubuntux{beta}. Runsmake releasethenmake test. - Lint: Ubuntu stable. Runs
make lint(format check + clippy with-D warnings). - E2E: Only on
release/*branches or manual trigger. Runsmake test-e2e.
Triggers on v* tags. Builds cross-platform binaries and uploads to GitHub Releases + Cloudflare R2.
| Function | Purpose |
|---|---|
sanitize_output(output) |
Normalizes ports → <PORT>, dates → <DATE>, boundaries → <BOUNDARY>, version → orb/0.1.0 |
sanitize_error(output) |
Normalizes IP:port patterns in error messages |
null_device() |
Returns /dev/null (Unix) or NUL (Windows) |
normalize_os_error(error) |
Maps Windows error messages to Unix equivalents |
parse_args(input) |
Shell-style arg parsing respecting quotes |
test_server() |
Pre-configured server with /test, /echo, /raw routes |
- Add field to
Argsstruct inpackages/orb-cli/src/cli.rs - Add validation function in
cli.rsif needed - Call validator from
packages/orb-cli/src/main.rs - If client-level: add to
HttpClientBuilderinpackages/orb-client/src/http_client.rs - If request-level: add to
RequestBuilderorpackages/orb-cli/src/request.rs - If response-level: add to
packages/orb-cli/src/output.rs - Add tests in
packages/orb-cli/tests/options.rs(usetest_casefor parameterized tests) - Run
make lintbefore committing
- Add variant to
ClientEventinpackages/orb-client/src/events.rs - Emit the event at the appropriate point in
orb-clientcode - Handle the event in
VerboseEventHandlerinpackages/orb-cli/src/verbose_events.rs - Add tests verifying the verbose output