Architecture & Concepts

A deep-dive into Automergent's internals — the phase-driven agent loop, layered prompt composition, context window management, tool system, sub-agent orchestration, session persistence, and sandboxing.

1. System Overview

Design Philosophy

Automergent is a terminal-native AI coding agent written in Go. It runs entirely in your command line — no Electron, no VS Code extension, no browser. This means:

Core Principle: Automergent brings the power of IDE coding agents (file editing, terminal access, code intelligence) directly into any terminal — with the reliability and speed of a compiled Go binary.

Tech Stack

LayerTechnologyPurpose
TUI Frameworkcharm.land/bubbletea/v2Elm-architecture terminal UI
Stylingcharm.land/lipgloss/v2Declarative ANSI styling
Markdown Rendercharm.land/glamourTerminal-native markdown
AST Parsingtree-sitter (via CGO)Language-aware code intelligence
AI ProvidersGemini, OpenAI, Anthropic, DeepSeek, OllamaMulti-provider abstraction
ConfigurationViperYAML + env var config
Sandboxingbubblewrap (Linux), seatbelt (macOS)OS-level process isolation

Directory Layout

Automergent/
├── cmd/automergent/              # CLI entrypoint
├── internal/
│   ├── agent/                    # Agent loop, orchestration, approval policies
│   │   ├── agent.go              # Core Agent struct + Execute()
│   │   ├── builtin/              # Built-in agent definitions (explore, review, etc.)
│   │   ├── custom/               # User-defined agent loader
│   │   ├── init.go               # INIT phase decomposer
│   │   ├── subagents.go          # Sub-agent spawning & management
│   │   └── autocompact.go        # Context window auto-compaction
│   ├── ai/                       # Provider abstraction (Gemini, OpenAI, Anthropic)
│   ├── config/                   # Viper configuration, validation
│   ├── context/                  # Budget management, compaction, dependency tracking
│   │   ├── manager.go            # Central context coordinator
│   │   ├── budget.go             # Token budget allocation
│   │   ├── compaction.go         # 6-tier progressive compaction pipeline
│   │   └── adaptive.go           # Anchor+estimate token counting
│   ├── prompt/                   # Phased prompt system (13-layer composer)
│   │   ├── composer.go           # Layered prompt assembly
│   │   ├── phase_manager.go      # Phase state machine
│   │   ├── behavioral.go         # Behavioral rule injection
│   │   └── bases/                # Model-specific base prompts
│   ├── sandbox/                  # OS-level sandboxing (bubblewrap/seatbelt)
│   ├── session/                  # Persistent transcripts, memory, checkpoints
│   ├── tools/                    # 43+ tools (FS, Terminal, AST, Web, Diagnostics)
│   │   ├── tool.go               # Tool interface definition
│   │   ├── agent/                # Sub-agent tools (task, batch_task, read_agent)
│   │   ├── filesystem/           # read, write, edit, glob, search
│   │   └── shell/                # bash, async shells, process management
│   ├── tui/                      # Bubble Tea v2 TUI
│   └── workflow/                 # Artifact system, plan management
└── Makefile                      # Build, test, lint, release

2. Four-Phase Agent Loop

Every user message flows through a structured 4-phase state machine. Each phase has its own tool set, step budget, prompt style, and behavioral rules. The PhaseManager controls transitions; the PhaseClassifier determines initial routing.

┌─────────────────────────────────────┐ │ USER MESSAGE │ └──────────────────┬──────────────────┘ │ ┌────────▼────────┐ │ INIT PHASE │ │ (classifier) │ │ 3-step budget │ └───┬────┬────┬───┘ │ │ │ ┌───────────────────┘ │ └───────────────────┐ │ │ │ ┌───────▼───────┐ ┌───────▼───────┐ ┌───────▼───────┐ │ EXPLORE PHASE │ │ PLAN PHASE │ │ BUILD PHASE │ │ (read-only) │ │ (architect) │ │ (implementer) │ │ 10 steps │ │ 5 steps │ │ 20 steps │ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ │ │ │ └───────────┬───────────┘───────────────────────┘ │ ┌────────▼────────┐ │ INIT (next) │ └─────────────────┘

