@lifeaitools/codeflow
v0.36.1
Published
CodeFlow Memory Engine — Neo4j-backed knowledge graph with context resolution, ownership tracking, and boundary enforcement, exposed as an MCP server, CLI, and HTTP API.
Maintainers
Readme
@regen/codeflow
CodeFlow Memory Engine — a Neo4j-backed knowledge graph and MCP tool that maps the LIFEAI monorepo so AI agents spend their token budget on work, not on reading files.
Quickstart
The automated installer handles prerequisites, engine detection, and bootstrap in a single command:
# From the regen-root monorepo root
pnpm codeflow:installWhat it does:
- Prints an install manifest with every selected install action and target path.
- Verifies prerequisites (Node >=20, pnpm, Docker Desktop, clauth daemon, required clauth keys).
- Detects which AI engines are present (Claude Code, Codex, or both).
- Asks which repos to index (TTY interview or
--repos=a,b,cfor CI). - Provisions a local Neo4j Community instance via Docker.
- Applies the CodeFlow schema (
pnpm codeflow:schema). - Writes idempotent MCP entries to each detected engine's config file (stdio transport only in Wave 1).
- Installs the repo-local Codex CodeFlow PreToolUse hook into
.codex/hooks.jsonwhen Codex is detected. - Prints a result manifest with checkmarks so the install can be inspected after it runs.
Prerequisites
The installer checks each of these before doing anything. If any are missing it exits with an actionable message.
| Requirement | Minimum | Notes |
|---|---|---|
| Node.js | v20 | Check: node --version |
| pnpm | v8 | Check: pnpm --version |
| Docker Desktop | running | Check: docker info |
| clauth daemon | running + unlocked | Check: curl -s http://127.0.0.1:52437/ping |
| regen-root checkout | C:/Dev/regen-root | The package must be present in the monorepo |
clauth keys required:
| Key | Purpose |
|---|---|
| neo4j-local | Neo4j container password (single scalar; user is the constant neo4j) |
| supabase-anon | Outcome ledger (Supabase) |
If any key is missing, the installer registers it interactively rather than failing silently.
The Four Moving Parts
Understanding these four components explains every failure mode you will encounter.
1. Neo4j (graph store)
CodeFlow uses Neo4j Community Edition, provisioned via Docker. The single database is named codeflow. Every node and edge carries a generation_id property so multiple indexed generations can coexist safely during a bootstrap without disturbing in-flight agent sessions.
- Provisioned by:
packages/codeflow/docker/docker-compose.yml(WP-1, ships in Checkpoint E Wave 1) - Managed by:
pnpm codeflow:bootstrap(initial),pnpm codeflow:reindex(incremental) - Health check:
pnpm codeflow:doctor(WP-6, ships in Checkpoint E Wave 1)
2. Supabase (outcome ledger)
Every agent interaction — tool call, query target, first-attempt success, file reads, boundary violations — is recorded in the codeflow_outcomes table in the project's shared Supabase instance. The adaptive scoring pipeline reads these records to re-rank which facts appear in agent payloads.
Pattern records (Checkpoint D) will also live in Supabase, not in Neo4j. This keeps global semantic patterns available to every engine regardless of which Neo4j instance it points at.
- Project ref:
uvojezuorjgqzmhhgluu - Schema migration:
pnpm codeflow:schema - Credentials:
supabase-anonfrom clauth daemon
3. clauth (credential vault)
All credentials flow through the clauth daemon at http://127.0.0.1:52437. No .env files, no hardcoded keys.
- Retrieve a credential:
curl -s http://127.0.0.1:52437/v/<key>(returns plain text) - Health check:
curl -s http://127.0.0.1:52437/ping(returnspong) - Restart daemon:
scripts\restart-clauth.bat(Windows)
4. MCP config and hosted services
CodeFlow exposes its core agent tools through MCP and its operator/dashboard surface through HTTP. The MCP entry manager writes the correct config format for each detected engine:
- Claude Code: JSON entry in
~/.claude/settings.jsonundermcpServers.codeflow - Codex: TOML entry in
~/.codex/config.tomlunder[mcp_servers.codeflow]
The installer also registers the repo-local Codex CodeFlow hook:
.codex/hooks.jsongets aPreToolUseentry fornode "C:/Dev/regen-root/.codex/hooks/codeflow-preflight.js".codex/hooks/codeflow-preflight.jssends read/search/edit preflights tohttp://127.0.0.1:3109/api/codeflow/*- The install is idempotent: reruns insert the hook only once and preserve unrelated hooks.
The installer also registers CodeFlow services with the clauth watchdog using
packages/codeflow/watchdog.manifest.json. The registration is manifest-based:
each watched service is inspectable before install, and restart actions remain
approval-gated in clauth/Dev Center.
The MCP server entry is dist/server.js (built by pnpm esbuild). dist/index.js is a side-effect-free barrel for type/utility imports and does NOT start a server. The entry must point at an up-to-date build; if src/ has changed since the last build, run pnpm esbuild before restarting.
Checkpoint F also ships a PM2-hosted codeflow-mcp service and @regen/codeflow-explorer dashboard. The hosted Explorer uses HTTP routes for graph, hydration, repo actions, operations, events, and scoped search; local Claude/Codex MCP entries may still use stdio.
Package Scripts
These scripts exist today in package.json and can be run manually:
| Script | Command | What it does |
|---|---|---|
| Build | pnpm esbuild | Compile TypeScript + copy assets to dist/ |
| Schema | pnpm codeflow:schema | Apply Neo4j constraints and Supabase migrations |
| Bootstrap | pnpm codeflow:bootstrap | Scan repos, write new generation, flip :Meta pointer |
| Hydrate repo | pnpm --filter @regen/codeflow codeflow:hydrate --repo <repo> | Enrich a registered repo with skills, commands, installers, documents, and tests |
| Backfill relationship evidence | pnpm --filter @regen/codeflow codeflow:backfill-relationship-evidence | Stamp hydration relationships with deterministic evidence metadata |
| Reindex | pnpm codeflow:reindex | Incremental reindex of changed files |
| Sync flow memory | pnpm codeflow:sync-flow | Import FlowMemory from existing reports |
| MCP smoke | pnpm --filter @regen/codeflow mcp:smoke | Prove the MCP surface can answer through the built server |
| Readiness | pnpm --filter @regen/codeflow readiness | Check schema, graph, hydration, MCP, dashboard, and proof gates |
| Zero trust | pnpm --filter @regen/codeflow zero-trust | Run the Checkpoint F acceptance-gate proof harness |
| Test: ingestor/indexer | pnpm --filter @regen/codeflow test:ingestor-indexer | Required gate after touching parser, AKG ingest, scanner, local index, graph-truth, or context-query code |
| Test: regression | pnpm test:regression | Structural regression suite |
| Test: comprehensive | pnpm test:comprehensive | Full 36-assertion comprehensive suite |
| Test: quality | pnpm test:quality | 6-dimension quality rubric (test corpus) |
| Test: quality (real) | pnpm test:quality:real | Quality rubric against real regen-root data |
Ingestor/Indexer Test Gate
Run pnpm --filter @regen/codeflow test:ingestor-indexer every time a change
touches the parser, AKG ingest path, scanner, incremental reindexer, local index,
graph-truth harness, or context-query resolution. The command includes the
original graph-truth fixture plus the larger cf-test-* fixture corpus:
src/__harness__/graph-truth/cf-test-repo/— a small multi-package fixture with core, engine, app, Python, JSON, and YAML surfaces.src/__harness__/graph-truth/cf-test-expected.manifest.json— fixture inventory and parser/coverage expectations.src/__harness__/graph-truth/cf-test.test.ts— parser/inventory and isolated rig smoke. If the destructive test rig is unavailable, only the Neo4j-dependent section skips; parser/inventory assertions still run.src/__harness__/graph-truth/cf-test-edits.test.ts— deterministic add, modify, delete, rename, cycle-break, and cross-language mutation sequence against the local object index with JSONL-style evidence.src/__harness__/graph-truth/cf-test-learn.tsand.test.ts— post-session analyzer for latency, accuracy, ghost nodes, edge consistency, coverage delta, confidence calibration, and Markdown report output.
The destructive graph rig is the red lane on port 3129 with its own Neo4j on
bolt 7688 (container codeflow-neo4j-test). These tests must never target the
live local/dev brain on 7687.
Bring it up with the one script that owns both lanes — not PM2, which was removed from this box:
pwsh -NoProfile -File $env:LIFEAI_ENV/services/restart-codeflow.ps1 -Lane red-Lane dev (the default) brings up the :3109 gateway instead. The red lane
hydrates on bring-up by default; pass -NoHydrate to skip it.
The orchestration/report plan for making this a touched-surface report gate is
../../.rdc/areas/infrastructure/codeflow/plans/codeflow-ingestor-indexer-test-report-orchestration.md; until that
runner lands, test:ingestor-indexer is the required manual report command.
Architecture
Full architecture documentation, topology diagrams, and design decisions (D1-D8):
docs/systems/codeflow/ARCHITECTURE.md
Key sections:
- Local stack topology diagram
- Data flow: bootstrap path and query path
- Checkpoint F zero-trust hydration model
- Repository lifecycle and graph actions
- Document handles vs future semantic concept ingestion
- Generation pinning (D6)
- Single-database generation swap (D4)
- Pattern store split decision (D7)
- All eight design decisions D1-D8
Operator guides:
- HYDRATION.md — repo hydration command, labels, proof, and known limits
- REPOSITORY-LIFECYCLE.md — import, archive, tombstone, revive, and purge behavior
- SEMANTIC-DOCUMENT-INGESTION-DESIGN.md — design for knowledge-token concept extraction beyond file handles
- apps/codeflow-explorer/docs/GRAPH-ACTIONS.md — dashboard graph action surface
Brain Segmentation — Three-Layer Domain Model
Added: WP-1, codeflow-brain-segmentation epic (2026-05-15). Architecture:
docs/systems/cs2/THREE-LAYER-DOMAIN-MODEL.md
Brain target resolver (src/brain/target.ts)
All Neo4j connection parameters are resolved via resolveBrainTarget().
Resolution order:
- Explicit override —
NEO4J_URIset → useNEO4J_URI/NEO4J_USER/NEO4J_PASSWORD/NEO4J_DATABASEdirectly. - Preset —
CODEFLOW_BRAIN=local|dev→ look up in the static preset table. - Default —
localpreset (Neo4j onneo4j://127.0.0.1:7687, databasecodeflow).
Dev preset password is resolved via clauth (neo4j-dev key) — never hard-coded.
Do not confuse this with the gateway's active brain.
resolveBrainTarget()answers "which Neo4j do I dial if I dial one." The:3109gateway's active brain defaults todev, akind:'remote'route, and in that mode it dials no Neo4j at all — it forwards the whole MCPtools/callto Vultr and answers/health+/api/codeflow/*locally from a working-tree index. The resolver'slocaldefault only takes effect once something actually opens a bolt session. SeeARCHITECTURE.md§ Routing semantics.
Node property contract (src/brain/schema.ts)
Every CodeFlow brain node must carry these properties:
| Property | Type | Description |
|---|---|---|
| owner_domain | string | Single owning domain — the writer. Never co-owned. |
| node_layer | 'domain' \| 'kernel' \| 'virtue' | Structural layer per the three-layer model. |
| location | string | Current file/repo location (former repository_id). A location attribute, never the segmentation key. |
The Domain node type carries: { name, layer, writer_brain, last_write_at }.
Domain dump format — codeflow.domain_dump.v1
The domain segment dump format (frozen by Design Decision D4 so WP-3/WP-4 can parallelize):
{
"schema": "codeflow.domain_dump.v1",
"domain": "<domain-name>",
"layer": "domain",
"source_brain": { "name": "local", "uri": "...", "database": "codeflow" },
"dumped_at": "<ISO>",
"last_write_at": "<ISO|null>",
"nodes": [ { "uid": "...", "labels": ["..."], "props": {} } ],
"edges": [ { "type": "...", "from": "<uid>", "to": "<uid>", "props": {} } ],
"kernel_stubs": [ { "uid": "...", "labels": ["..."], "owner_domain": "core-kernel", "name": "..." } ],
"virtue_refs": [ { "uid": "...", "owner_domain": "virtue", "name": "..." } ],
"counts": { "nodes": 0, "edges": 0, "kernel_stubs": 0, "virtue_refs": 0 }
}Rules:
- In-segment nodes:
owner_domain == <domain>. - Internal edges (both endpoints in-segment) →
edges. - Edge to a
kernel-layer node →kernel_stubsentry (thin: uid + labels + owner + name). - Edge to a
virtue-layer node →virtue_refsentry (overlay pointer). - Edge to another
domain-layer node → kept inedges; target emitted as a kernel-style stub tagged with itsowner_domain(grammar-import boundary). uidis stable: existingid/uidprop, elseowner_domain + ':' + name + ':' + file_path. Never Neo4j internal ids.
Domain scripts
| Script | What it does |
|---|---|
| pnpm codeflow:dump-domain | Dump a domain's brain segment to JSON (scripts/dump-domain.mjs — WP-3) |
| pnpm codeflow:copy-domain | Copy a domain dump into a target brain (scripts/copy-domain.mjs — WP-4) |
Brain Registry
Added: WP-1, codeflow-brain-registry epic (2026-05-17). Plan:
../../.rdc/areas/cs2/codeflow/plans/codeflow-brain-registry.mdDesign Decisions D1/D2/D4/D5. Migration:packages/codeflow/migrations/008-brain-registry.sql(applied asbrain_registry_v1).
brain_registry is a Supabase table — the control-plane inventory of connected CodeFlow Neo4j brains. It is the brain analog of deployment_registry: a row per brain, no passwords (clauth service name only).
Table columns
| Column | Type | Notes |
|---|---|---|
| name | text PK | Canonical brain name: local, dev, production |
| environment | text | local \| dev \| production |
| bolt_uri | text | neo4j:// connection URI |
| database | text | Neo4j database name |
| browser_url | text | Neo4j Browser dashboard link |
| explorer_url | text | codeflow-explorer instance pointed at this brain |
| credential_key | text | clauth service name only (e.g. neo4j-local). Never a password. |
| status | text | reachable \| unreachable \| unknown (default: unknown) |
| last_seen_at | timestamptz | Updated by heartbeat |
| last_node_count | int | Node count at last heartbeat |
| notes | text | Free-form operator notes |
| created_at / updated_at | timestamptz | Auto-managed |
RPC functions
-- Get a single brain row (returns null if not found — never errors)
SELECT get_brain('dev');
SELECT get_brain('nonexistent'); -- null
-- List all brains (sorted by environment, name)
SELECT list_brains();
-- Record a heartbeat (updates status, last_seen_at, last_node_count)
SELECT update_brain_heartbeat('local', 'reachable', 2276);Seeded rows
| name | environment | database | credential_key |
|---|---|---|---|
| local | local | codeflow | neo4j-local |
| dev | dev | neo4j | neo4j-local |
The dev brain uses database
neo4j, NOTcodeflow. The static preset insrc/brain/target.tswas wrong; the registry records the verified truth. The registry-backed resolver (WP-2) reads this row and supersedes the incorrect preset.
RLS
Public read for anon and authenticated roles (mirroring deployment_registry). Writes are service-role only.
AEMG Imprint Layer (Memories Sublayer)
Added: WP-1, aemg-imprint-layer epic (2026-05-18). Plan:
../../.rdc/areas/cs2/aemg/plans/aemg-imprint-layer.mdDesign Decisions D1–D3. Architecture:docs/systems/cs2/BRAIN-MEMORIES-SUBLAYER.md. Schema migration:packages/codeflow/schema/009-imprint-layer.cypher.
The imprint layer gives the CodeFlow brain a memories sublayer — per-domain, decision-grained episodic snapshots that capture a decision plus the telemetry needed to recreate the thought (salient subgraph, certainty-then, virtue weighting, inputs, rejected alternatives, bi-temporal anchor).
Design decisions
| Decision | Choice |
|---|---|
| D1 — node layer | node_layer = 'domain' (owned by a domain). sublayer = 'memory' + Imprint label is the marker. No 4th layer value. |
| D2 — bi-temporal | Every imprint carries decision_at (event time) and ingested_at (ingestion time). Enables retroactive correction and dual-truth then-vs-now. |
| D3 — reference-not-copy | FROZE edges to salient node uids + certainty_snapshot JSON payload. Never copies subgraph nodes. |
Neo4j schema
Applied via schema/009-imprint-layer.cypher:
CREATE CONSTRAINT imprint_id— unique onImprint.idCREATE INDEX imprint_decision_at— time-range queriesCREATE INDEX imprint_owner_domain— dump/copy segment selection
Adapter API (src/brain/imprint.ts)
import { writeImprint, readImprint } from '@regen/codeflow';
import type { ImprintNode, ImprintContext } from '@regen/codeflow';
// Write an EpisodicMemory as an Imprint node
const imprint: ImprintNode = await writeImprint(session, episodicMemory, {
owner_domain: 'codeflow',
decision_at: '2026-05-18T10:00:00.000Z', // event time (defaults to mem.occurred_at)
salient_node_uids: ['uid-nodeA', 'uid-nodeB'],
certainty_snapshot: { 'uid-nodeA': 0.85, 'uid-nodeB': 0.60 },
virtue_weighting: { wisdom: 0.9, courage: 0.8 },
inputs: ['design decision D2'],
rejected_alternatives: ['single timestamp'],
});
// Read back by id
const fetched: ImprintNode | null = await readImprint(session, imprint.id);writeImprint creates:
- One
Imprintnode with all properties - One
FROZErelationship per entry insalient_node_uids(reference-not-copy, D3)
readImprint returns null when no Imprint with the given id exists.
ImprintNode shape
| Property | Type | Notes |
|---|---|---|
| id | string | UUIDv4 assigned at write time |
| node_layer | 'domain' | Always domain (D1) |
| sublayer | 'memory' | Always memory (D1) |
| owner_domain | string | From ImprintContext.owner_domain |
| decision_at | string (ISO 8601) | Event time (D2) |
| ingested_at | string (ISO 8601) | Ingestion time (D2) |
| narrative | string | From EpisodicMemory.narrative |
| certainty_snapshot | Record<string, number> | node_uid → certainty-then (D3) |
| virtue_weighting | Record<string, number> | Virtue weights at decision time |
| inputs | string[] | Inputs considered |
| rejected_alternatives | string[] | Alternatives rejected |
| source_memory_id | string | EpisodicMemory.id back-reference |
| pal_id | string | PAL instance ID |
| consolidation_strength | number | From source memory |
Troubleshooting
See the runbook for symptom-level diagnosis and remediation steps:
docs/systems/codeflow/RUNBOOK.md
Note: RUNBOOK.md ships in Checkpoint E Wave 2 (WP-12). Until it exists, use
pnpm codeflow:doctor(WP-6) for health checks, and consultdocs/systems/codeflow/INSTALL.mdfor manual install problems.
Common first checks:
# Is clauth running?
curl -s http://127.0.0.1:52437/ping
# Is Neo4j reachable?
curl -s http://localhost:7474
# Is dist up to date?
pnpm esbuild