Coodra Docs
v 0.5.14 Contribute GitHub ↗
Coodra · Documentation · v 0.5.14 · 2026

Supercharge your coding agent.

Coodra is a local-first plugin architecture for AI coding agents: native agent plugins install Coodra MCP, the lifecycle_event hook tool, managed Graphify, recipes, Deep Wiki, durable memory, and policy governance so sessions start with context and end with evidence.

Audience
Engineers · Architects · Contributors
Read time
Quick start in 5 min · Full read ~45 min
License
Apache-2.0 · open source · local-first
/01 — Foundation

What Coodra is, in one breath.

Read first
~3 min

A coordination layer between human architects and AI coding agents — Claude Code, Codex, Cursor, Devin, Antigravity, and MCP-speaking clients. It runs locally, installs through native plugins, and routes lifecycle events through Coodra's MCP (Model Context Protocol) server.

/ plugin

Native agent plugins

Generated plugin bundles install the Coodra MCP server, the lifecycle_event hook tool, managed Graphify MCP entry, and task skills for context, recipes, wiki, Work Packs, and graph-aware development.

Claude · Codex · Cursor · Devin · Antigravity
/ memory

Context Packs

Context Packs, decisions, Work Packs, wiki pages, recipes, and run history live in SQLite/Postgres. Agents see a manifest at boot, then pull the specific memory they need through MCP tools.

Measurable pull-through, not prompt stuffing
/ guardrail

Policy enforcement

Pre-tool-use checks, kill switches, native advisory rules, and audit rows keep humans in charge. Coodra returns a verdict only when it has a rule; otherwise the agent's native permission system remains authority.

Fail-open engine · append-only audit

/01.1Design principles

Five things that are true everywhere in the codebase, and that any contribution must respect.

Local-first
Everything useful runs on your laptop first. SQLite is the hot-path store in solo mode and remains the local write path in team mode; sync is asynchronous.
Fail-open
If the policy engine throws, times out, or the breaker opens — the verdict is ALLOW. Coodra never blocks the agent because of its own faults. packages/policy/src/policy.ts — FAIL_OPEN_RESULT
Append-only audit
Policy decisions and decisions records are never updated or deleted. Idempotency keys gate writes. Resumed kill-switches keep the row, just stamp resumed_at. ADR-007
Production-grade
Plugin files, MCP registrations, wiki pages, Graphify artifacts, and package contents are treated as real product surfaces. If a user can depend on it, tests and docs should name it.
Bind to 127.0.0.1
Every long-running process listens on loopback by default. Hooks, MCP HTTP transport, web UI. Nothing exits the laptop unless the operator sets DATABASE_URL.
/02 — Onboarding

Five minutes to your first run.

Solo mode
Zero network

If you have Node 22, pnpm, and a supported agent installed locally, you are a few commands away. Solo mode is the default after coodra init; native plugins carry the MCP and lifecycle wiring.

/00

Confirm the prereqs.

You need Node 22.16.0 (pinned in .nvmrc), pnpm 10.33.0 via corepack, git, and a supported agent installed locally. macOS uses launchd; Linux uses a fallback daemon manager with PID files.

terminal · prereq check
# Versions Coodra pins to
nvm use            # 22.16.0 per .nvmrc
corepack enable    # activates pnpm 10.33.0
node --version    # → v22.16.0
pnpm --version    # → 10.33.0
/01

Install the CLI.

The only published artefact is @coodra/cli. It ships as a self-contained bundle — bring-your-own SQLite native module is rebuilt on install.

terminal · install
npm i -g @coodra/cli
# or, in a workspace:
pnpm add -D @coodra/cli
/02

Initialise the project.

From your repo root, run coodra init. It registers the project under .coodra/, seeds the default policy, creates recipe/wiki/graphify/Work Pack directories, and leaves repo-root MCP config user-owned.

repo root
coodra init
# picks the slug from git remote, asks which IDE,
# defaults to --solo. Use --team to wire Clerk.

# What it creates:
.coodra/config.json   {"projectSlug":"my-app"}
.coodra/manifest.json project registration ledger
.coodra/recipes/      agent recipe workspace
.coodra/graphify/     managed structural graph output
.coodra/wiki/         Deep Wiki grounding + mirrors
~/.coodra/data.db     SQLite primary store
~/.coodra/.env        solo-mode env, ready to grow into team
/03

Start the daemons.

One command brings up the local MCP server and web UI. Native plugins report SessionStart, prompt, tool, compaction, and SessionEnd events through the Coodra MCP hook tool, lifecycle_event. Sync-daemon stays asleep in solo mode.

terminal · launch
coodra start
# → mcp-server   listening on 127.0.0.1:3100
# → web-v2       http://localhost:3001

# Confirm everything's alive
coodra status
coodra doctor          # 12 essential checks (36 with --full)
/04

Open the agent & watch.

Run coodra agent add <agent> or coodra agent repair <agent>, then launch your agent in the repo. SessionStart reaches Coodra through the plugin, opens a runs row, captures base_sha, and returns a compact manifest of recipes, decisions, context, and project state. The agent pulls bodies through MCP when needed.

Visit http://localhost:3001/runs to watch the trace populate live.

→ Next

Now skim Core concepts to understand what's happening under the hood, or jump to the CLI reference for every subcommand.

/03 — Deployment

Two modes. Same primitives.

Mode is a COODRA_MODE
env flag

Solo and Team mode share schema, code, and CLI. The difference is who sees what, and whether the sync-daemon boots.

/ solo · default

Everything on your laptop.

SQLite at ~/.coodra/data.db. Loopback only. Solo-bypass auth — no Clerk, no JWT, just SOLO_ACTOR stamped on every write. The sync-daemon does not boot. Zero network egress.

Best for: individual contributors, OSS hacking, air-gapped envs, contractors with a strict no-cloud policy.

Set: COODRA_MODE=solo
/ team · opt-in

Cloud-synced memory.

Same local SQLite — plus a Postgres + pgvector mirror you operate, plus Clerk for identity. The sync-daemon pushes sync_to_cloud outbox rows and pulls teammates' runs, decisions, and packs back into local SQLite.

Best for: small teams sharing context, multi-laptop developers, BYO-cloud self-host.

Set: COODRA_MODE=team · DATABASE_URL · CLERK_*

/03.1Mode matrix

Capability Solo Team
Local SQLite primary storeYESYES
Native plugin + Coodra MCP lifecycleYESYES
Web UI on :3001YESYES
Sync-daemon bootsNOYES
Clerk auth · JWT verificationBYPASSREQUIRED
Cross-teammate visibilityNOYES
Cross-machine (same user)NOVIA team install
Network egress requiredNONEPOSTGRES + CLERK

Promote a project from solo to team without losing history with coodra team setup → coodra cloud-migrate. The migration is tracked in _migration_attempts with per-row mapping in _migration_map for surgical rollback.

/04 — Concepts

The vocabulary.

Read this once.
It pays back.

These nouns carry the whole system. Internalise them and the rest of the docs read like an implementation map: agent events enter through MCP, memory lives in the database, Work Packs bind issue work to evidence, Graphify supplies the code graph, and the Deep Wiki turns that structure into navigable documentation.

