Workspace map
Dependency rules (strict)
These are enforced by the build:cognis-corehas zero internal-crate dependencies.cognis-llm,cognis-rag,cognisgraph,cognis-traceeach depend only oncognis-core(andcognis-macroswhere they use a derive). They do not depend on each other.cognisis the only crate that depends on the four siblings together.cognis-macrosis proc-macro-only; consumed by everything that wants the derives.
cognis-core).
Where new code goes
Agent orchestration middleware (filesystem, memory, subagent, planning, skills, todo, prompt caching) belongs in
cognis. Agent policy building blocks (retry, rate limiting, PII, redaction, model fallback) live in cognis too — they share the same Middleware trait.
Design patterns (mandatory)
These shape every feature in the codebase. Follow them when adding new code.Traits, not classes
Each capability is a trait with a small required surface and generous provided defaults. NewMemory impls implement read/write/clear and inherit seed. New RateLimiter impls implement acquire(estimated_tokens) and inherit the policy combinators.
When adding a new variant of an existing trait, mirror the builder methods and naming of its siblings. A new Memory variant ships with_system(...) because the others do.
Builders return Self
with_X(self, x) -> Self. Constructors don’t take optional args — promote them to builder methods.
Enums for closed sets
Where Python uses union types or magic strings, Rust uses enums with exhaustive matching. Examples:Message, ContentPart, ToolChoice, StreamMode, Goto, Durability.
Generic Runnable, not Value-typed
Runnable<I, O> is generic — never Value-typed at trait boundaries. Use serde_json::Value only at system edges (user input, persistence, wire serialization). Heterogeneous composition uses type-erased wrappers (DynRunnable).
Errors are actionable
Each crate below the umbrella defines its own error type viathiserror. Cross-crate errors use From conversions — cognis_graph::Error wraps cognis_core::CognisError.
The umbrella cognis crate does not depend on thiserror directly. When adding a new error type there, hand-roll Display and Error.
Async by default
All I/O-bound trait methods areasync via #[async_trait]. No sync compat layer; callers use block_on if they need to.
Feature flags for optional deps
Every external integration is behind a feature flag. The core crates compile with no network deps. New providers, vector stores, and exporters all gain a feature.Code quality rules
- All public types, traits, and functions get
///doc comments. - No
unwrap()orexpect()in library code — propagate errors with?. - No
println!in library code — usetracingmacros. - Clippy passes:
cargo clippy --workspace --features all-providers -- -D warnings. - Format with
cargo fmtbefore every commit. - New public API gets at least one unit test and one doc-test.
What NOT to port from Python
See also
Adding a provider
The walkthrough for a new LLM client.
PR guidelines
The PR checklist that maps to these rules.
Reference → cognis
The umbrella’s re-export surface.