INIT Phase — Classifier & Router

Persona: Serious, decisive. Minimal output.

Tools: bash, read_file, glob, grep, edit_file, task — no todo tools

Step budget: 3

INIT decomposes the user message into structured intents using an LLM call. It:

// internal/shared/types.go
AgentPhase = "init" | "explore" | "plan" | "build"

// TaskSpec carries routing metadata
TaskSpec {
    Agent  string  // "main", "explore", "general-purpose", "review", ...
    Phase  AgentPhase  // explore | plan | build
    Type   string  // "explore", "implement", "fix", "plan", ...
    ...
}

EXPLORE Phase — Read-Only Investigation

Persona: Thorough, investigative. File:line reporting.

Tools: glob, grep, read_file, bash, list_directory — read-only only

Step budget: 10

EXPLORE is strictly read-only. It performs codebase reconnaissance:

PLAN Phase — Architect Mode

Persona: Structured, analytical. Produces actionable plans.

Tools: read_file, write_file, bash, task, grep, glob

Step budget: 5

PLAN consumes INIT's constraints and EXPLORE's findings to produce a structured implementation plan:

BUILD Phase — Implementer + Tester + Todo Manager

Persona: Focused, pragmatic. Verify after every change.

Tools: Full set — edit_file, write_file, bash, read_file, task, glob, grep, multi_edit

Step budget: 20

BUILD is the implementation workhorse:

Phase Transitions & Step Budgets

FromAllowed TransitionsStep BudgetTrigger
INITEXPLORE, PLAN, BUILD, INIT (self)3User message classification
EXPLOREPLAN, BUILD, INIT10Findings complete, blocked, or clarified
PLANBUILD, EXPLORE, INIT5Plan ready, needs more info, or done
BUILDEXPLORE, PLAN, INIT20Implementation complete, blocked, or needs plan revision
// internal/prompt/phase_manager.go
PhaseManager {
    currentPhase   AgentPhase
    phaseHistory   []PhaseTransition
    taskQueue      *TaskQueue
    violationCount map[ViolationType]int
}

// Valid transitions are enforced:
CanTransition(from, to) → bool
Transition(to, reason, trigger) → error

3. Prompt System Architecture

The system prompt is assembled from 11+ composable layers via the PromptComposer. Each layer is independent, cached where possible, and injected in a fixed order.

Layered Composition