developer vocabulary map
flowchart TD
  Agent["Coding agent"] --> Plugin["Native Coodra plugin"]
  Plugin --> Event["Lifecycle event"]
  Event --> Tool["lifecycle_event MCP tool"]
  Tool --> Run["Run"]
  Run --> Events[("run_events")]
  Tool --> Policy["Policy engine"]
  Policy --> PolicyRows[("policy_decisions")]
  Run --> Memory["Coodra memory"]
  Memory --> Packs["Context Packs"]
  Memory --> Decisions["Decisions"]
  Memory --> Work["Work Packs"]
  Work --> External["External issue or PR"]
  Graph["Graphify code graph"] --> Wiki["Deep Wiki"]
  Graph --> Decisions
  Wiki --> Memory
  Packs --> Future["Future agent session"]
  Decisions --> Future
  Work --> Future
session
An agent-side identifier. One per IDE/agent invocation. Coodra never invents one — it accepts whatever the agent sends. UNIQUE (project_id, session_id) in runs
run
A row in the runs table — agent type, mode, status, base_sha, created_by_user_id, project_id. Bound to a session by get_run_id; reused across get_run_id calls within the same session. One run per session per project
lifecycle event
A normalized event from a native agent plugin: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PostCompact, Stop, or SessionEnd. Events resolve runs, refresh context, check policy, record activity, and finalize evidence.
hook MCP tool
lifecycle_event. The Coodra MCP tool native plugins call for lifecycle events. It is the developer entrypoint for run creation, prompt-time memory refresh, tool policy checks, event recording, compaction bookkeeping, and SessionEnd finalization.
memory
DB-backed, MCP-mediated project knowledge: Context Packs, Decisions, Work Pack links, wiki pages, recipes, manifests, policy teaching, and access telemetry. Coodra records explicit SessionStart manifest and policy-reason push rows, plus pull rows when the agent retrieves memory through instrumented MCP tools.
context pack
A durable markdown summary of one run: what changed, what was tested, what remains open, and what a future agent should know. Stored in context_packs, linked to runs and optionally Work Packs, searchable by MCP, and created by the agent or by SessionEnd lifecycle fallback.
work pack
An issue-bound implementation record under .coodra/work-packs/<slug>/ and the work_packs tables. Work Packs connect external work items from Jira, Linear-style planning tools, GitHub/GitLab, or manual sources to local plan/status, runs, decisions, and Context Packs.
agent recipe
Reusable task guidance, authored by humans or agents in .coodra/recipes/<slug>/. Pulled on demand via list_recipes / get_recipe when a task matches a recipe's trigger — not auto-injected.
decision
A structured architectural choice — description, rationale, alternatives, reversibility — recorded by the agent mid-run. Idempotent on sha256(description)[:32]. Surfaced to later sessions through lifecycle relevance refresh
code graph
The Graphify structural graph managed under .coodra/graphify/out/: graph.json, GRAPH_REPORT.md, and graph.html. It is queried through a separate Graphify MCP server and used for file-neighborhood context, wiki planning, and graph-backed decision lookup.
deep wiki
A two-pass architecture wiki. coodra wiki build creates grounding from source, Graphify, and prior Coodra memory; an agent saves structure and pages through wiki_save_structure / wiki_save_page; wiki_ask retrieves authored pages for future work.
policy
The pre-tool governance layer: kill switches, rules, grants, native advisory projections, path matching, just-in-time decision teaching, and fail-open behavior. If Coodra has no matching rule, it records audit context and leaves authority with the agent's native permission system.
policy decision
An append-only audit row: who asked, what tool, what input, what verdict. Idempotency key pd:{sessionId}:{toolUseId}:{toolName}:{eventType}. ADR-007

/04.1Runs & sessions

A session is what the agent calls itself. A run is what Coodra calls that work. The first call to get_run_id for a session either opens a new runs row, or — if the agent crashed and restarted — finds and resumes the existing one.

session → run binding
// MCP tool: get_run_id  ·  apps/mcp-server/src/tools/get-run-id/
const { runId } = await mcp.call("get_run_id", {
  sessionId: "cc-sess-2026-05-16-8a3f2c",
  projectSlug: "my-app",
  agentType: "claude_code",
});

// First call:  inserts a runs row, returns runId.
// Repeat call: returns the same runId (UNIQUE on project_id, session_id).

Every run_events row, every policy_decisions row, and the eventual context_packs row hang off this runId. run_events.run_id uses ON DELETE SET NULL so PreToolUse events that fire before the run exists still land — they just attach later when the row appears.

/04.2Lifecycle events

Lifecycle events are not user-facing commands. They are the machine-readable contract between a native agent plugin and Coodra's MCP server.

Event Primary Coodra behavior Developer mental model
SessionStartOpen or resume a run, capture base_sha, return session contract and memory manifest.Boot context.
UserPromptSubmitPerform bounded relevance refresh using prompt, file, Work Pack, FTS/BM25, and Graphify signals.Just-in-time context.
PreToolUseEvaluate kill switches and policy rules, then write policy_decisions.Govern before action.
PostToolUseRecord the event, external MCP activity, latency/error metadata, and pull-side memory access where applicable.Evidence after action.
PostCompactAdvance baseline generation; later prompt-time context belongs to the new generation.Keep post-compaction pull-through attribution honest.
Stop · SessionEndFinalize the run, capture diff, write fallback Context Pack, update Work Packs, and trigger safe graph refreshes when available.Close the evidence loop.

The implementation center is apps/mcp-server/src/tools/lifecycle-event/handler.ts, with reusable finalization and memory workers in packages/lifecycle/. The important boundary is that the plugin reports events; Coodra normalizes, records, and answers through MCP.

/04.3Memory model

Coodra memory exists to make future agent sessions start with project history, architectural intent, and task evidence without stuffing the whole past into every prompt.

memory save and retrieval loop
flowchart TD
  Session["Agent session"] --> Save["Save memory"]
  Save --> CP["save_context_pack"]
  Save --> DEC["record_decision"]
  Save --> WP["work_pack_upsert / update"]
  Save --> WIKI["wiki_save_page"]
  CP --> Store[("SQLite / Postgres")]
  DEC --> Store
  WP --> Store
  WIKI --> Store
  Store --> StartSurface["SessionStart manifest surfaces ids and titles"]
  Store --> PromptSurface["UserPromptSubmit relevance refresh surfaces context"]
  Store --> PolicyTeach["Policy reason teaches motivating decisions"]
  StartSurface --> PushRows["push rows: session_start_manifest"]
  PolicyTeach --> PushRows2["push rows: policy_reason"]
  PushRows --> Access[("memory_access_events")]
  PushRows2 --> Access
  StartSurface --> AgentPull["Agent pulls bodies through MCP tools"]
  PromptSurface --> AgentPull
  AgentPull --> Tools["read_context_pack / search / query / wiki_ask / get_recipe"]
  Tools --> Access[("memory_access_events")]
  Access --> Rollups["memory_access_daily / memory_cohorts"]
  Store --> Freshness["memory gardening marks freshness"]
  Freshness --> AgentPull
Purpose

Continuity, not prompt stuffing

Memory gives the next agent the project state it cannot infer from the current prompt: what happened, why decisions exist, which issue is active, what files are implicated, and where the deeper explanation lives.

Storage

DB-backed and MCP-mediated

Solo mode writes to ~/.coodra/data.db. Team mode keeps the same local hot path and syncs to operator-owned Postgres. Agents read and write through MCP tools, not by mutating markdown mirrors directly.

