This file is the canonical repo-level contract for Codex, Claude Code, Cursor, and other coding agents. Use it for repo-wide coding conventions, path routing, and stable coordination shapes.
AGENTS.mdis the canonical repo-level contract for all coding agents. It owns repo-wide invariants, coding conventions, routing, and the stable coordination shapes below.docs/workflows/rust-ai.mdis the canonical workflow for task setup, split, handoff, and integration.docs/guides/*contains lazy-loaded reference guidance. Open only the file that matches the current task, red flag, or lint failure.docs/rules/*contains tool-neutral entry rules used through tool-specific symlinks.- If two documents disagree:
AGENTS.mdwins overdocs/workflows/*,docs/guides/*, anddocs/rules/*, which win over crateREADME.md/CONTEXT.md, which win over tool-specific shims.
- Minimal magic and hidden dependencies.
- Predictability, testability, and reproducibility.
- Components should stay loosely coupled and replaceable.
- Code is the source of truth. Each crate keeps
README.mdas an overview; longer contracts and invariants belong in the owning crateCONTEXT.md, and project-wide architecture lives incrates/kithara/CONTEXT.md(symlinked from the rootCONTEXT.md).
- No speculative code. Do not add helpers, branches, or abstractions that are not used by the current task.
- Workspace-first dependencies. Add versions only in the root workspace and reuse existing crates when possible.
- Shared media types live in
kithara-stream. Do not duplicateAudioCodec,ContainerFormat, orMediaInfoelsewhere. - Do not use
unwrap()orexpect()in production code without a strong, explicit reason. - Name the canonical owner before changing shared state, shared types, or cross-crate contracts. If the owner is unclear, stop and clarify before implementation.
- Do not introduce parallel mutable sources of truth without an explicit transition contract. When old and new state must coexist temporarily, use a staged ownership transfer in the task packet or plan.
- No fallback chains (
try A, else B, else C) to paper over state-resolution bugs. A fallback is a code smell: if the primary path has no correct answer, the underlying state contract is broken - fix the contract, not the symptom. Legitimate fallbacks (user-facing defaults, optional config, degraded-mode operation) must be explicitly justified in the owning crateCONTEXT.mdor the task packet. Tests that codify fallback behaviour protect symptoms and should be treated as evidence of a root-cause bug. - Prefer generics and composition over near-duplicate protocol-specific types.
- Use
tracing, notprintln!ordbg!, in production code. - Do not use destructive git commands unless the user explicitly asks for them.
- Cancel-token hierarchy is typed and propagate-down. Hard-coded
CancelToken::root()andCancelToken::never()are forbidden outside sanctioned owner sites. Seedocs/guides/cancel-policy.mdonly when touching cancellation. - Zero-tolerance for lint suppressions and baseline growth. Unavoidable lint means STOP and fix the underlying code. See
docs/guides/lint-policy.mdonly when touching lint policy or a lint exception. - Prefer clean, maintainable code over clever shortcuts or speculative abstractions.
- Keep code readable and easy to understand.
- Optimize for performance in hot paths.
- Use repo harnesses for acceptance and formatting:
cargo xtask test/just testandcargo xtask format. Rawcargo test,cargo nextest, or direct formatter commands are scoped probes only, not final validation claims.
Reject a design before coding when it:
- Has no canonical owner for touched state, shared types, or cross-crate contracts, or creates multiple mutable sources of truth.
- Masks state-contract bugs with fallback, retry, sentinel, or workaround branches.
- Crosses platform, protocol, surface, test, or crate-layer boundaries without owning the contract.
- Widens public API or adds ad-hoc Rust shapes instead of standard traits, domain types, config, or builders.
- Uses
Arc<...>, especiallyArc<Atomic*>, as ownership glue instead of an owner, command, or snapshot model. - Introduces shared mutable god-state, globals, god objects, callback spirals, or unrelated responsibilities in one file, type, trait, or facade.
- Requires a lint suppress, new baseline entry, or "temporary" bypass to pass.
- Declare dependency versions only in the root
Cargo.tomlunder[workspace.dependencies]. - Reference dependencies from crates with
{ workspace = true }. - Do not add duplicate or overlapping crates when the workspace or standard library already covers the need.
- Do not add temporary dependencies without a real need.
- Do not pull in a heavy crate for a small utility without checking cost first.
- If a new dependency is unavoidable, justify it in the task, plan, or PR description and add it to
[workspace.dependencies]first.
- Keep production code in
src/and substantial fixtures intests/. - Keep
useimports at the top of the file. Do not placeuseinside functions, methods, or blocks. - Prefer short readable names in the body over repeated deep qualified paths.
- Full paths are acceptable only when they clearly improve readability, such as resolving a name conflict.
- Default visibility is
pub(crate). Public named-field types exposed across crates should be#[non_exhaustive].
- Choose the simplest and shortest names that still describe the real meaning.
- Prefer standard, obvious words such as
open,new,get,put,read,write,seek,stream,send, andrecvwhen they fit. - Avoid clever or overly long names that encode implementation history instead of meaning.
- Keep in-code comments short and local.
- Do not add large comment blocks at the top of files.
- Do not restate the obvious in comments.
- Contracts, invariants, lifecycle, protocol, or cache explanations belong in the owning crate
CONTEXT.md; theREADME.mdstays an overview that points to it. - No separator comments, banner comments, or ad-hoc style variants that conflict with workspace lint rules.
- Do not let a single
.rsfile grow into a dump of abstractions. - Extract large types, big
implblocks, or distinct subsystems into their own files or modules. - Prefer
mod.rsplus focused sibling files over one oversized source file. lib.rsandmod.rsshould contain only module declarations and re-exports.
src/is for production code, not for a growing fixture warehouse.- Large fixtures, local servers, generated content, and multi-step scenarios belong in
tests/. - Small unit tests and tiny helpers under
#[cfg(test)]are fine next to the code.
- Behavior changes should be driven by tests that describe the intended contract.
- Tests must be deterministic.
- Tests must not depend on the external network.
- Tests should capture the contract, not an incidental implementation detail.
- Test logs and generated data should stay at a reasonable size.
- Prefer standard and
tokioabstractions when they fit instead of inventing near-identical custom traits. - Extend behavior through type parameters, traits, and composition instead of copy-paste specialization.
- Do not create near-duplicate HLS and file types when the difference can be expressed generically.
- Avoid large "god traits". Prefer several smaller traits with clearer ownership.
- New items should be
pub(crate)unless they are part of a documented public contract. - Do not use bare
pubfor internal helpers or implementation details. - When promoting something to
pub, verify that it is intentional, documented, and covered by tests.
- Public enums and public named-field structs exposed across crate boundaries should be
#[non_exhaustive]. - Small, obviously stable exceptions are allowed when extension is unlikely and direct construction is part of the intended contract.
- Shared types such as
AudioCodec,ContainerFormat, andMediaInfolive inkithara-stream. - Before introducing a new shared type, search the workspace and reuse an existing canonical type when possible.
- Keep cache, network, orchestration, decode, and playback responsibilities separate.
- Avoid circular dependencies.
- Dependencies should point downward toward base abstractions, not back upward into higher-level orchestration.
- Facade layers may aggregate components, but should not hide "smart" logic that belongs lower in the stack.
- External code must not depend on internal cache layout or a specific HTTP client unless that is explicitly part of the contract.
- Respect workspace-wide config such as
rustfmt.toml,clippy.toml,deny.toml,.config/tomlfmt.toml,.config/typos.toml, andsgconfig.yml. - Change lint policy in the shared config files instead of creating per-crate drift unless there is a strong reason.
- The pre-commit hook expects clean formatting, linting, and tests. If they fail after your change, assume your change caused it until proven otherwise.
- Treat
rustcwarnings (for exampleunused-imports,dead_code,deprecated, unfulfilled#[expect],unreachable_pub) the same as Clippy: fix the cause in code you touch - remove dead code, update imports and APIs, replace deprecated items - rather than leaving warnings to accumulate. - Prefer fixing the cause of a compiler or Clippy warning (correct types, control flow, dependency or API change) over silencing it. Do not add
#[allow(...)], file-level#![allow(...)], or other lint suppressions unless there is no reasonable code-side fix; if you must suppress, document why in the owning crateCONTEXT.mdor in a short comment on the same item.
- No separator comments such as
// ====. - Import names at the top of the file rather than using inline qualified paths in function bodies.
lib.rsandmod.rsshould contain only module declarations and re-exports.- Cargo manifests stay sorted by
cargo-sortwith internalkithara/kithara-*dependencies first; non-Cargo TOML, JSON, and Markdown stay formatted by Rust-native tooling.
- Errors should be typed and include context about what failed and on which resource.
- Logs should be useful and should not leak secrets.
- Use
tracingfields for context such asasset_id,url,resource,variant,segment_idx,bytes,attempt, ortimeout_ms. - Do not leave temporary prints in production code.
- Any public API change should come with tests that capture the contract.
<task_packet> Goal: Affected paths: Read first: Same-as example: Constraints: Non-goals: Expected output: Validation scope: Split proposal: </task_packet>
<split_policy> Prefer split execution when write boundaries are explicit and independent.
Every split task must define:
- owned paths per agent
- forbidden paths per agent
- required reads per agent
- sequencing dependencies
- one integrator owner
Do not split when two agents would contend on the same file, the same shared type, or the same unresolved design boundary. </split_policy>
<handoff_contract> Done: Remaining: Touched paths: Decisions made: Validation: Open risks: </handoff_contract>
<final_report> Changed files: Commands run: Risks or follow-ups: </final_report>
- Start from a task packet when the task is non-trivial, shared, or likely to benefit from explicit coordination.
- Small single-owner tasks with a clear boundary can proceed directly without a task packet.
- Treat a non-trivial task packet as incomplete until
Constraints,Non-goals, andValidation scopeare filled in. - Keep the primary acceptance target explicit in the packet or plan and revisit it after local fixes.
- Read only the repo docs and crate
README.md/CONTEXT.mdfiles that match the owned paths. - The stable task packet, handoff, and final report shapes live here. Do not create parallel template docs for them.
- If a task needs a plan, follow
docs/workflows/rust-ai.mdanddocs/plans/_template.md. - Load
docs/guides/*files only when the task, a red flag, or a failing lint points to that topic. - Load
docs/guides/tooling.mdonly when touching formatter, lint, dependency-audit, or external-tool policy. - Load
docs/guides/test-harness.mdonly when adding/debugging tests or reporting validation scope. - Load
docs/guides/agent-hooks.mdonly when touching tool adapters, hooks, or command routing. - Load
docs/guides/performance.mdonly when optimizing a hot path, cutting allocations, or triaging a perf regression. - If shared boundaries are unclear, stop and clarify before implementation.
- Keep debate procedures, investigation journaling, and TDD choreography out of
AGENTS.md. Put that guidance in workflow docs or owningCONTEXT.mdfiles. - Do not restate the same repo rule in tool-specific files. Tool-specific files should only route the agent to canonical docs and scoped domain guidance.
- If a product requirement conflicts with these rules, discuss the compromise first and update
AGENTS.md. - Any forced rule bypass should be explained briefly in the owning crate
CONTEXT.md.