1 Base Model Model-specific base (bases/{model}.txt) — identity & tone
2 Platform Core Shared rules, task discipline, action care, communication style
3 Environment Working dir, git status, platform, date, model info
4 Agent Definition Per-agent custom prompt from config or agentdef
5 Phase Prompt Phase-specific mission, rules, exit criteria (phases/*.txt)
6 Behavioral Rules Phase discipline, context hygiene, verification, safety
7 Tool Prompts Per-tool guidance — only for tools offered this phase
8 Skills / MCP Available skills & MCP server instructions
9 Dynamic Init results, task progress, working areas, todo snapshot
10 Project Instructions AUTOMERGENT.md / AGENTS.md / CLAUDE.md (user msg)
11 Git Status Snapshot Compact git status block (user msg)
12 Task Notifications Sub-agent completion notifications (user msg)
13 Long-Run Nudges Transient system messages for long-running tasks

Composer Pipeline

// internal/prompt/composer.go

PromptComposer {
    layers      map[PromptLayer][]string
    layerOrder  []PromptLayer   // fixed assembly order
    model       ModelInfo
    agent       *AgentDefinition
    phase       AgentPhase
    registry    *tools.Registry  // live tool metadata
}

// Assembly order — each layer appends to its slot
buildAllLayers() → buildBaseModel → buildPlatform → buildEnvironment →
    buildInstructions → buildSkills → buildMCP → buildAgentCustom →
    buildPhase → buildBehavioral → buildTool → buildDynamic

// Final render — joins layers with "---" separators
Compose() → string

The composer's SetRegistry() method attaches the live tool registry so the tool layer renders ToolMeta self-documentation for each offered tool — tools document themselves.

Behavioral Rules

Behavioral prompts are injected by RenderBehavioralPrompts() and grouped by dimension:

DimensionRulesTriggers
Phase DisciplineStay in current phase. Don't edit during EXPLORE. Don't explore during BUILD.always
Context HygieneDon't re-read known files. Use file:line references. Micro-compact tool outputs.always
VerificationRun tests after every edit. Confirm build passes. Check for regressions.tool_use, phase_change
Safety & HonestyDon't fabricate. Don't commit secrets. Confirm destructive ops. Escalate violations.always, violation

4. Context Window Management

Automergent uses a progressive degradation ladder to keep conversations within the model's context window. The CompactionPipeline operates across 6 tiers, each triggered at a different threshold.

The Compaction Ladder

Context Window Usage 0% 50% 65% 75% 85% 90% 95% 100% ├──────────────────────┼─────────┼─────────┼─────────┼─────────┼─────────┤ ┌─────┐ │GHOST│ persist large outputs to disk, replace with stub └─────┘ ┌───────────┐ │ TRUNCATE │ keep head+tail with "[truncated]" marker └───────────┘ ┌──────────┐ │ DISTILL │ LLM-summarize old file reads └──────────┘ ┌──────────┐ │ SNAPSHOT │ Master State JSON + summary └──────────┘ ┌─────────────┐ │MICROCOMPACT│ compact tool results only via LLM └─────────────┘ ┌──────────────┐ │ FULL COMPACT │ summarize + probe-verify └──────────────┘

Token Budgets & Thresholds

TierStrategyThresholdDescription
1ghost50%Persist large tool outputs (>32KB) to disk; replace with preview stub
2truncate_middle65%Keep 40% head + 40% tail of tool results; insert truncation marker
3distill75%LLM-summarize old file reads (>2 turns old, >2KB)
4snapshotEmit Master State JSON with active tasks, facts, constraints, recent arc
5microcompact90%Non-LLM compact of all but last 2 tool results
6full_compact95%Full history summarization + probe-verify for completeness
Summary Reserve: 20K tokens  |  Auto-compact Buffer: 13K (50K window)  |  Micro-compact Trigger: 55% usage

Token Estimation

Automergent uses anchor-plus-estimate token counting:

Compaction Boundaries & Metadata Markers

Compacted sections are delimited by metadata markers that the agent can detect:

Post-Compact File Restore

Ghosted outputs can be restored on demand via read_file — the stub includes the persistence path. The ToolResultStore manages the on-disk ghost files and cleans up after session end.

5. Tool System

Tool Interface & Registry

// internal/tools/tool.go

Tool interface {
    Name() string
    Description() string
    Schema() map[string]any
    Execute(ctx, args) → (Result, error)
    RequiresConfirmation(mode) → bool
    IsConcurrencySafe(args) → bool
    IsReadOnly(args) → bool
    IsDestructive(args) → bool
    EstimatedCost() → ToolCost
}

ToolCost {
    TokensApprox  int     // estimated tokens consumed
    LatencyMs     int     // typical latency in ms
    RiskLevel     string  // "low" | "medium" | "high"
}

BaseTool // embeddable defaults: conservative (not concurrency-safe, not read-only)

The Tool Registry supports:

Tool Orchestrator & Security

Security Layer: The orchestrator enforces confirmation policies, path boundary checks, destructive-op gating, and concurrency safety before any tool execution.

6. Sub-agent Architecture

Agent Types

TypeRoleToolsUse Case
general-purposeFull coding agentFull toolsetImplementation, debugging, refactoring
exploreRead-only researcherRead-only toolsFile discovery, code understanding
reviewCode reviewerRead-only + analysisBug detection, security analysis
code-reviewDeep code reviewRead-only + diagnosticsPR review, style compliance
contexterContext managerContext toolsCompaction, memory optimization
coordinatorOrchestratorTask spawningSpawns and manages child agents
taskCommand executorShell + file toolsExecute commands with verbose output

Agent Lifecycle

Parent Agent │ ├── task(agent_type="explore", prompt="find auth handlers") │ │ │ ├── 1. Clone tool registry (filtered for read-only) │ ├── 2. Create child session (sidechain transcript) │ ├── 3. Compose prompt (own phase + behavioral rules) │ ├── 4. Execute turns (model → tools → model → ...) │ │ │ │ │ └── steer channel ← task notifications │ │ │ └── 5. Return result (or notify on background completion) │ ├── task(agent_type="general-purpose", mode="background") │ └── Runs async. Use read_agent to collect results. │ └── batch_task([explore, review]) └── Launches multiple agents in parallel. Max 8 concurrent.

Key architectural details:

7. Session Management

Persistent Transcripts

Every conversation is persisted as a JSONL transcript. Sessions survive process restarts and can be resumed.

// internal/session/session.go
Session {
    ID        string
    Title     string
    WorkDir   string
    Messages  []ai.Message
    Metadata  map[string]string
    AllowedTools []ToolApproval   // survives restarts
    TotalInputTokens  int
    TotalOutputTokens int
}

Checkpoint / Recovery

Checkpoints are atomic snapshots written to disk at configurable intervals:

Undo Stack

File edits are tracked in an undo stack. The agent can revert changes on failure or user request.

Memory System

Durable Facts: The memory system stores learned patterns, conventions, and project knowledge that persist across sessions.
// internal/session/memory.go
ProjectMemory {
    Conventions   map[string]Convention     // learned coding conventions
    CodePatterns  []CodePattern            // reusable patterns
    Architecture  *ArchitectureDecisions  // project architecture
    FilePatterns  map[string]FilePattern   // per-filetype conventions
    Preferences   map[string]string       // user preferences
}

Convention {
    Name        string
    Description string
    Confidence  float64   // 0.0–1.0
    Source      string    // where learned from
}

// /dream command consolidates session observations into memory
// Memory is injected into context via GetContextWithMemory()

Session Search & Compaction

8. Sandboxing

Automergent wraps every shell command in an OS-level sandbox to contain damage from runaway or malicious tool executions.

PlatformMechanismCapabilitiesAvailability
Linux bubblewrap (bwrap) Namespace isolation, mount sandboxing, seccomp, network isolation, resource limits Requires bubblewrap installed
macOS sandbox-exec (seatbelt) Filesystem restriction, network filtering,itlement-based isolation Built-in on macOS
Windows noop No sandboxing — commands run without restrictions Fallback only
// internal/sandbox/sandbox.go
Sandbox interface {
    Wrap(ctx, name, args) → (string, []string)
    WrapWithPolicy(ctx, name, args, policy) → (string, []string)
    IsAvailable() → bool
    Name() → string
    Capabilities() → Capabilities
}

Capabilities {
    SupportsNamespaces      bool
    SupportsSeccomp         bool
    SupportsCgroups         bool
    SupportsNetworkIsolation bool
    SupportsFSIsolation     bool
    SupportsResourceLimits  bool
    RequiresRoot            bool
}

Path Boundary Enforcement

The PathScope component ensures all file operations stay within the working directory:

Defense in Depth: Sandboxing is a safety net, not the primary defense. The approval policy, path boundary enforcement, and behavioral rules form the first three layers. The sandbox catches anything that slips through.

Automergent Architecture Documentation — Generated from source code analysis
internal/agent/agent.go · internal/prompt/composer.go · internal/context/compaction.go · internal/tools/tool.go · internal/tools/agent/tools.go · internal/sandbox/sandbox.go · internal/session/