Measure

Usefulness is observable

Coodra records two push channels today — session_start_manifest and policy_reason — plus pull rows from instrumented retrieval tools. Pull-through, stale-at-access share, bytes, latency, and actor breakdowns show whether memory helped or merely existed.

Memory surface How it is saved How it is retrieved What it is for
Context Packssave_context_pack or SessionEnd fallback.search_packs_nl, list_context_packs, read_context_pack.Resume what changed, what was tested, and what remains open.
Decisionsrecord_decision with rationale, alternatives, reversibility, and impact.query_decisions, query_decisions_by_file, prompt-time recent decisions.Preserve why an architecture choice exists.
Work PacksAgent fetches provider state through that provider's native MCP, then persists a local map with work_pack_upsert / work_pack_update.work_pack_status; Work Pack filters on packs and decisions.Resume Jira, Linear-style, PR, or manual implementation work with linked evidence.
Deep Wikiwiki_save_structure and wiki_save_page after grounded authoring.wiki_ask and local coodra wiki ask.Explain subsystems and architecture from source, Graphify, and prior memory.
Recipes.coodra/recipes/<slug>/ plus recipe index metadata.list_recipes, get_recipe, get_recipe_file.Reusable task guidance before work starts.
Policy teachingActive decisions linked to affected paths and policy audit context.Pre-tool policy responses and decision lookup.Teach the agent why a permission prompt or denial matters.

At session start, Coodra can surface a compact manifest and bounded recent context, and that manifest is recorded as session_start_manifest push rows. On prompt submit, it performs a narrower relevance refresh using exact issue/file signals, Work Pack hints, FTS/BM25, and Graphify-backed file-decision lookup; that context is surfaced to the agent, but it does not currently create push rows. The agent then pulls full bodies only when useful, and pull access is recorded from instrumented tool outputs rather than guessed from the prompt.

Freshness is layered on top of memory instead of rewriting it. Gardening can mark a pack or decision stale, unverified, or fresh and can propose repairs, but it does not invisibly edit the historical record. That keeps Coodra useful as both memory and audit trail.

/04.4Work Packs

A Work Pack is Coodra's local, evidence-backed representation of a unit of implementation work. It can mirror Jira, Linear-style planning tools, GitHub/GitLab PRs, or a manual task, but provider reads and writes stay in the provider's own native MCP.

Scope

Issue-bound work state

Lives in .coodra/work-packs/<slug>/ and work_packs. It carries normalized Coodra type/status, provider-native issue type/status, local spec, implementation notes, sync notes, relationships, and metadata.

Provider

Native MCP handoff

The agent fetches fresh Jira or Linear-style planning data through that provider's MCP, then calls work_pack_upsert to persist the local map. Coodra stores provider keys and evidence; it does not own provider credentials.

Resume

Context with evidence

work_pack_status returns local Work Pack state for the agent, while Context Packs and Decisions linked to the same pack show what changed, why, and what remains open.

Moment Agent action Coodra record
ImportRead Jira, Linear-style, GitHub/GitLab, or manual task details through the relevant MCP or local source.external_work_items, work_packs, work_pack_external_links.
PlanWrite implementation notes, relationships, and normalized type/status through work_pack_upsert.spec_markdown, implementation_markdown, sync_markdown, relationship rows.
WorkSave Context Packs and Decisions with Work Pack slugs attached.work_pack_context_pack_links, work_pack_decision_links, latest activity rollup.
RefreshFetch fresh provider state through the provider MCP, then persist updated local state.sync_events, provider status fields, local_ahead / local_only sync state.
ResumeCall work_pack_status, then pull linked packs/decisions/context bodies only when needed.Local resume surface plus memory pull-through telemetry where instrumented memory tools are used.
Rule

Provider MCPs are the authority for external systems. Coodra is the local execution memory: it remembers what the agent understood, what it changed, which evidence is linked, and what should be resumed next.

/04.5Recipes & Context Packs

These three are easy to confuse because all three help an agent continue work. They differ by ownership and time: recipes guide before work, Work Packs scope issue-bound work, and Context Packs preserve after-work evidence.

→ before

Agent Recipe

Human- or agent-authored. Lives in .coodra/recipes/<slug>/. Reusable guidance the agent pulls on demand via list_recipes / get_recipe when a task matches its trigger.

Direction: human → agent.

↔ during

Work Pack

Issue-bound implementation state. Lives in .coodra/work-packs/<slug>/ and work_packs, with links to runs, decisions, Context Packs, relationships, and external work items fetched through Jira, Linear-style, GitHub/GitLab, or manual workflows.

Direction: issue ↔ agent ↔ evidence.

← after

Context Pack

Agent-authored (or lifecycle fallback on session end). One row per run in context_packs with title, content, content_excerpt, meta. Queryable cross-session via search_packs_nl, list_context_packs, read_context_pack.

Direction: agent → future agents.

Memory

Coodra memory is not a prompt dump. SessionStart can surface a compact manifest; the agent then pulls bodies through instrumented tools such as read_context_pack, search_packs_nl, list_context_packs, query_decisions, query_decisions_by_file, wiki_ask, list_recipes, and get_recipe. Work Pack state is retrieved through work_pack_status, but that tool is a resume surface rather than a pull-through telemetry source today.

If a saved pack has source: 'agent' and a new save_context_pack call arrives with the same runId, the response is status: 'idempotent_hit'. Automatically generated packs can be upgraded in place when the agent later provides richer context for the same run.

Sync

Work Packs are provider-neutral on purpose. Coodra does not own Jira or Linear credentials and does not call those APIs directly; the coding agent uses the relevant native MCP to fetch or update the planning tool, then calls Coodra's Work Pack tools to persist the local implementation map and evidence links.

/04.6Code graph & Deep Wiki

Graphify and Deep Wiki are connected, but they are not the same artifact. Graphify maps structure; the wiki explains it.

Graphify

Structural code graph

Coodra manages Graphify output at .coodra/graphify/out/. The current graph provides graph.json, GRAPH_REPORT.md, and graph.html; native plugins wire a separate Graphify MCP server beside Coodra MCP.

Deep Wiki

Grounded architecture docs

coodra wiki build creates grounding.md and job.md from source, Graphify communities, god nodes, and prior recorded work. Pages are saved through MCP and mirrored under .coodra/wiki/<slug>/md/.

For developers, the practical rule is simple: use Graphify when you need structural neighborhoods or dependency paths; use Deep Wiki when you need a human-readable explanation of the subsystem. wiki_ask retrieves authored wiki pages, while Graphify MCP answers graph questions directly.

/04.7Decisions

An ADR-grade record the agent emits when it makes a non-trivial choice: pick an ORM, change a public API shape, defer a refactor. They survive across sessions and surface to the next agent via the UserPromptSubmit event.

MCP tool · record_decision
await mcp.call("record_decision", {
  runId,
  description:   "Use better-sqlite3 instead of sql.js for primary store",
  rationale:     "Synchronous API matches MCP request lifecycle; ~3x faster on writes.",
  alternatives:  ["sql.js", "libsql/Turso"],
  confidence:    "high",
  reversible:    false,
});
// Idempotent on  dec:{runId}:{sha256(description)[:32]}
// Resurfaces on next  UserPromptSubmit  through lifecycle_event relevance refresh

