Voltar ao Blog
CortexPrism v0.49: The Modularization Release

CortexPrism v0.49: The Modularization Release

CortexPrism v0.49.0 ships a full codebase modularization into 6 Deno workspace packages with 41 contract interfaces, an interactive D3 memory graph, and an integrated xterm.js terminal — the most significant architectural transformation since the OS kernel.

jacobJune 22, 20267 min de leitura0 visualizações

When we shipped the OS kernel in v0.48, CortexPrism crossed an architectural threshold — it became an operating system for AI agents, not just a collection of features. But the codebase hadn't caught up to the architecture. A single router file had grown to 6,075 lines. The UI assembler was 17,740 lines. The agent loop was 1,605 lines with every pipeline stage in one function. New contributors couldn't find where to make changes. Cross-cutting concerns were tangled in monolithic files.

v0.49.0 fixes that at the structural level. This is the "make it right" release — the one where we pay down the technical debt that accumulates during rapid feature development.

The Package Architecture

We reorganized the codebase into 6 coarse Deno workspace packages, each with a clear domain boundary:

packages/
├── core/     — @cortex/core:  config, database, i18n, utils, plugins (41 files)
├── gate/     — @cortex/gate:  security, sandbox, virtual filesystem (29 files)
├── ai/       — @cortex/ai:    agent, tools, memory, LLM, pipeline, skills (166 files)
├── server/   — @cortex/server: server, channels, A2A, MCP, voice, codegraph (222 files)
├── infra/    — @cortex/infra: processes, scheduler, observability, triggers (43 files)
└── cli/      — @cortex/cli:   CLI commands, TUI framework (92 files)

The dependency graph is strict and acyclic:

@cortex/core ← @cortex/gate ← @cortex/ai ← @cortex/server ← @cortex/cli
                       ↖                               ↗
                 @cortex/infra

This means core has zero internal dependencies — it's the foundation. gate depends only on core. ai depends on core and gate. server depends on core and ai. cli is the composition root, depending on everything. infra sits between ai and cli, depending on core and ai.

Each package exposes a contracts/ directory with pure TypeScript interfaces that define its public API. These 41 interfaces have zero runtime dependencies — they're purely type-level contracts. For example, @cortex/ai/contracts/tools.ts defines ITool, IToolRegistry, IToolContext, IToolResult, and 8 other types. Any package that depends on @cortex/ai sees only these interfaces, not the implementation details in src/.

A boundary enforcement script (scripts/check-boundaries.ts) validates that cross-package imports only reference contracts/ directories. If someone accidentally imports from packages/ai/src/ instead of packages/ai/contracts/, CI will catch it. This is the same pattern that operating systems use — a stable syscall interface that implementations must satisfy but callers only see.

What Happened to the Monoliths?

Three files had grown well past the point of maintainability. Here's exactly what happened to each:

The Router (src/server/router.ts, 6,075 lines) was a single file where every REST endpoint lived — auth, agents, memory, sessions, tools, config, codegraph, MCP, channels, workflows, OS health, debug settings, etc. Each section was separated by // ── Auth ── style comments. The mechanical split produced 62 files in src/server/routes/, one per API area — routes/auth.ts, routes/agents.ts, routes/memory.ts, and so on. Each exports RouteHandler[] — an array of { method, pattern, handler } tuples. new-router.ts iterates a flat publicRoutes/protectedRoutes table with the auth guard between them. Adding a new endpoint is now: create a new route file, export handlers, add to the table. No more scrolling through 6,000 lines to find the right // ── comment.

The UI (src/server/ui.ts, 17,740 lines) was a single template literal that assembled the entire SPA — CSS, 41 HTML page templates, 25 JavaScript blocks, shared utilities — all in one file. The split produced 74 files under src/server/ui/: css.ts (embedded CSS), 41 files in pages/ (one per page — pages/chat.ts, pages/memory.ts, pages/codegraph.ts, etc.), 25 files in js/ (concatenated JavaScript modules — js/01_core.ts, js/02_router.ts, js/03_websocket.ts, etc.), and shared utilities in shared/. mod.ts assembles all pieces via string concatenation into a single <script> block, preserving the global variable scope that the existing JS modules depend on (ws, sessionId, currentPage, etc.). The assembly preserves the exact same output — just modularly composed.

The Agent Loop (src/agent/loop.ts, 1,605 lines) contained 11 pipeline stages interleaved in a single function. The split produced 11 files under src/agent/stages/ (setup, history, assessment, prompt-builder, model-selector, llm-stream, tool-executor), 3 under post/ (response, background, cleanup), and 3 under helpers/ (nanoid, preferences, strip-tool-calls). The orchestrator in loop.ts is now 81 lines:

export async function agentTurn(opts: IAgentTurnOptions): Promise<IAgentTurnResult> {
  const ctx = createTurnContext(opts);
  await setupStage(ctx);
  await historyStage(ctx);
  await assessmentStage(ctx);
  await promptBuilderStage(ctx);
  await modelSelectorStage(ctx);
  await llmStreamStage(ctx);
  await toolExecutorStage(ctx);
  await postResponseStage(ctx);
  backgroundStage(ctx);        // fire-and-forget
  await cleanupStage(ctx);
  return ctx.result;
}

