The engine loop
core/engine.ts runs the agent loop:
route → stream → permission gate → tools → results → repeat
- Route — the router picks a model and effort for the task.
- Stream — the model’s response is streamed from the provider.
- Permission gate — every tool call passes the permission policy.
- Tools — allowed calls run; their output becomes tool results.
- Repeat — results are appended and the loop continues until the turn ends.
The engine is independent of the UI: it only emits protocol events (protocol/events.ts). The Ink TUI, headless mode and the JSONL log are all just consumers of the same events.
Modules
| Path | Responsibility |
|---|---|
core/engine.ts | Agent loop; emits protocol events only. |
router/ | Task type × complexity × profile → model + effort; escalation; Haiku classification when unsure. |
llm/ | Provider-neutral message and event types; Anthropic adapter; scripted provider for offline runs and tests; its own retry / backoff policy. |
tools/ | read, glob, grep, edit, write, exec_command, write_stdin, read_block, update_plan, ask_user. |
permissions/ | Command classification and policy. |
context/ | Frozen system prompt, environment inventory, project instruction files, dynamic state in reminders. |
core/optimizer, connectivity, session/resume | Token optimization, offline resilience, server-side tool-output clearing / compaction, keep-alive, /resume. |
headless.ts | Non-interactive runs (vulgr -p). |
tui/ | Ink interface: blocks, agent turn, permission and question boxes, status bar. |
The LLM layer
- Provider-neutral types — the engine never sees SDK types directly.
- Anthropic adapter — replays signed thinking blocks exactly as received, and places prompt-cache breakpoints.
- Scripted provider — deterministic responses for offline use and tests.
- Retry / backoff — Vulgr Agent’s own policy, not the SDK default.
Context and caching
context/ builds a frozen system prompt plus an environment inventory, and loads project instructions from AGENTS.md, VULGR.md or CLAUDE.md.
Resilience and sessions
- Token optimizer — keeps the working context lean.
- Connectivity — survives going offline; keep-alive on long turns.
- Server-side cleanup — tool-output clearing and compaction.
/resume— sessions are recorded as JSONL and can be resumed.