/04.8Policy & kill switches

Two layers of guardrail. Kill switches sit above policy — they're operator-level pauses, evaluated first.

/01
kill_switch_check
Polymorphic (scope, target) — global, project, tool, agent_type. 5s in-process cache. Soft-resume keeps the row.
FIRST
/02
policy.check(event)
Cache-first DB read inside a Cockatiel timeout(100ms) + circuitBreaker(5) fuse. Picomatch path globs. First match wins by priority ASC.
EVALUATE
/03
recordPolicyDecision
Writes to policy_decisions with ON CONFLICT (idempotency_key) DO NOTHING. Async; the hook returns before the write.
AUDIT
/04
return verdict
ALLOW · ASK · DENY — only an explicit rule match returns DENY.
VERDICT
/--
FAIL_OPEN
On breaker open · isolation · timeout · any thrown DB error, returns { decision: 'allow', reason: 'policy_check_unavailable' }.
SAFETY NET

Policy rules match on five axes — event type, tool name, path glob, agent type, and priority. Decisions are append-only. The default policy seed lives in packages/db/src/ensure-default-policy.ts.

/05 — Architecture

Process topology.

5 layers
plugin-first

The primary runtime is plugin-first: agents call Coodra's MCP server, lifecycle events enter through lifecycle_event, and Graphify runs as a separate managed MCP server beside Coodra.

Layer model
L0 · Agent
Claude Code mcp_tool hooks
Codex command hook-runner
Cursor · Devin · Antigravity native plugins
L1 · Protocol
Coodra MCP :3100 · 26 tools · stdio + HTTP
Graphify MCP managed graph.json · structural queries
L2 · Core
Policy engine cockatiel · 100ms timeout
Memory service context · decisions · wiki · recipes
Run recorder events + diff
OutboxWorker SQLite-backed queue
L3 · Storage
SQLite ~/.coodra/data.db · local hot path
.coodra/graphify/out 6948 nodes · 15381 edges · 309 communities
Postgres + pgvector team mode only
L4 · Clients
Web v2 :3001 · Next.js 15
CLI current command tree · 36 doctor checks
Ink TUI coodra ui

/05.1Long-running processes

Process Port Bind DB Started by
mcp-server
26 MCP tools · stdio + HTTP transport
3100 127.0.0.1 SQLite (local) coodra start · native plugins · hook-runner
sync-daemon
Push + pull · kill-switch puller
none n/a SQLite + Postgres coodra start · team mode only
web-v2
Next.js 15 · 56 page/route files
3001 0.0.0.0 SQLite (server actions) coodra start · skip with --no-web

/05.2MCP lifecycle

Exactly what happens between an agent session starting and the final run evidence landing in Coodra.

/01
SessionStart
Native plugin calls lifecycle_event, opens or resumes a runs row, captures base_sha, and returns session context plus a pullable memory manifest.
RUN OPENED
/02
UserPromptSubmit
Adds a bounded relevance refresh when the host supports it: prompt, issue, file, Work Pack, FTS/BM25, and Graphify-backed decision signals.
REFRESH
/03
PreToolUse
Kill-switch check → policy.check → return allow/ask/deny. Outbox writes policy_decisions.
GATE
/04
PostToolUse
Inserts a run_events row with phase, tool name, tool input, outcome.
LOG
/05
Stop · SessionEnd
@coodra/lifecycle marks completion, captures run diff, writes fallback Context Pack, updates Work Packs, and can trigger structural Graphify refreshes on daemon transports.
CLOSE
/06 — Storage

Data model.

33 SQLite tables
36 Postgres tables

Drizzle dual-dialect schemas. Postgres mirrors SQLite for shared product tables and adds cloud-only migration/audit tables. The intentional column drift: context_packs.summary_embedding is vector(384) in Postgres and text in SQLite.

SQLite primary store · grouped tables
Table Purpose Key constraints
projectsProject registry. One durable row per repo slug and org scope.slug UNIQUE · org_id
runs · run_events · run_diffsAgent session envelope, append-only tool activity, and end-of-run diff evidence.UNIQUE (project_id, session_id) · diff PK = run_id
context_packs · decisions · decision_edgesLong-lived memory: run summaries, architectural decisions, supersession, and file/Work Pack/code-graph impact edges.UNIQUE context_packs.run_id · UNIQUE decisions.idempotency_key
memory_access_events · memory_access_daily · memory_cohortsRaw memory access telemetry, daily utilization rollups, and per-item pull-through cohorts.Daily grain includes project_id, day, channel, site, memory_type, actor_user_id
policies · policy_rules · policy_decisionsActive tool policies, ordered rule axes, and append-only PreToolUse audit rows.UNIQUE policy_decisions.idempotency_key
policy_versions · policy_exceptions · policy_grantsPolicy change history, time-bound exceptions, and capability grants.Project-scoped indexes for policy review and enforcement.
controls · control_attestationsImported governance controls and native advisory attestation state.Control-catalog/project indexes.
kill_switchesPolymorphic operator pauses for global, project, tool, or agent-type scopes.idx (resumed_at, scope, target)
featuresAgent Recipe index rows derived from .coodra/recipes/<slug>/recipe.md.UNIQUE (project_id, slug)
wikis · wiki_pagesDeep Wiki structure and page bodies authored through wiki MCP tools.Project/slug and wiki/page indexes.
work_packs · work_pack_*_links · external_work_itemsIssue-bound implementation packs, provider item mirrors, relationships, and links to decisions/context packs.UNIQUE (project_id, slug) · link-pair uniqueness
integration_connections · sync_events · pending_jobsProvider sync configuration, local sync audit, and durable outbox queues.Provider/project uniqueness · queue/status indexes
audit_events · team_invitesGeneral audit stream and HMAC-signed onboarding tokens.Invite jti UNIQUE

/06.1ER summary

foreign-key topology
projects ─1───n─ runs ─1───n─ run_events
   │         │           ├─0/1─ context_packs   (UNIQUE run_id)
   │         │           ├─0/1─ run_diffs       (PK run_id, CASCADE)
   │         │           └─0/n─ decisions       (FK ON DELETE SET NULL)
   │         │
   │         ├──1───n─ policies ─1───n─ policy_rules
   │         │                                │
   │         │                                └─ policy_decisions.matched_rule_id
   │         │
   │         ├──1───n─ work_packs ───n─ work_pack_decision_links
   │         │                        └─n─ work_pack_context_pack_links
   │         │
   │         └──1───n─ wikis ─1───n─ wiki_pages
   │
   ├─ context_packs.project_id
   ├─ policy_decisions.project_id
   ├─ memory_access_events.project_id
   └─ features.project_id (Agent Recipes; UNIQUE project_id, slug)

# Top-level (not FK'd to projects):
kill_switches, team_invites, pending_jobs

# Sentinel projects (seeded at every boot):
'__global__'   ensureGlobalProject()   # events before a real project
'__solo__'     SOLO_ACTOR.orgId         # solo-mode org

# Cloud-only mirrors (Postgres):
_migration_attempts ─1───n─ _migration_map   # migrate resume + rollback
knowledge_audit                              # cloud knowledge audit

/06.2What lives in ~/.coodra/

