Documentation / Concepts
Inside the runtime
A tour of how the Seshat runtime is built: layers, one turn of the loop, one tool call, and what happens when a provider fails. With counts you can reproduce.
Architecture gives the short version. This page goes one level down, for people who want to extend the runtime, embed it, or simply judge how it is made. Everything below was checked against the source on 12 October 2026, dev branch, commit e151301. Counts change with the code: the last section shows how to recompute them.
The layers, and which way dependencies point
The direction is one-way: cmd/* calls pkg/sdk, which calls internal/*. A test, internal/archtest/boundary_test.go, fails when an internal/ package imports pkg/ outside a short, explicit allow-list. The public surface has 39 packages under pkg/ (types, the tool contract, providers, config, storage, vector, RAG, web, skills, MCP, workflow, connectors and more), and the implementation has 43 under internal/.
The terminal interface (tui/internal/seshattui) is a fork of the Charm Crush interface, under the FSL-1.1-MIT license. It drives the SDK through a bridge in its workspace/ package, like any other host.
What lives in internal/
| Group | Packages | Role |
|---|---|---|
| Execution | prompt, providers, execution, tools, permissions | Builds the system prompt in cached sections, talks to the models, runs tool calls, and decides what is allowed. |
| State and data | db, runtime, memory, vector, storage | SQLite for sessions, checkpoints, goals, vectors and tasks. Compaction and state backends (SQLite, files, memory). A long-term memory graph. |
| Platform services | web and the browser, sandbox, agent, mailbox, team, automation, auth, monitoring, hooks, modes | Web access, Docker or Landlock isolation, sub-agents and teams, scheduled work, OAuth, OpenTelemetry and Prometheus, shell hooks, and the plan and execute modes. |
One turn: what the loop does
A user message starts a turn. A turn is a loop of up to 100 iterations by default (one model call, then its tools, then the next model call), inside a session limited to 100 turns by default in the SDK. Every transition is recorded as one of Continue, ContinueWithRecovery or Terminate, so a turn can always be explained afterwards.
- Start. The
query_starthook runs with the session, the turn, the permission mode and the model. It only observes. - Iteration begins. The iteration counter goes up and the
iteration_starthook can stop the turn. If stage detection is on, the system prompt is refreshed when the stage of the conversation changed (for example after a tool result). - Preparation. Messages are prepared, the toolsets are resolved, and auto-compaction runs when the context is getting full. A failed compaction ends the turn instead of sending a broken request.
- Model call, streamed. Retries and fallbacks happen here (see the last section).
- Does the answer contain tool requests? If yes, the orchestrator runs them (in parallel when they are safe to run together, in series otherwise), appends the results, and the
tool_uses_completehook fires. If atool_searchcall discovered deferred tools, the loop continues with a recovery transition so the new tools are available. - No tool requests. Before the turn can end, the loop looks for a reason to go on. If the model hit its output limit, it is told to resume. If it only announced a next step (“I will now…”), it is nudged to continue, at most three times. If a token budget remains, the loop can continue for it. Last, the stop hooks run and may ask for one more cycle.
- End. The
query_completehook receives the result and a recovery context.
A recoverable error during the model call goes through tryRecovery with an exponential backoff, then the loop starts the iteration again. The turn ends when the model has nothing left to do, a hook stops it, the iteration cap is reached (max_iterations_reached), or the context is cancelled.
One tool call: the pipeline
Every tool call goes through the same stages, and each one reports its progress so interfaces can show it. An OpenTelemetry span named tool <name> wraps the call.
- Validate the input, then fill in what hooks and permissions need to see.
- Pre-hooks can stop the call or rewrite its input.
- Safety check. A checker looks for dangerous patterns and can refuse with a stated reason. It is not disabled by the most permissive permission mode.
- Permissions, local then global. There are six modes:
onRequest(the default),auto(a model-based classifier decides),acceptEdits,bypass,neverandgranular. - The call itself.
- Post-hooks, then the tool formats its own result, truncated on a character boundary so it never cuts a UTF-8 sequence.
Before the pipeline, calls are partitioned: tools declared safe for concurrency run in one parallel batch, the others run one after the other.
When a provider fails
Seshat reaches 16 providers through one interface: Anthropic, OpenAI, Codex, Mistral, Gemini, MiniMax, OpenRouter, DeepSeek, OpenCode, Z-AI, Ollama, Bedrock, Vertex, Foundry, Kimi and Workers AI. Failures are handled in layers, from the cheapest to the most drastic:
| Layer | What it does |
|---|---|
| Retry | Exponential backoff with jitter. Errors are classified (client, authentication, rate limit, network, overload) so only the retryable ones are retried. |
| Fallback model | If retries fail, the next model in Routing.FallbackModels is tried. |
| Fallback provider | If the models are exhausted, a configured fallback provider is tried through its own client. Nothing leaves your chosen vendor unless you list one. |
| Circuit breaker | One per provider. After 5 consecutive failures the circuit opens and calls fail immediately without touching the provider. After 60 seconds it half-opens and lets 3 trial calls through; if they succeed, it closes. |
A non-recoverable error is terminal at once: the loop does not retry what cannot succeed.
By the numbers
Counted on 12 October 2026, dev branch, commit e151301.
| What | Count |
|---|---|
| Go version | 1.26.9 |
| Go files | 1,232 (947 without tests) |
| Lines of Go, without tests | 214,361 |
| Lines of Go, tests only | 65,483 |
Packages under internal/ | 43 |
Packages under pkg/ | 40 |
| Providers | 16 |
| Built-in tools in the default registry | 129 (95 enabled without keys) |
The terminal interface, a fork, and the tools make up the largest share of the code. The agent core itself (engine, execution, prompt and permissions) is much smaller.
Where to go next
Updated on 2026-10-13