Reference · Deployment
One binary. Nine shapes. Pick the one your infrastructure already has.
A single static Go binary, CGO_ENABLED=0, no runtime dependencies. Deploying it is copying a file and deciding what listens where.
01 / The constant
Four parts, and the relationship never changes.
Every topology below rearranges where these run. None of them changes what talks to what.
Solid blue is the engine, the only part Ion ships. Dashed is the model, which is not ours and not in your host. The two grey boxes are yours.
02 / Topologies
Worked topologies
A sample, not an inventory. Filter by what you actually have, or compare two shapes side by side.
Where the pieces sit
One machine
One host
Everything on one box, talking over a unix socket. This is the shape you develop against and the shape a small operation can run in production without apology.
A row is a starting point, not a commitment. Turn on comparison to hold two shapes side by side.
03 / Manifests
The files you would actually write.
Five configurations you can copy as they are.
04 / Listeners
Paths, ports, and one thing to know before you open a port.
ION_SOCKET_PATH, ION_PID_PATH and ION_EXIT_PATH take precedence over ION_DATA_DIR. Give ION_SOCKET_PATH a host:port value and the engine listens on TCP instead of a unix socket.
The TCP listener is unauthenticated
That listener has no authentication. There is no token, no handshake, no client certificate check. The engine accepts a connection, reads a command and runs it. The listener is plaintext, and there is no TLS option on it. The address is used exactly as given, so a bare :PORT binds every IPv4 interface. The engine does not restrict the bind, and it does not warn. The unix socket path gets a filesystem boundary because the engine creates ~/.ion with mode 0700. TCP has no equivalent, so the boundary has to come from the network around it.
Bind
Bind 127.0.0.1 and reach it through an SSH tunnel.
Network
Keep the host on an isolated network segment.
Firewall
Restrict the port with host firewall or security-group rules.
Proxy
Put a TLS or mutual-TLS terminating proxy in front of it.
These are controls outside the engine. None of them adds authentication to the listener itself.
05 / Host
What the host has to provide.
Published binaries cover Linux amd64, macOS amd64 and arm64, and Windows amd64. The published container image is linux/amd64 only.
Network egress is the cost driver, not the engine: provider API calls dominate bandwidth and latency. If policy requires the sandbox, a session on a platform without support does not start. No disk-capacity requirement is documented.
06 / State
What is on disk, and what you back up.
What ION_DATA_DIR moves
Point it at a per-instance root and conversations, the scheduler and the runtime files follow it. That is what lets several engines run on one host without colliding on paths or sharing sessions.
What stays under ~/.ion
ION_DATA_DIR scopes instance state, not identity. Credentials, tokens, user config, extensions and the operational log stay at the home path, so instances on one host share one credential store and one log. Enterprise config has its own override, ION_ENTERPRISE_CONFIG.
Backup boundary
Back up conversations/. Add session-bindings.json if the same session keys must resume their conversations. Credential and MCP token files hold secrets, so back them up only if the process is approved to hold secrets.
Discarding the conversation store loses history, branches, stored attachments, persisted tool results, conversation memory and dispatch history. Sockets and PID files are runtime files, not backup data.
07 / Operating it
Health, logs, and what a restart costs.
Health
ion health is the image HEALTHCHECK. It connects to the configured socket, sends a health command, prints JSON, and exits 0 when the engine answers ok. It exits 1 when it cannot connect, gets an error, or gets no health data. It needs a running engine, not a session.
The response carries engine version, start time, uptime, session count and socket path. For an HTTP liveness probe, bridge HTTP to the socket in a sidecar.
Logs, and where they go
Operational logging is on by default and local: NDJSON at ~/.ion/engine.jsonl. Downstream egress is opt-in through logging.egressTargets: http POSTs batches to logging.egressEndpoint, otel exports OTLP log records. Empty is the default and means local file only.
Telemetry is disabled by default. Enabled with no target it writes ~/.ion/telemetry.jsonl.
msg is a constant, data-free clause so it stays groupable; all variable context goes in fields. Correlation IDs stay top level and are not interchangeable: conversation_id is durable across restarts, trace_id is scoped to one prompt-to-completion run, session_id to one client connection. Omitted, never empty, when out of scope. Source: observability/log-schema.md.
What a restart costs
Less than you would expect. The conversation store is written as the work happens, so a restart cannot lose what already occurred. What a restart interrupts is live identity, and the engine journals enough to continue the root run when recovery is enabled.
08 / Worth knowing
Six details that change how you deploy it.
- ION_SOCKET_PATH takes a host and port as well as a path. Give it host:port and the engine listens on TCP; the CLI and your clients connect the same way either way.
- ION_DATA_DIR scopes per-instance state, so several engines can run on one host without colliding. It moves conversations, the scheduler and the runtime files; credentials, user config and the operational log stay under ~/.ion.
- ion prompt --output json is the whole integration story for a pipeline. One command, structured output, exit code you can branch on.
- A row in that table is a starting point, not a commitment. Nothing coordinates these choices, so nothing constrains them.
- ion upgrade replaces the binary in place after a SHA-256 checksum check, and refuses to upgrade a development build. Conversations are read forward by a newer engine; reading them with an older engine after a downgrade is not documented.
- Only the latest release of each component gets security fixes. There is no backport to an older release, so staying current is the update path.
Next: the same pieces, assembled and running
In practice