data.db
Primary SQLite store. 33 Drizzle tables. Override with COODRA_SQLITE_PATH. Managed by coodra db backup / restore
packs/
Per-pack markdown mirror of context_packs rows. Filename: {date}-{sanitised-runId}.md. Gitignored. Useful for grep + AI agent file-side reads
graphify-mcp/
Shared machine runtime for the managed Graphify MCP server. Project graph artifacts live under each repo's .coodra/graphify/out/.
logs/<service>.log
Per-service stderr captured by the daemon manager. Tail with coodra logs <service> --follow
pids/<service>.pid
Fallback daemon manager PID files. On macOS (launchd) this dir stays empty — PIDs come from launchctl print.
config.json
Per-machine identity + mode. Clerk user_id, org_id, deployment mode. Written by init, login, team setup.
clerk-token.json
Verified Clerk JWT claims after coodra login. Consumed by the MCP server identity guard.
.env
Single source of truth for env vars on a laptop. Merged from coodra team setup output.

/06.3Sync & multi-tenancy

In team mode, the sync-daemon pushes outbox rows to cloud Postgres and pulls teammates' rows back into local SQLite — both directions on a 1-second tick.

push
OutboxWorker
Filtered to ['sync_to_cloud']. Every record_decision, save_context_pack, etc. enqueues a paired job that the daemon drains.
LOCAL → CLOUD
pull
team-rows-puller
Pulls runs · decisions · context_packs · run_events cloud → local via ON CONFLICT DO NOTHING. Skips __global__ + __solo__.
CLOUD → LOCAL
pull
kill-switch-puller
Propagates org-scoped pauses to every teammate so a hard stop is global.
CLOUD → LOCAL

Every shared table carries Clerk user attribution: created_by_user_id on runs, decisions, context_packs, policies; paused_by_user_id / resumed_by_user_id on kill_switches. Web-v2 enforces single-tenant via COODRA_EXPECTED_ORG_ID — a deployment refuses to boot without it.

/07 — Reference

CLI commands.

198 CLI source files
36 doctor checks

Every command is a thin shell over a typed core module. Pass --json almost anywhere for machine output. Pass --help for the up-to-date flag list.

/07.1Lifecycle commands

Command What it does Key flags
coodra installInstall or repair machine-level runtime state under ~/.coodra/.--dry-run · --json
coodra initBootstrap a project. Writes project-local .coodra/ config, manifest, recipes, graphify, wiki, and Work Pack directories.--project-slug · --solo · --team · --force · --dry-run
coodra startBring up local runtime services. Picks launchd / fallback manager based on platform.--no-mcp · --no-sync · --no-web · --foreground · --tunnel
coodra stopTear down daemons. --uninstall removes launchd plists.--service · --uninstall
coodra statusHealth snapshot of each daemon + DB.--json
coodra metrics · coodra roiPrint ROI / value KPIs for captured knowledge, reuse, governance, and modeled net value.--project · --json
coodra doctor12 essential checks by default. Add --full for all 36.--full · --fix · --timeout-ms · --json
coodra agentsDetect installed IDEs and confirm native plugin MCP, hook, and skill wiring.--json
coodra agentInstall, repair, remove, or inspect one native agent plugin.add · repair · remove · status · --dry-run · --json
coodra filesInspect or clean files Coodra generated for this project from .coodra/manifest.json.status · clean · --force · --dry-run · --json
coodra logs <svc>Tail ~/.coodra/logs/<svc>.log across platforms.--follow · --lines · --since
coodra upgradeCompares installed version against npm view. Restarts daemons unless --no-restart.--check-only · --no-restart
coodra uninstallRemoves the CLI. --purge deletes ~/.coodra/.--purge · --dry-run

/07.2Data & memory commands

Command Subcommands Use case
coodra projectlist · show · reset · promote · demoteManage which projects Coodra tracks; promote a transient project to active.
coodra runlist · show · cancel · capabilitiesInspect runs, cancel non-terminal sessions, or adjust capability context.
coodra workstatus · show · importManage local Work Pack artifacts under .coodra/work-packs/.
coodra recipeadd · list · show · edit · index · remove · migrateManage Agent Recipes under .coodra/recipes/.
coodra wikibuild · status · list · open · clean · askGenerate, inspect, open, clean, or query the project Deep Wiki.
coodra graphifybuild · status · open · cleanBuild and inspect Coodra-managed Graphify code graph artifacts.
coodra policylist · show · add · enable · disable · sync · catalog · workflowAuthor policy rules, sync policy projections, import control catalogs, and render workflow policy.
coodra templatelist · install <source>Install reusable Coodra templates.
coodra export <runId>—Export a run as markdown · json · html · slack. With --include-audit for the full policy trail.
coodra dbmigrate · backup · restoreDrizzle migrations + snapshot management.

/07.3Team & auth commands

Command Subcommands What it does
coodra login—Browser handoff to Clerk hosted sign-in. Captures JWT via loopback listener.
coodra logout—Clears ~/.coodra/clerk-token.json. --force skips confirmation.
coodra invite <email>—Mints an HMAC-signed invite URL + writes team_invites row in cloud.
coodra orgstatus · switch <slug>Inspect or switch the active Clerk org for this machine.
coodra teamsetup · init · install · join · leave · migrate · login · logoutFull team lifecycle. setup provisions Clerk + DB; install redeems an invite on a second laptop.
coodra pause—Trip a kill switch. Scope = global · project · tool · agent_type; mode = hard · soft.
coodra resume—Un-pause. --id, --all, or scope+target.
coodra cloud-migrate—One-shot SQLite → Postgres migration. Tracked in _migration_attempts with surgical rollback.
coodra ui—Foreground Ink TUI for live triage.
Tip

The coodra team namespace re-exports login and logout as aliases — both coodra login and coodra team login work. The doctor runs 12 essential checks by default; --full runs the 36-check registry under packages/cli/src/doctor/checks/.

/08 — Reference

MCP tools — all 26.

Source of truth
tools/index.ts

Order matches registration order in apps/mcp-server/src/tools/index.ts. Graphify is not folded into this list: native plugins wire it as a separate managed MCP server pointed at .coodra/graphify/out/graph.json.