Each stage receives a TurnContext with typed access to session, agent, tools, memory, and pipeline state. Stages can mutate the context but can't see each other's internals. The pipeline hooks system registers before/after handlers on any stage.

Interactive Memory Graph

While the modularization was the main architectural work, we also shipped two user-facing features. The Memory > Graph tab now renders an interactive D3 force-directed graph. Previously it showed a static card list of entities. Now you see colored nodes (blue for concepts, green for code symbols, purple for domains) connected by typed edges. Hover for details. Click to explore. The graph makes memory tangible — you can see what your agent has learned and how concepts relate.

Integrated Terminal

The Terminal tab in the editor panel now runs a real shell. Before v0.49.0, it was a static "not connected" placeholder. Now it spawns bash or PowerShell via WebSocket with full stdin/stdout/stderr piping. It's a full xterm.js terminal emulator — not a simulation. Ctrl+C sends SIGINT to the running process. Ctrl+D sends EOF. Session state (working directory, environment variables) persists between commands and across tab switches.

The Bug Backlog

Every major architectural change surfaces issues in existing code. The modularization process (especially the UI split) uncovered 53 JavaScript functions that were silently dropped during extraction. Template literal escaping in the terminal feature broke 11 strings. But beyond the extraction artifacts, the deeper win was finding and fixing 5 modules that were written but never actually wired up:

  • preference-learner.ts (260 lines): A full preference learning system with confidence tracking and pattern extraction. Never imported by any file. The agent loop had its own separate regex-based implementation. Now wired into both detectAndPersistPreference() and the prompt enrichment pipeline.

  • glossary.ts: A term definition and lookup system that was entirely in-memory — all terms lost on restart. Now DB-persisted via semantic_memory with proper async loading.

  • cross-agent-context.ts: Wrote shared context to a shared_context table that had no corresponding migration. All writes silently failed. Migration 039 created the table with proper schema and indexes.

  • context-bridge.ts: A cross-session context bridge that was defined but never called. Now wired into the agent loop's prompt enrichment pipeline alongside memory injection and preferences.

  • privacy.ts: Retention enforcement that was defined but had zero callers. Expired entries were never actually purged. Now wired into daily consolidation.

These aren't just bug fixes — they're features that were partially built, tested, and then accidentally left disconnected. The modularization process forced us to trace every import chain, which is how we found them.

Memory heuristics had a subtle ordering bug: boostImportanceFromAccess() reset access_count to 0, then slowDecayForFrequentAccess() checked access_count >= 5 — which always failed because the count was already zero. Episodic last_accessed was never updated (only semantic). Daily consolidation only re-scored semantic decay, leaving episodic memories to accumulate indefinitely. Qdrant's upsert was using the wrong HTTP method (PUT instead of POST) and missing the /upsert path suffix. Pinecone's API version was 8 months stale.

What's Next

With the modular architecture in place, the codebase is positioned for three areas of development:

  • Distributed agent swarms. The kernel's process tree and resource accounting were designed to extend across machines. With clean package boundaries, adding cross-instance coordination becomes an implementation detail of @cortex/infra.

  • WebAssembly tool plugins. With the @cortex/gate contracts defining capability-based access control, WASM plugins get stronger isolation guarantees — a plugin that only needs stdout shouldn't have filesystem access at all.

  • Multi-user collaboration. Shared workspaces with per-user agent configs. The @cortex/server contracts define channels and sessions in a way that naturally extends to multi-tenant routing.

Get Started

CortexPrism runs on macOS, Linux, and Windows as a single Deno binary. No Docker required, no Python, no node_modules.

# Install
curl -fsSL https://cortexprism.io/install.sh | bash

# Setup and start
cortex setup
cortex serve

# Open http://localhost:3000

Already running? Upgrade in place:

cortex self update

The project is Apache 2.0 licensed, fully open source, and has zero telemetry. Everything runs on your hardware.

GitHub: github.com/CortexPrism/cortex Changelog: CHANGELOG.md


Built with Deno. 6 packages. Clean contracts. Zero telemetry.

J

jacob

Related posts

CortexPrism v0.50: The Stabilization Release
+3

CortexPrism v0.50: The Stabilization Release

CortexPrism v0.50.0 ships a stabilization milestone — wiring dead code that was built but never connected, hardening security across all 6 layers with 18 resolved issues, overhauling the UI with top navigation and dark/light theme, and fixing 18 critical bugs in the dual quartermaster intelligence systems.

jacobJune 22, 202616 min de leitura5
CortexPrism v0.48: From Agentic Harness to AI Agent Operating System
+3

CortexPrism v0.48: From Agentic Harness to AI Agent Operating System

CortexPrism v0.48.5 ships an OS kernel, a custom terminal UI framework, 5 built-in agent profiles, an IDE-style code editor, and a virtual filesystem — marking the evolution from "agentic harness" into a full AI agent operating system.

jacobJune 21, 202610 min de leitura