Cordis Redesign — YAGNI Ladder (Phase -1, Step 3)
Date: 2026-08-20
Commit: e4f3bcc (11 workspace crates + ares-server root)
Rule: rust-safe-large YAGNI ladder — walk each crate before writing any new crate. No code change in this step.
Workspace at e4f3bcc
| Crate | Lines (rs) | Files | Deps (key) | Description |
|---|---|---|---|---|
| ares-types | 1,980 | 4 | axum, utoipa, chrono, serde | TenantTier, tenant models, shared API types |
| ares-config | 6,135 | 5 | toon-format, toml, arc-swap, notify, reqwest, aes-gcm | TOML/TOON config, 110 KB toml_config.rs, fleet_secrets, nvidia_catalog |
| ares-db | 23,019 | 30+ | sqlx, libsql, qdrant, lancedb, lance, chromadb, pinecone | DB + vector store clients, 20+ modules (tenants, skills, schedules, runtime_*) |
| ares-llm | 13,503 | 13 | async-openai, arc-swap, parking_lot, futures | LLM clients, provider_registry, pool, coordinator, capabilities |
| ares-agents | 9,460 | 15 | ares-llm, ares-tools, ares-db | Agent registry, resolver, configurable, orchestrator, research, memory |
| ares-tools | 7,797 | 18 | daedra, scraper, boa_engine, rmcp, arc-swap | Built-in tools, registry, runtime_registry, mcp_bridge, connectors/* |
| ares-mcp | 6,772 | 8 | rmcp, reqwest, toon-format | MCP client/server, registry, auth |
| ares-rag | 8,627 | 6 | fastembed, text-splitter, lancor, lru | Chunking, embeddings, search, reranker |
| ares-vector | 4,440 | 8 | hnsw_rs, anndists, scc, memmap2 | Pure-Rust HNSW, published crate 0.1.2 |
| ares-auth | 902 | 2 | jsonwebtoken, argon2 | JWT + argon2 only |
| ares-memory | 1,291 | 1 | chrono, serde | Single-file LRU session store |
Total workspace Rust ≈ 88k lines (excluding src/ root ~190KB admin.rs etc. + crates/ares-vector published).
Decisions
Keep as standalone crate (justified)
-
ares-types — KEEP. Cross-cutting types used by all crates (
TenantTier, API DTOs). 1,980 lines is above noise threshold, and it has axum/utoipa dependencies that leaf crates need without pulling the whole server. Workspaceversion.workspaceensures single version. -
ares-config — KEEP but split internally. 6,135 lines, cross-cutting, but
toml_config.rsalone is 110 KB per plan (currently split acrosstoml_config.rs/toon_config.rs/nvidia_catalog.rs/fleet_secrets.rs). YAGNI: keep as one crate (config is a coherent domain), but Phase 5 must split by domain (server,auth,providers,tools,agents,workflows,rag,billing) behindServicetraits — not as separate crates, as modules. Do not create 8 config crates. -
ares-db — KEEP but modularize internally. 23k lines is the workspace's largest crate, but it is the DB boundary (traits + implementations for postgres/turso/vectors). Splitting into
ares-db-postgres/ares-vector-storeswould be premature — the 6 backends sharetraits.rsand transaction logic. Instead, enforce feature-gated modules (postgres,turso,qdrant, etc.) and plan Phase 3 to replace polling reload withFiber::refresh. Do not merge intoares-server— DB belongs at leaf. -
ares-llm — KEEP. 13.5k lines, provider-agnostic LLM abstraction, client pool, observability. Touches every agent execution path. Needs its own crate to isolate
async-openai/ollama-rsdeps behind features and to ownProviderRegistry→LlmServicemigration. Keepopenai,ollamafeatures. -
ares-tools — KEEP. 7.8k lines, tool registry + runtime registry + connectors. Distinct from agents/llm, owns execution semantics (
Tooltrait,Arc<Tool>). Will becomeToolServicein Phase 5 that composes static + runtime + MCP. -
ares-rag — KEEP. 8.6k lines, RAG pipeline (chunker, embeddings, reranker, cache, search). Distinct vector dependency path (
lancor,text-splitter,fastembed). Keep alongsideares-vector. -
ares-vector — KEEP. 4.4k lines, published crate
ares-vector 0.1.2with its own README/license, useshnsw_rs/anndists/scc. Already versioned independently and excluded from the build gate (defaultbut not incargo check --no-default-features --features openai,postgres,mcp). Must remain leaf crate — do not merge.
Merge (below YAGNI threshold)
-
ares-auth (902 lines, 2 files) — MERGE into new
ares-coreor keep as leaf but question justification. Currently JWT + argon2 only, no DB, no config. Ladder: a standalone crate needs ≥2 consumers with distinct feature sets or a publishable boundary.ares-authis consumed only byares-server(middleware) andares-types(claims). YAGNI says merge intoares-runtime/ares-core(proposedcrates/ares-contextorcrates/ares-core). Decision: Merge intoares-core(new leaf crateares-cordis-core/ares-contextwill absorb auth traits) or intoares-serverroot if no core crate is created. For the redesign, auth becomes aService(JwtService) provided viaContext, not a crate boundary. Path: re-exportjsonwebtoken/argon2behindJwtServiceinares-core, deprecateares-authwithpub use ares_core::auth::*for one release if needed, then remove. No client-specific logic — confirm generic. -
ares-memory (1,291 lines, 1 file) — MERGE into
ares-agentsorares-core. Currently a singlelib.rsLRU session store (ConversationMemory,MemoryStore). No independent versioning, no external deps beyondchrono/serde. YAGNI says a 1-file crate is ceremony. Decision: Merge intoares-agents(where it is already consumed viaares-agents/src/memory/*andcontext_provider.rs) or intoares-coreasMemoryService. Thelru = "0.16.3"dep moves with it. Delete crate boundary; keep moduleares_agents::memory(already exists) and promoteSessionMemoryServiceas aService.
Borderline — keep with conditions
-
ares-agents (9,460 lines) — KEEP as standalone, but do not let it absorb memory. It already has
ares-memoryas dep (circular pressure). After mergingares-memory,ares-agentsbecomes the orchestration crate. Consider whetherresearch/,orchestrator,loop_detectorbelong inares-runtime. YAGNI: keepares-agents(orchestration is distinct from tool/provider execution), but the newAgentExecutionService(Phase 4) should live inares-agents, notares-context, to keep business logic out of the generic context primitive. -
ares-mcp (6,772 lines) — KEEP with deprecation path to merge into
ares-tools. The plan flagsToolRegistry/RuntimeToolRegistry/McpRegistryfragmentation (P4).ares-mcpduplicates tool abstractions (McpRegistry,McpTool). Ideal:ares-mcpbecomes a feature ofares-tools(mcpfeature already exists inares-tools/Cargo.toml→dep:ares-mcp). Ladder says keep as crate for now (MCP usesrmcp0.12.0 with distinct transport), but Phase 5 must unify behindToolServicesoares-toolsowns the trait andares-mcpis just a bridge implementation. Do not create a new crate; do not merge yet — prove theToolServicecomposition first, then evaluate post-spike whetherares-mcpstays or collapses intoares-tools/src/mcp_bridge.rs.
New Crates (per plan)
-
ares-cordis-core / ares-context (spike) — CREATE as leaf crate per Phase 1, Step 8. Zero internal ARES deps, only
tokio,thiserror,tracing,anymap/hashbrown,arc-swap. This is the Cordis primitive crate (Context,Fiber,Effect,Disposable,EventsService,RegistryService,Loader). It is not a merger target — it is the new foundation. YAGNI: start ascrates/ares-cordis-core(orcrates/ares-context) with ~1–2k lines, nolibloadingHMR, no WASM. Stub file-watch →Fiber::reload(). -
ares-runtime / ares-core (potential) — DEFER. Only create if
ares-auth+ares-memorymerged need a home that is notares-serverand notares-cordis-core. The plan mentionsares-runtime/ares-coreas optional absorbers for small crates. YAGNI says do not pre-create — first prove the spike (Phase 1) and theAppState→Contextmigration (Phase 2 step 12) can absorbares-auth/ares-memorywithout a new crate. If AppState decomposition reveals a shared service layer, then introduceares-runtimein Phase 2 as needed.
Anti-Decisions (explicitly not doing)
- Do not create
ares-config-domains(8 crates for server/auth/providers/tools/agents/workflows/rag/billing) — that is Phase 5 module split, not crate split. - Do not create
ares-db-postgres/ares-db-vectorssplits — feature flags suffice. - Do not create
ares-providers/ares-workflowscrates — currentares-llm+src/workflowsboundary is sufficient; engines becomeServices, not crates. - Do not merge
ares-vectordespite small size — it is published and has distincthnsw_rsdeps andrust-version = "1.75"(vs 1.91 for workspace).
Ordering
Phase -1 decision is log only. Implementation order for Phase 1–2:
- Create
crates/ares-cordis-core(leaf, no ARES deps) — proves Context/Fiber theorem. - Merge
ares-memoryintoares-agents(orares-core) after spike — oneState<AppState>shim commit, then delete crate. - Merge
ares-authafter spike —JwtServiceinares-cordis-core. - Keep all other 9 crates (types, config, db, llm, agents, tools, mcp, rag, vector) as-is; internal module splits happen in place.
Verification
- No code changed in this step — decision log only (this file).
cargo check --no-default-features --features openai,postgres,mcpmust still pass oncordis-redesignafter this doc commit (it will — doc-only change).