# Tool Kind What it does
01pingreadHealth check. Returns { pong, serverTime, sessionId, idempotencyKey }.
02get_run_idwriteIdempotently opens or returns a runs row for this (project, session).
03lifecycle_eventwriteCanonical native-plugin event path for SessionStart, prompts, tool use, compaction, and SessionEnd finalization.
04save_context_packwritePersists an agent-authored Context Pack, including Work Pack links and idempotent automatic fallback upgrades.
05search_packs_nlreadLocal keyword search over Context Packs. The agent ranks and synthesizes from returned evidence.
06record_decisionwriteIdempotent durable decision write with file, graph-node, supersession, and Work Pack targeting.
07query_run_historyreadRecent runs, attached Context Packs, issue/PR references, and chronological session history.
08check_policywriteEvaluates policy rules and kill switches, writes audit rows, and defers to native permissions when Coodra has no rule.
09query_decisionsreadCross-session decision history with Work Pack and relationship-aware filters.
10query_decisions_by_filereadFile-impact lookup using decision targets plus Graphify-backed neighborhood matching when available.
11list_context_packsreadPaginated, newest-first Context Pack index with Work Pack-aware filters.
12read_context_packreadFull Context Pack body, metadata, linked decisions, and memory-access instrumentation.
13list_recipesreadLightweight Agent Recipe index from .coodra/recipes/; agents choose what to pull.
14get_recipereadPull-on-trigger recipe body plus supporting file list. Does not inline every file blindly.
15get_recipe_filereadReads one allowed supporting recipe file with path-escape and size guards.
16query_run_diffreadUnified diff plus per-file numstat. Soft failures include analysis_pending, no_base_sha, and git_diff_failed.
17link_run_to_issuewriteBinds the run to an issue key locally. It does not call Jira.
18link_run_to_prwriteBinds the run to a PR/MR reference locally. Provider reads/writes stay in provider MCPs.
19prepare_jira_commentreadAssembles a markdown Jira comment from run evidence. Posts nothing itself.
20wiki_save_structurewriteDeep Wiki pass 1: persists the planned structure and pending page skeletons.
21wiki_save_pagewriteDeep Wiki pass 2: authors one page's Markdown with Mermaid validation.
22wiki_statusreadDeep Wiki progress and resume status.
23wiki_askreadCloud-facing/wiki-store retrieval counterpart to local coodra wiki ask.
24work_pack_upsertwriteCreates or refreshes a local issue-bound Work Pack and external-work-item map.
25work_pack_updatewritePartial local Work Pack editorial patch; marks linked provider items local-ahead for later sync.
26work_pack_statusreadReads current local Work Pack state so agents can resume issue-bound work safely.

/08.1Lifecycle events

Wired by native Coodra plugins and normalized through lifecycle_event. Invalid or unsupported payloads fail softly so the agent can keep working.

Event Handler Side effects
SessionStartlifecycle_eventOpens / resumes run · captures base_sha · returns manifest and recent context
UserPromptSubmitlifecycle_eventBounded relevance refresh using exact, FTS/BM25, Work Pack, file, and graph signals
PreToolUselifecycle_eventKill-switch · policy check · native-permission defer · audit rows
PostToolUselifecycle_eventInserts run_events row and records external MCP activity
PostCompactlifecycle_eventBumps baseline generation; the next prompt-time refresh can surface post-compaction context
Stop · SessionEnd@coodra/lifecycleMark completed · run diff · auto Context Pack · Work Pack update · graph refresh triggers
/09 — Reference

Configuration.

single source
~/.coodra/.env

Defaults are sensible. You usually only need to touch COODRA_MODE, DATABASE_URL, and the Clerk pair. Everything else has a documented fallback.

Required in team mode
Variable Default Purpose
COODRA_MODEsolosolo | team. Controls auth strategy and whether sync-daemon boots.
DATABASE_URLnonePostgres connection string. Required in team mode.
CLERK_SECRET_KEYsk_test_replace_meSentinel value triggers solo bypass; real key required in team mode.
CLERK_PUBLISHABLE_KEYpk_test_replace_meSame sentinel pattern.
CLERK_JWT_ISSUERnoneTenant JWT issuer URL for Clerk JWT verification.
LOCAL_HOOK_SECRETnoneShared secret for X-Local-Hook-Secret header. Required outside solo bypass.
COODRA_EXPECTED_ORG_IDnoneSingle-tenant pin. Web-v2 refuses to boot without it in team mode.
COODRA_INVITE_HMAC_SECRETnoneHMAC signing key for invite tokens.
Tunables
Variable Default Purpose
MCP_SERVER_PORT3100HTTP transport port.
MCP_SERVER_HOST127.0.0.1HTTP bind.
MCP_SERVER_TRANSPORTbothstdio · http · both.
COODRA_WEB_PORT3001Service-manager override for the web-v2 port.
PORT3001Port passed to the Next.js standalone process.
COODRA_SQLITE_PATH~/.coodra/data.dbOverride the SQLite file location.
COODRA_HOME~/.coodraOverride the whole data dir. Used in compose.
COODRA_CONTEXT_PACKS_ROOT~/.coodra/packsWhere Context Pack markdown mirrors are materialised.
GRAPHIFY_OUT.coodra/graphify/outManaged project-local Graphify output for graph.json, GRAPH_REPORT.md, and graph.html.
COODRA_SYNC_TICK_MS1000Outbox + puller cadence.
COODRA_SYNC_LEASE_MS30000Worker lease duration.
COODRA_WEB_URLhttp://localhost:3001Used by CLI login for browser handoff.
LOG_LEVELinfopino level.
Env

The runtime source of truth is the generated machine env under ~/.coodra/.env plus the service manager. For the web app, Coodra resolves COODRA_WEB_PORT and starts Next.js with PORT; the documented default is 3001.

/10 — Operate

Self-host the team stack.

4 services
docker compose

Team mode runs on your own Postgres. deploy/compose.yaml ships the database, migrator, MCP server, and sync-daemon; native agent plugins still keep the hot path local-first.

Service Image Depends on Port
postgrespgvector/pgvector:pg16—${POSTGRES_PORT:-5432}:5432
cloud-migratedeploy/Dockerfile.cloud-migratepostgres healthyone-shot
mcp-serverdeploy/Dockerfile.mcp-servercloud-migrate done${MCP_SERVER_PORT:-3100}:3100
sync-daemondeploy/Dockerfile.sync-daemoncloud-migrate done—
operator path · first deploy
# 1. Clone & build images locally
git clone https://github.com/your-org/coodra
cd coodra
cp deploy/.env.example deploy/.env
# Fill in: DATABASE_URL, CLERK_*, COODRA_EXPECTED_ORG_ID, LOCAL_HOOK_SECRET

# 2. Bring it up
docker compose -f deploy/compose.yaml up -d

# 3. Point laptops at it
#    Each developer runs:
coodra team install <invite-url>
coodra start

/10.1Auth chain & RBAC

The MCP server, web app, and sync daemon share the same identity rules. First match wins.

/01
Solo bypass
CLERK_SECRET_KEY === 'sk_test_replace_me' OR COODRA_MODE === 'solo'. Attaches SOLO_IDENTITY.
solo
/02
Local plugin secret
Compared against LOCAL_HOOK_SECRET. Attaches { source: 'local-plugin' }. Used by generated native plugin callers.
local-plugin
/03
Bearer JWT
Authorization: Bearer <token> → verifyClerkJwt. Required in team mode.
clerk
/--
No match
Returns 401 { ok: false, error: 'unauthorized' }. No further processing.
unauthorized

RBAC has three roles — viewer, member, admin — parsed from Clerk's org:admin/org:viewer (anything else → member). The shared assertCanEdit helper enforces admin-OR-(member + ownership); viewer never edits. Knowledge mutations have their own gate, assertCanAuthorKnowledge.

/11 — Operate

When things break.

First, run
coodra doctor

Every problem in Coodra leaves a trail in ~/.coodra/logs/, in policy_decisions, or in the doctor output. Start there.

/ symptom

Agent never sees Coodra context

SessionStart is not reaching Coodra's MCP lifecycle path. Confirm the native plugin is installed and healthy:

coodra agents reports the target agent fully wired?
coodra status shows mcp-server healthy on 3100?
tail ~/.coodra/logs/mcp-server.log shows native_plugin_lifecycle_event?

/ symptom

Policy denies something it shouldn't

Look up the audit row by idempotency_key = pd:{sessionId}:{toolUseId}:{toolName}:{eventType}. The matched_rule_id tells you exactly which rule fired.

