Guidance for coding agents working in this repository.
just check # Run all local verification checks (CI parity)
just fmt # dprint check (TOML + Markdown + Rust)
just lint # cargo clippy --workspace -- -D warnings
just hawk # unnecessary public API visibility (macOS and Linux)
just test # cargo nextest run + cargo test --doc
just build # cargo build --workspaceTests run via cargo nextest (process-per-test isolation); doctests run
separately via cargo test --doc since nextest does not run them.
Requires protoc installed for protobuf compilation (firma-protobuf and
firma-grpc-interceptor-proto both compile .proto files via
tonic-prost-build against a system protoc).
dprint is the single formatter for the repo. Run dprint fmt after modifying
.toml, .md, or .rs files. just fmt runs dprint check in CI.
docs-site/ is excluded and uses its own toolchain.
Workspace lints are strict and enforced in CI:
clippy::pedanticwarnclippy::unwrap_useddenyclippy::expect_useddenyclippy::panicdenyunsafe_codedeny
Do not use .unwrap(), .expect(), panic!(), or unsafe. Prefer
Result<T, E> with thiserror for error handling.
Rust APIs in crates whose Cargo metadata resolves to publish = false are
internal implementation details, even when their items are declared pub for
workspace use. Do not report visibility reductions, removals, or signature
changes in those crates as SemVer-breaking changes. Still update all workspace
callers and verify the workspace.
Review user-facing compatibility separately. CLI behavior, configuration and file formats, network and wire protocols, and documented integration contracts may be stable boundaries regardless of a crate's publish setting.
Before adding or moving Rust tests, load and follow the
rust-tests-guidelines skill.
Before adding or changing CLI, deterministic E2E, live-agent, or VS Code
coverage, load and follow the
writing-black-box-tests skill.
OpenFirma supports only Unix and Windows targets. When implementing
platform-specific behavior, use #[cfg(unix)] and #[cfg(windows)] code paths.
Do not add fallback, no-op, passthrough, stub, or compile_error! code for
unsupported targets. It is acceptable for unsupported targets to fail naturally
due to missing platform-specific implementations.
Some contributors use Git, some use Jujutsu.
- Invoke
jjfrom the working copy to determine whether the local clone uses Jujutsu; do not infer this by inspecting the filesystem for.jj/. - If the
jjprobe succeeds, preferjjcommands for history, diff, conflict resolution, and changeset manipulation. - If the
jjprobe fails because the clone is not a Jujutsu workspace, use Git. - Do not assume every clone uses
jj; detect the active VCS before choosing commands. - When giving user-facing revision identifiers or instructions, match the VCS actually in use in that clone.
Whenever the working copy is already dirty or you are about to touch revision history, use the repository skills instead of improvising:
commit-guidelinesfor dirty-worktree inspection, atomic checkpoint commits/changesets, and reviewed-history preservationopen-prfor opening GitHub pull requestssplit-jj-changesetfor splitting mixed Jujutsu changesetsverifyfor per-revision and final verification
Use commits or jj changesets as local checkpoints during substantial work. Prefer small atomic revisions that can stand on their own when feasible.
Before implementing any behavior or architecture change, load and follow the
planning-changes skill. It determines
whether formal planning applies and, when it does, selects a Full or Compact
workflow and defines the evidence-backed design-plan artifact. Full triggers
take precedence over both Compact planning and no-plan exemptions regardless of
the expected size or locality.
Accepted plans and findings must have a durable, team-accessible repository path
or URL; do not rely on an agent or private conversation as the handoff.
Use adversarial-review to select an
independent reviewer. It routes plan reviews to
reviewing-plans and implemented changes to
reviewing-changes, with
review-rust-code added for Rust changes.
Plan review does not replace post-implementation review.
OpenFirma is an L7 policy enforcement sidecar for AI agents. Every outbound agent call passes through the Sidecar before reaching external systems.
firma-core— shared types and trait contracts such asDecision,ExecutionEnvelope,CapabilityClaims,TokenVerifier,TokenSigner,PolicyEvaluator, andRevocationStore. No dependencies on other crates.firma-audit-schema— behavior-freeDecisionandExecutionEventtypes shared by audit producers, tests, and third-party JSONL consumers.firma-protobuf— gRPC wire contract via protobuf, vendored in-tree atcrates/firma-protobuf.build.rscompiles.protofiles withtonic-prost-build. Owns thefirma.v1.EnforcementDecisionenum (AARM R4: ALLOW/DENY/ABORT/MODIFY/STEP_UP/DEFER).firma-grpc-interceptor-proto— the agent↔sidecar interceptor hook proto, separate fromfirma-protobuf(Authority↔Sidecar contract).firma-sidecar— enforcement proxy binary. Key top-level modules:interceptor— captures outbound agent traffic.normalizer— maps raw HTTP requests to canonicalExecutionEnvelopevalues with normalized action classes. Unclassifiable protected actions fail closed to DENY.enforcement— two-stage engine: capability validation, then constraint enforcement.pipeline— orchestrates normalizer and enforcement through a singleenforce()entry point.
firma-authority— local/dev Authority reference implementation. Issues PASETO v4 tokens and streams policy bundles and revocations. Never on the hot path.firma-config-loader— sharedfirma.tomldiscovery, schema loading, and agent profile parsing used by the CLI and runtime crates.firma-secret-provider— secret-provider spec types (IntegrationSpec:Cli/Httpvariants), the built-inIntegrationRegistryof CLI vault specs, the extraction engine (CompiledMatcher,SecretPlaceholder), and the sharedendpointmodule:unix:///tcp://ClientEndpoint/ServerEndpointtransport addresses used by thegatewayandbrokermodules. Thestoremodule owns the run-scoped placeholder↔secret dictionary (SecretStore, moved here fromfirma-run). Thegatewaymodule holds theGatewayRequestwire types, theGatewayClienttransport (resolve_batch/push_secret), and theGatewayListenerserver that serves the same protocol from theSecretStore, for the Sidecar↔broker secret-gateway protocol. Thebrokermodule holds the out-of-sandbox secret-shim transport:BrokerClient(shim-side) andBrokerListener(broker-side) speaking a newline-terminated JSON protocol overunix://(Unix) ortcp://loopback (Windows), plus the sharedBrokerConfig. Shared byfirma-run(CLI vault shims, viasecret_providersconfig) andfirma-sidecar(HTTP vault MITM interception, via the mirroredhttp_secret_providersconfig). Depends only onfirma-coreandfirma-httpamong Firma crates.
- Fail closed: every error becomes a DENY decision.
- No network on the hot path: enforcement is fully local.
- Deterministic enforcement: same context plus same policy bundle yields the same decision.
- Immutable execution envelopes: treat
ExecutionEnvelopeas immutable once created.
The normalizer's host/method/path to action-class mapping is loaded from TOML
at startup by startup::pipeline::build_pipeline_runtime.
[enforcement.mapping] supports:
rules_path: String— primary mapping file, defaulting tomapping-rules.toml.rules_paths: Vec<String>— additional mapping files merged on top.
Rules from rules_path and each entry in rules_paths are concatenated before
passing to MappingTable::from_config. Duplicate (method, host, path) tuples
across merged files fail at startup.
Shipped mapping files live under crates/firma-sidecar/config/mappings/:
github.tomlstripe.tomlgmail.tomlcomposio.toml
After any major behavior, architecture, CLI, configuration, or public API change,
update the docs site under docs-site/ in the same change set. If the change
affects how people should discover or integrate OpenFirma, update
docs-site/public/llms.txt as well.
Write docs for a human reader first:
- Start from the user's task or question, not from internal implementation order.
- Keep prose concise, concrete, and free of marketing filler.
- Prefer small examples, commands, and links to related pages over long theory.
- Name important invariants explicitly: fail closed, no network on the hot path, deterministic enforcement, and immutable execution envelopes.
- Document sharp edges and operational gotchas when they affect real use.