Architecture
Iterion is organized around one compiled workflow and runtime model with multiple launch, execution, and persistence adapters. The local CLI and the cloud control plane do not maintain separate engines: both compile .bot sources to the same IR and execute them through pkg/runtime.
System view
There are two launch adapters. pkg/cli launches iterion run and host-schedule ticks directly; runview.Service launches studio/API and server-side automation requests. They share artifact loading, executor construction, the runtime engine, and run records. Local studio launches may execute in process or through a managed child; cloud launches are admitted by the server, published to NATS, and claimed by a runner.
Compilation pipeline
- Resolve the artifact —
pkg/dsl/workflowfileaccepts.bot, whilepkg/bundleloads.botzor a bundle directory, resolves adjacent resources, and computes the source identity used by resume. - Parse — the indentation-sensitive lexer and recursive-descent parser in
pkg/dsl/parserproduce the AST inpkg/dsl/ast. - Compile —
pkg/dsl/irexpands groups, binds schemas, prompts, variables, cursors, resources, and edges, then produces the executable graph. - Validate — structural and semantic passes check reachability, cycles and loop fuel, routing, convergence, capabilities, templates, sandbox settings, and backend constraints before execution. DSL diagnostics occupy C001–C199 plus the async-interaction band C240–C242; bundle consistency checks occupy C200–C234.
The compiler returns diagnostics rather than hiding repairs. The authoritative catalogue is references/diagnostics.md; the language surface is documented in dsl.md.
Runtime engine
runtime.Engine owns graph progress, branches, loops, budgets, checkpoints, and event emission. It delegates the work of one node to the NodeExecutor interface, keeping orchestration independent of a specific LLM or CLI agent.
Node execution
agentandjudgenodes use the model/delegation stack inpkg/backend.routernodes select edges through deterministic modes or an LLM decision.humannodes pause for persisted interaction or use an LLM interaction mode.toolandcomputenodes provide deterministic shell/action and expression steps. Verified Action nodes can recover a failed action while retaining a deterministic postcondition as the truth oracle.emitandwaitcoordinate branches through a reliable run-local event registry.await_answersparks a branch until pending async (ask_user_async) questions are answered — the deterministic sync point forinteraction: asyncnodes.subbotnodes launch child runs through a runtime seam, preserving run-tree provenance and optional isolation.doneandfailterminate the graph intentionally.
Branches and workspace safety
fan_out_all and fan_out_each can create concurrent branches. A shared semaphore enforces max_parallel_branches; a shared budget tracker accounts across all of them. Mutating branches are serialized by default. The explicit exceptions are isolated sub-bots and parallel_safe: true tool nodes inside a fan_out_each template whose writes are guaranteed to be item-partitioned.
Convergence is a property of the downstream node (await: wait_all or best_effort), not a separate join node. See routers.md and groups-iteration-subbots.md.
Checkpoints, recovery, and live control
The checkpoint stored in run.json is the authoritative continuation state. The engine saves progress after successful execution boundaries and preserves it for human pauses, cancellation, and resumable failures. Resume reconstructs the graph state without replaying completed upstream nodes.
Run-level automatic recovery can retry eligible transient failures. While a run is live, the operator can queue messages, grant more iterations to a loop, or raise budget ceilings. Overrides apply at a safe boundary, are recorded as run_steered, and are persisted so a later resume keeps them.
See resume.md, human-in-the-loop.md, and supervisors.md.
Execution backends and tools
pkg/backend/model supplies the production executor. It resolves launch overrides and node/workflow defaults, then dispatches to:
claw, the in-process multi-provider client with native Iterion tools;claude_code, the recommended external CLI agent for implementation work;- the generic CLI-agent seam used by Kimi Code and Grok Build;
- the frozen Codex compatibility delegate.
MCP servers, board capabilities, tool policies, permission checks, secret resolution, command-output rewriters, and cost hooks are assembled around the same executor. Backend-specific system-prompt modes preserve a native agent's operating prompt where it has one and add an authored base where it does not.
The exact support and credential matrix is backends.md.
Worktrees and sandboxes
worktree: auto creates a Git worktree before execution. Successful committed results are protected with a persistent branch; landing is controlled by the CLI or studio merge policy. A failed run keeps its worktree for inspection and resume.
Sandboxing is a separate execution adapter under pkg/sandbox, on by default at the product entry points (iterion run/resume, studio, dispatcher; opt out with sandbox: none or ITERION_SANDBOX_DEFAULT=none):
- Docker and Podman keep one long-lived container per run.
- The local workspace normally stays mounted at its host absolute path; an explicit
workspace_foldercan choose another target. - Kubernetes creates a sibling pod and copies the workspace to
/workspace. - Network mode is open by default. Allow/deny policy starts the CONNECT proxy.
- Local Docker can build an inline image with BuildKit; Kubernetes accepts pre-built images only.
- Bot-local and repository-local Devbox profiles are composed and added to
PATHfor every node.
See sandbox.md and merge-policy.md.
Persistence and streaming
Local store
Without an explicit store override, store.ResolveStoreDir uses a managed <project>/.iterion when it already exists; otherwise it chooses $ITERION_HOME/projects/<encoded-project-path>/ (normally under ~/.iterion/projects/). This avoids creating state inside every target repo and prevents unrelated projects from sharing an ancestor store accidentally.
The file-backed layout is:
<store-dir>/runs/<run-id>/
run.json metadata, status, checkpoint, steering state
events.jsonl append-only observational events
artifacts/<node>/<version>.json
interactions/<id>.json
user_messages.jsonl operator/supervisor conversation input
tools/<tool-use-id>/input large tool request payloads where needed
tools/<tool-use-id>/output large tool result payloads where needed
report.md generated chronological reportAdditional store subtrees hold the native dispatcher/board, marketplace data, project secrets, and run worktrees. Host schedule manifests and logs live under the global Iterion data directory unless explicitly overridden. See persisted-formats.md for the exact versioned formats.
Cloud store
Cloud mode replaces file-only storage with the store interfaces implemented on MongoDB and S3. NATS carries queued work, trigger events, and cross-process steering; store-specific run-stream sources feed the same WebSocket and REST projections used locally. Large IR and diff/file payloads can be persisted and referenced instead of being embedded in queue messages.
The control/data-plane split, claim protocol, and isolation model are detailed in cloud-architecture.md.
Control plane and automation
pkg/server serves the studio assets and REST/WebSocket API. pkg/runview supplies the read/control service consumed by that API and by the local product. The React/Vite application under studio projects editor, catalogue, run, board, pipeline, integration, automation, and administration views.
Automation enters through four complementary layers:
pkg/schedgate,pkg/cloudsched, and the host scheduler apply cron, overlap, guard, and tick-audit contracts;pkg/dispatcherowns the tracker actor, leases, retries, lifecycle hooks, and issue-to-bot dispatch;pkg/triggerpluspkg/eventbusnormalize board, run-completion, scheduled, and forge events;pkg/webhooksand server admission handlers authenticate, deduplicate, quota-check, and launch external events.
Cloud identity is organization → team. pkg/identity and pkg/auth own membership and active JWT context; pkg/forge owns repo connections, provider apps, hooks, installation tokens, and bot bindings. Quotas, audit, credentials, and PATs are separate packages and are enforced at the launch boundary.
Extension architecture
pkg/bundledefines the artifact boundary: workflow, manifest, skills, prompts, attachments, presets, and optional Devbox files.pkg/skilllibmanages operator-curated project/global skills referenced by the DSL.pkg/pluginresolves declarative, out-of-process contributions such as rewriters, MCP servers, skills, commands, agents, hooks, and lifecycle jobs.pkg/pluginsourcemakes plugin sources portable to cloud teams, including private Git-backed sources.pkg/marketplaceindexes both bot and plugin entries.
At run time these layers converge on resource mirroring, tool/MCP registration, and the rewrite chain; they do not bypass the compiler or dynamically load Go code. See bundles.md, skills-library.md, and plugins.md.
Repository map
| Path | Responsibility |
|---|---|
cmd/iterion/ | Cobra command registration and process entry points. |
cmd/iterion-desktop/ | Wails desktop wrapper around the embedded server/studio. |
pkg/dsl/ | Lexer, parser, AST, IR, expressions, types, unparser, workflow-file loading. |
pkg/runtime/ | Graph execution, concurrency, loops, budgets, checkpoints, recovery, worktrees. |
pkg/backend/ | LLM/delegated execution, tools, MCP, permissions, cost, credential detection. |
pkg/store/, pkg/runview/ | Persistence contracts and the shared run read/control service. |
pkg/server/, studio/ | HTTP/WebSocket control plane and React UI. |
pkg/dispatcher/, pkg/trigger/, pkg/eventbus/ | Issue and event-driven automation. |
pkg/cloud/, pkg/queue/, pkg/runner/ | Cloud configuration, NATS queue, and execution workers. |
pkg/identity/, pkg/auth/, pkg/forge/, pkg/secrets/ | Tenancy, access, repository integration, and credentials. |
bots/, examples/ | Maintained product bots and focused language/integration fixtures. |
Architecture decisions
Decision records under docs/adr/ are immutable, point-in-time explanations. Later ADRs and the current code can supersede earlier details. The living current-state overview, this page, and the domain references describe the as-built system.