If reason: 'policy_check_unavailable' — the engine fail-opened, never a deny. Check the breaker state in logs.

/ symptom

Sync-daemon can't connect

Symptoms: queue depth climbs in doctor (check 26), nothing appears on teammates' laptops.

Confirm DATABASE_URL reachable from this machine. coodra doctor --full runs cloud-reachability check 24. Look at ~/.coodra/logs/sync-daemon.log for connection errors. Restart with coodra stop --service sync-daemon && coodra start.

/ symptom

web-v2 refuses to boot

Almost always COODRA_EXPECTED_ORG_ID missing in team mode. The middleware refuses to start without it — by design, to prevent any Clerk-authed account in this deployment's Clerk app from reading your team's data.

If set but you land on /forbidden?reason=org_mismatch — your Clerk session is in a different org. Sign out and back in, or run coodra org switch <slug>.

/ symptom

SQLite locked or corrupted

Stop all daemons, snapshot the file, repair:

coodra stop && coodra db backup
sqlite3 ~/.coodra/data.db "PRAGMA integrity_check;"
coodra db restore <snapshot> if needed.

Open an issue with the doctor JSON + log tail.

/ symptom

No run_diff for completed run

query_run_diff returns analysis_pending, no_base_sha, or git_diff_failed. Common cause: the agent operated outside a git repo, or base_sha was unreachable when SessionEnd fired.

Re-trigger with coodra run show <id> --regen-diff after checking out the right commit.

/ symptom

Graphify or wiki context is stale

Check the managed graph first: coodra graphify status. Current managed output lives under .coodra/graphify/out/, not root-level graphify-out/.

Rebuild structurally without LLM spend via coodra graphify build --no-llm, then refresh the wiki with coodra wiki build and the two-pass wiki save flow.

/12 — Contribute

Build & test.

Turbo · Vitest
Biome

A monorepo with Turbo for orchestration, Biome for lint, and Vitest for everything from unit to e2e. CI currently runs six jobs: Linux verification/integration/e2e, cross-platform hook-adapter smoke, and two Windows smoke lanes.

/12.1Install & build

workspace bootstrap
nvm use            # 22.16.0 per .nvmrc
corepack enable    # pnpm 10.33.0
pnpm install
pnpm rebuild       # native modules: better-sqlite3 + sqlite-vec

# Day-to-day:
pnpm build         # turbo run build
pnpm typecheck     # turbo run typecheck
pnpm lint          # biome check .
pnpm lint:fix
pnpm --filter @coodra/cli build  # tsc + esbuild bundle

/12.2Test tiers

Command Runner Needs
pnpm test:unitVitestnothing — runs entirely in-process
pnpm test:integrationVitestPostgres + Redis service containers
pnpm test:e2eVitest · testcontainersDocker · fileParallelism: false · 120s hook timeout
pnpm test:functionalbash__tests__/functional/run-all.sh · 13 shell scripts

/12.3CI jobs

