CodeAlta

2026-07-05 · page · source ↗ · raw capture · source summary

A terminal-based AI coding agent workspace built in C#/.NET that integrates multi-provider LLM access, durable project-scoped sessions, trusted local plugins, and keyboard-driven project navigation behind a single alta CLI command. Created by Alexandre Mutel (xoofx), it's the most architecturally sophisticated open-source terminal agent workspace — notable for its provider-agnostic session model, JSONL journal-based persistence, in-process .NET plugin system, and compaction-as-provider-turn design.


Architecture

CodeAlta is a .NET 10 monorepo of ~25 projects in a strictly layered architecture:

CodeAlta (TUI frontend, XenoAtom.Terminal)
  ↓
CodeAlta.Orchestration (session lifecycle, runtime events, instruction composition)
  ↓
CodeAlta.Agent (provider contracts, session runtime, compaction, tools)
CodeAlta.Catalog (project/session/skill catalogs, config store)
CodeAlta.Plugins (plugin runtime, source builds, load contexts)

The frontend is a terminal UI built on XenoAtom.Terminal, with views, dialogs, and a shared command registry. The frontend never calls runtime services directly — all interaction goes through immutable shell commands, coordinators, and an event pump.

Session lifecycle (src/CodeAlta.Agent/Runtime/AgentSession.cs, src/CodeAlta.Orchestration/Runtime/SessionRuntimeService.cs): Sessions are CodeAlta-owned, not provider-owned. The session id is generated before provider attachment. Sessions replay from JSONL journals at ~/.alta/sessions/yyyy/MM/dd/<session-id>.jsonl. A SQLite projection cache at ~/.alta/cache/cache.sqlite3 provides fast listing, but journals remain the source of truth.

Concurrency model (src/CodeAlta.Orchestration/Runtime/Actors/): Per-session mailbox actors serialize same-session mutations. SessionActor owns command ordering and lifecycle. BoundedRuntimeEventStream<TEvent> uses a bounded channel with newest-event drop — slow readers don't create memory pressure. The codebase explicitly avoids Akka.NET: "Reconsider a full actor framework only after tests and measured complexity show that the local primitives no longer simplify orchestration ownership."

AgentHub (src/CodeAlta.Orchestration/Runtime/AgentHub.cs): The active session facade. Creates/resumes sessions from provider registry, owns SessionEntry with reference-counted disposal — waits for all references to drain before cleanup, with best-effort abort signaling. This avoids the "session disposed while tool is running" race.

Provider abstraction (src/CodeAlta.Agent/IModelProviderContracts.cs): Providers own protocol adaptation, credentials, and model metadata. They do NOT own persisted sessions. Nine built-in provider types: openai-chat, openai-responses, azure-openai, codex (ChatGPT subscription via WebSocket), copilot (direct HTTP), xai (PKCE OAuth), anthropic, google-genai/vertex-ai, and mistral.

Plugin system (src/CodeAlta.Plugins/, src/CodeAlta.Plugins.Abstractions/): Trusted local .NET source files at ~/.alta/plugins/<id>/plugin.cs. Compiled at startup with CodeAlta-generated build files, loaded into collectible AssemblyLoadContext. Plugins extend PluginBase and contribute commands, agent tools, prompt parts, UI elements, skill roots, MCP manifests, and instruction processors. Safe mode (--no-plugins) disables all plugins.

The alta live tool (src/CodeAlta.LiveTool/): An in-process command gateway exposed to agent sessions as a tool. Accepts CLI-style JSON arguments, returns compact JSONL. Built-in groups: project, session, skill, provider, model, plugin, tool, ask, notes, reminder, prompt, version. Plugins extend via PluginBase.GetAltaCommands().

Key Techniques

Provider-Agnostic Sessions

Sessions are CodeAlta-owned with a canonical id generated before provider attachment. Providers MUST preserve the id (returning a different one is a contract violation). This enables provider switching by replaying canonical history to a different compatible provider. Unlike Claude Code (tightly coupled to backend sessions) or Codex CLI (provider-owned sessions), CodeAlta's model is truly provider-independent.

Compaction as Provider Turn

Rather than a separate summarization API, compaction runs as an ordinary provider turn through the same executor. The summarizer prompt is a structured 9-section template (Objective → Active User Request → Constraints → Progress → Decisions → Next Steps → Critical Context → Relevant Files). Any provider that supports chat completions can compact. Multi-pass shrinking handles oversized summaries (up to 4 recursive passes). Post-compaction, activated skills are rehydrated into composed instructions so skill guidance survives.

Source Plugin Compilation

CodeAlta generates MSBuild files, invokes dotnet build plugin.cs, and loads the output assembly into a collectible context. This gives plugins full process access (trusted model) while supporting unload and rebuild. Build manifests skip recompilation when sources are unchanged. Most agent frameworks use scripting or MCP for extensibility; CodeAlta's approach is unique.

Dual JSON+TOML MCP Configuration

MCP server connections live in JSON files (mcp.json) for editor compatibility. Enablement, tool policy, timeouts, and output caps live in TOML (config.toml). This separation means policy changes don't rewrite JSON, and JSON files stay compatible with Claude Desktop and VS Code. Progressive tool exposure: alta mcp activate <server> marks servers for the current session, tools are enumerated on the next agent run.

Instruction Processing Pipeline

Plugin instruction processors (PluginBase.GetInstructionProcessors()) can inspect or replace final system/developer instructions before provider submission. Processors run in deterministic contribution order, receive full context metadata, and return Continue, Replace(...), or Cancel(...). Replacement results include audit-safe change summaries only — no secret-bearing text in the manifest. This is an extensibility/audit mechanism, not a security boundary.

Bounded Event Streams

BoundedRuntimeEventStream<TEvent> drops oldest events when readers fall behind, counting drops for diagnostics. This prevents runaway memory in long sessions — a deliberate choice against unbounded buffering that plagues many agent frameworks.

Design Decisions

In-process over isolation: Plugins are trusted code loaded in-process. Fast and powerful, but no sandbox. Safe mode is binary (all on/off), not granular. Contrast with WASM-based plugin systems (Paca) or OS-level sandboxing (Zeroclaw).

Terminal-first over GUI/web: The entire workspace is a TUI — keyboard-first, works over SSH, no browser required. This is a deliberate aesthetic choice shared with Claude Code and Pi, but CodeAlta's multi-pane workspace (tabs, sidebar, timeline, command palette) is richer than either.

Journal as source of truth: JSONL journals are append-only and provider-independent. The SQLite cache is derived and rebuildable. This is event sourcing applied to agent conversations — human-readable, replayable, portable.

Strict layer enforcement: Architecture guardrail tests (~2,100 lines) verify that no UI code calls runtime services directly, legacy terminology is banned, and frontend/runtime separation holds. Unusually rigorous for a solo-maintainer project.

Mailbox actors without a framework: Three internal classes (OrchestrationMailboxActor, SessionActor, SessionActorRegistry) provide per-session serialization without pulling in Akka.NET. Public APIs use request records and events — actor internals are never exposed.

Comparison Notes


Source: CodeAlta Last updated: 2026-07-05 Tags: #tool #project #agents #terminal #coding-agent