/01
verify
migration-lock check (packages/db), lint, typecheck, unit. No services.
ubuntu
/02
integration
Builds @coodra/* in dependency order, then runs pnpm test:integration against postgres + redis containers.
depends → verify
/03
hook-adapter-smoke
Runs scripts/hook-adapters/__tests__/smoke.sh on both ubuntu and macos.
parallel
/04
windows-core-smoke
Windows x64 core install smoke: native dependencies, coodra init, MCP daemon start, /healthz, status, stop.
depends → verify
/05
windows-native-full-smoke
PowerShell-native lane with Windows-focused unit tests, Graphify path checks, web standalone build, publish artifact assertion, and web smoke.
depends → verify
/06
e2e
Testcontainers-driven full-stack scenarios.
depends → verify + integration
/13 — Contribute

Contribution guide.

Apache-2.0 licensed
PRs welcome

Coodra is built linearly, start to finish, as a production-grade system. Contributions are welcome — and held to the same bar.

/13.1Core principles (read first)

  1. Ship complete or don't merge. No placeholder surfaces, no mocked endpoints to make the UI render, no "we'll come back to this later." Every module ships end-to-end.
  2. Local-first remains the default. Any new feature must work offline. If it requires the cloud, it must degrade gracefully back to local + offer a clear path to enable.
  3. Fail-open in the hot path. Hooks return ALLOW on engine fault. Hot-path code paths catch and log async — never throw at the agent.
  4. Append-only audit. Don't add an UPDATE on policy_decisions, decisions, or run_events. Resurface via a new row with the same idempotency key.
  5. Document divergence. If your PR contradicts an ADR, README claim, or essentials doc — update the source-of-truth doc in the same commit.

/13.2Workflow

/01

Pick or file the issue.

Look for good-first-issue or help-wanted. For non-trivial work, open an issue first so we can align on shape before code lands.

/02

Branch off main.

Naming: feat/<short-slug>, fix/<short-slug>, chore/<short-slug>, docs/<short-slug>. Squash-merge expected at the end.

/03

Write the tests.

Unit tests live next to source as *.test.ts. New tables/migrations require a schema-parity test. New MCP tools require a happy-path + soft-failure test at minimum.

/04

Update docs.

If you touched the public surface — env vars, CLI flags, MCP tools, lifecycle payloads — update the relevant table in this docs page in the same PR. If the change alters durable architecture, record or supersede the decision through record_decision.

/05

Pre-commit & push.

The .githooks/pre-commit hook runs the migration-lock check automatically when packages/db/* is staged. Before pushing: pnpm lint:fix && pnpm typecheck && pnpm test:unit.

/06

Open the PR.

Title in conventional-commit form (feat:, fix:, chore:, docs:). Body should state: what changed, why, how to verify locally, and any decision/docs it touches. CI will run verify, integration, hook-adapter-smoke, windows-core-smoke, windows-native-full-smoke, and e2e.

/13.3Code conventions

Biome is the source of truth. Rules ratcheted up over time — these are the ones most likely to flag a PR.

useConst
error — Prefer const. Reach for let only when re-assigning.
useImportType
error — Type-only imports must be marked. import type { Foo } from '...'
noExplicitAny
error — any is a code smell. Prefer unknown + narrowing, or a real type.
noNonNullAssertion
warn — Avoid x!. Prefer explicit guard + early return.
noUnusedImports / Variables
error — Lint-fix will strip them automatically.
noImportCycles
error — Scoped to apps/mcp-server/src/lib/**. If your import cycles, refactor the shared bits up a layer.
noConsole
warn — Use the shared logger (pino-backed). console.log only for CLI user output.

/13.4Where things live

repo map
Coodra/
├── apps/
│   ├── mcp-server/      # 26 MCP tools · stdio + HTTP transport
│   ├── sync-daemon/     # push + pull workers · team mode only
│   └── web-v2/          # Next.js 15 dashboard · 56 page/route files
├── packages/
│   ├── cli/             # @coodra/cli npm package · only published artefact
│   ├── db/              # Drizzle dual-dialect schema + migrations
│   ├── lifecycle/       # shared SessionStart/End, diff, graph refresh, memory workers
│   ├── policy/          # Cockatiel-wrapped evaluator + types
│   └── shared/          # auth, roles, recipes, wiki, logger, env
├── .coodra/
│   ├── recipes/        # project-local Agent Recipes
│   ├── graphify/out/   # managed graph.json, GRAPH_REPORT.md, graph.html
│   ├── wiki/           # Deep Wiki grounding + Markdown mirrors
│   └── work-packs/     # local issue-bound implementation artifacts
├── docs/
│   ├── index.html       # public docs source of truth
│   ├── brand/           # brand kit
│   ├── deploy/          # self-hosting
│   ├── DEVELOPMENT.md
│   ├── PRD-memory-utilization.md
│   ├── team-*.md        # team setup/onboarding manuals
│   └── value-story.md
├── deploy/              # 4 Dockerfiles + compose.yaml
├── scripts/             # maintenance + publishing helpers
├── __tests__/           # e2e + functional + manual harnesses
└── .github/workflows/   # ci.yml (4 jobs)

Hot tip: when in doubt about whether a behaviour is correct, start from .coodra/wiki/coodra/md/ and verify targeted source files. The wiki is grounded by Graphify, but source files remain the final authority.

/14 — Design

Decisions of record.

Coodra decisions store
curated highlights

Architectural decisions are durable Coodra memory, written through record_decision and superseded through decision edges rather than maintained as standalone ADR files. The cards below are curated highlights of the most load-bearing decisions.

ADR-007

Append-only audit

Policy decisions, decisions records, and kill-switch state changes are append-only. Idempotency keys gate writes. Resumes don't delete — they stamp resumed_at on the existing row. Recovery and forensics become trivial.

ADR-010

Graphify is a reader

Coodra consumes Graphify as a separate managed MCP server pointed at .coodra/graphify/out/graph.json. It installs and refreshes the structural graph, but does not fold graph queries into Coodra's own tool list or mint Work Packs from graph communities.

ADR-012

Agent-driven NL assembly

Natural-language memory assembly stays inside the agent loop. Coodra exposes retrieval tools (search_packs_nl, list_context_packs, read_context_pack); the agent ranks, synthesizes, and cites returned evidence.

ADR-013

Run Diff in process

Shared lifecycle finalization captures base_sha → head_sha, stores deterministic git diff evidence, and links the result back to the run without depending on a separate analysis service.

ADR-014

Tier 2.5 RBAC

Three roles — viewer, member, admin — parsed from Clerk org roles. assertCanEdit centralises the gate; ownership unlocks member-level edits on rows they created. Knowledge mutations are their own narrower gate.

COOD-53

Lifecycle is MCP-native

Native plugins route session events to lifecycle_event. Shared @coodra/lifecycle owns finalization, diff capture, auto Context Packs, Work Pack updates, and graph refresh.

/15 — Reference

External dependencies.

Material
libraries

Only the libraries that shape behaviour. If something in the runtime surprises you, the explanation is usually here.

Package Where What it gives us
@modelcontextprotocol/sdkmcp-serverMCP protocol server with stdio + HTTP transports.
hono · @hono/node-servermcp-server HTTPTiny HTTP framework. Validates payloads via @hono/zod-validator.
drizzle-ormpackages/dbDual-dialect schemas + migrations.
better-sqlite3everywhere localSynchronous SQLite driver. Native module — rebuild after install.
sqlite-vecpackages/db extensionVector search for the context_packs_vec virtual table.
postgresweb-v2 · packages/dbPostgres driver.
next 15 · react 19web-v2Server framework + UI.
@clerk/nextjs · @clerk/backendweb-v2 · cliIdentity, org membership, JWT.
cockatielpackages/policyCircuit breaker + timeout fuse around DB reads.
picomatchpolicy · mcp-serverPath glob matching for policy rules.
zodeverywhereSchema validation at every untrusted boundary.
commander · execa · inkcliCLI parser, subprocess management, React-for-terminal TUI.
vitest · testcontainerstestsUnit + integration + e2e runners.
biomerepoLint + format.
turborepoWorkspace orchestration.

Not present, in case you're checking: no @anthropic-ai/sdk, no openai, no @google/generative-ai, no web-tree-sitter, no bullmq, no @octokit/*, no JIRA SDK. The MCP server is the only LLM-facing surface — and it talks to the agent, not the model.

/16 — Help

Frequently asked.

Short answers
linked deep dives
Is Coodra a code editor?
No. It runs alongside your editor or coding agent. Coodra is the plugin/MCP layer between the agent and your project: context in, evidence out.
Does it call out to OpenAI / Anthropic?
Coodra itself does not call model APIs. Your agent talks to its model. Coodra talks to the agent through MCP and may run key-free structural Graphify refreshes locally.
Is Graphify part of Coodra?
No. Graphify is an independent open-source project. Coodra manages the local wiring, MCP entry, and .coodra/graphify/out/ artifact path; Graphify owns the graph engine. See the repository NOTICE file for attribution.
Can I use Coodra without Claude Code?
Yes. Codex, Cursor, Devin, and Antigravity are supported through native plugins, and any MCP-speaking client can talk to mcp-server.
What happens if Coodra's lifecycle path goes down?
The agent keeps coding through its native flow. You lose Coodra audit, memory refresh, run diffs, and policy advice for affected events until MCP/plugin health is restored.
Where is my data stored?
In solo mode: only at ~/.coodra/data.db. In team mode: also in the Postgres you operate. Coodra ships no hosted backend.
Can I delete my run history?
Yes — scripts/wipe-disposable-projects.sh or scripts/wipe-all.sh. Append-only doesn't mean undeletable; it means we don't update rows in place.
Can I change the web port?
Yes. Set COODRA_WEB_PORT for Coodra's service manager, or PORT when running the Next.js standalone process directly. Default is 3001.
Is the web UI required?
No — it's a convenience. coodra start --no-web skips it. coodra ui gives you a TUI alternative.
/17 — Help

Glossary.

Short
definitions
Actor
The authenticated entity behind a request — userId, orgId, role, source. Solo bypass attaches SOLO_ACTOR.
Cockatiel
The resilience library wrapping policy DB reads. Provides timeout + circuit breaker primitives.
Doctor
A self-diagnostic CLI command. 12 essential checks by default, 36 with --full.
Drizzle
The TypeScript ORM. Dual-dialect schemas in packages/db/src/schema/{sqlite,postgres}.ts.
Fail-open
When the engine can't decide, the verdict is ALLOW. Never block the agent because of our own faults.
Graphify
Coodra-managed structural code graph under .coodra/graphify/out/, queried through a separate managed Graphify MCP server.
Hook MCP tool
lifecycle_event, the canonical Coodra MCP tool native plugins call for SessionStart, prompt, tool, compaction, and SessionEnd events.
lifecycle_event
The MCP-native lifecycle entrypoint for run creation, prompt-time memory refresh, tool policy checks, event recording, and finalization.
Idempotency key
A deterministic string used to gate writes. Same key → at most one row.
Ink
React for the terminal. Powers coodra ui.
launchd
macOS's service manager. Coodra writes per-service plists into ~/Library/LaunchAgents/ during start.
MCP
Model Context Protocol. The standard Coodra speaks to AI agents.
Outbox
The durable SQLite-backed queue (pending_jobs table) used for async writes and cloud sync.
picomatch
Path glob library. Used to match policy_rules.match_path_glob.
Run diff
Unified diff between runs.base_sha and runs.head_sha, captured at session end.
Sentinel project
__global__ for events before a real project exists; __solo__ for the solo-mode org.