Deterministic agent orchestration — route work, run it natively, gate it at humans.
Fort takes a task, routes it to the right agent by fixed rules (no model in the routing path), runs it by spawning the agent CLIs itself, and sequences multi-step work as a DAG that pauses at human gates. It runs as one native Go binary and exposes a control plane you can drive from the web, iOS, macOS, CarPlay, and Apple Watch.
Built native per the Agent Ops Backlog (rev. 2). The original TypeScript prototype was an experiment; this Go build is the delivered project. Governing spec:
specs/021-fort-native.md.
fort serve # full plane: control + deterministic execution
fort control # CONTROL PLANE ONLY — board, chat, scheduler, gate inbox, feed
# no router/runtime/DAG, no agent CLIs needed; tasks are boarded- Control plane — the human surfaces: Kanban board, chat, scheduler, gate inbox, live feed, and the client apps. Depends on nothing but the store.
- Execution plane (deterministic) — the router, the native runtime that
spawns
claude/codex/hermes/openclaw, and the DAG engine. Optional — plug it in forfort serve, leave it out forfort control.
One Go module, hard module seams (enforced by core/arch_test.go):
| Module | Role |
|---|---|
core/ |
deterministic orchestration: rules, router, runtime interface, store, engine, graph, inbox, flow, scheduler, server |
exec/ |
native execution: NativeRuntime (PTY-less CLI executor), FakeRuntime, gateway (budgets/tracing/failover) |
ui/ |
control-plane HTTP/SSE API + web board; imports none of the execution components |
control/ |
adapters wiring execution into the ui ports (or a queue-only dispatcher) |
rules/, flows/ |
the routing ruleset and flow definitions (YAML) |
cmd/fort/ |
the fort CLI |
ui/apple/ |
FortKit Swift package + iOS / macOS / CarPlay / watch clients |
Design tenets: routing is deterministic (proven by tests, zero model calls);
only task nodes invoke inference; every state change is an append-only
event (the feed + board are derived, replayable).
# install
brew install tobsai/tap/fort # or: make build -> ./bin/fort (needs Go 1.22+)
fort control # control plane at http://127.0.0.1:4087/
# or, with the execution plane + agent CLIs installed:
fort serveThe binary embeds a default ruleset, so fort serve works from any directory
with no checked-out repo.
Then open the board at /, or drive the API:
fort route --dry-run --label bug "null deref" # -> codex
fort task add --label research "read the repo" # auto-route + run natively
fort task breakdown "add search" # planner -> backlog sub-tasks
fort flow run ship-feature --input "add search" # DAG, pauses at gates
fort gate approve <run> plan_gateFORT_FAKE=1 runs a token-free fake runtime for demos/CI.
Break a goal into backlog sub-tasks with the board's Break down button or
fort task breakdown "<goal>" — a planner agent (FORT_PLANNER, default
claude) decomposes it into source=agent items you curate and drag onto the
board to run. It's a normal, visible run and needs the execution plane (fort serve); in control-only mode it 409s, like gates.
All surfaces speak one HTTP/SSE contract (docs/notes/event-contract.md):
- Web — served at
GET /: a three-zone dashboard (Define · Ready · In progress) — markdown compose with breakdown, Start buttons on ready work, live runs with nested tool/subagent activity and inline gate approvals, plus a light/dark theme toggle. Click any run to open a detail drawer: a flow shows its DAG steps and each step's own live log; a single run shows its live log. Task and backlog bodies render a safe markdown subset (headings, emphasis, code, lists, http(s) links). - Apple —
ui/apple: a shared FortKit package reused by iOS, macOS (menu bar), CarPlay, and watchOS (app + complication).make apple-buildcompiles them all. Deploy:docs/notes/testflight.md.
One control plane can orchestrate agents across several hosts (e.g. a Mac Mini +
a MacBook Pro). Fort routes each task to the agent (deterministic, as always)
and then to a machine that offers it — local or remote — streaming the run
back to the board you're watching. Remote execution is just another
runtime.Runtime, so the core is unchanged.
The easy path is fort mesh: it mints and distributes the shared token and
manages the registry for you — no file edits.
# hub (laptop)
fort serve &
fort mesh invite # prints: fort mesh join http://100.x.y.z:4087 --code XXXX-XXXX
# new machine (paste the printed line)
fort mesh join http://100.x.y.z:4087 --code XXXX-XXXX
fort servefort mesh invite mints the durable mesh token on first use (the hub then also
accepts inbound mesh exec) and prints a paste-ready fort mesh join line good
for one use within its TTL (--ttl, default 15m, capped at 1h). fort mesh join probes $PATH for agent CLIs (or takes --agents a,b), registers with
the hub, and writes this machine's identity. fort mesh remove <name> drops a
machine from the registry — see the token-rotation runbook in
docs/notes/threat-model.md for what it does
not do.
The board shows every host (with reachability) and tags each run with the machine
it ran on; chat and fort task add --machine <host> can pin a target. Placement
is deterministic: an explicit pin, else the local host if it offers the agent,
else the first host in the registry that does. Inter-host /api/exec is
bearer-token authenticated; keep it on a trusted LAN.
You can still hand-manage the registry and token instead of fort mesh:
cp machines.example.yaml machines.yaml # name + url + agents per host
# on each host that runs agents (expose on the LAN, share one token):
FORT_ADDR=0.0.0.0:4087 FORT_NODE_TOKEN=shared-secret fort serve
# on the host you drive (also knows the registry):
FORT_MACHINES=machines.yaml FORT_NODE_TOKEN=shared-secret \
FORT_NODE_NAME=mac-mini FORT_ADDR=0.0.0.0:4087 fort serveUnset FORT_MACHINES ⇒ classic single-machine mode. When FORT_MACHINES is
set, fort mesh refuses to write to it (it only manages its own file).
- The execution plane spawns real agent CLIs (
claude,codex,hermes,openclaw) with your provider keys — see.env.example. Theopenclawinvocation is a best guess (spec 023) until the CLI is installed and probed; correct one line inexec/native/providers.goif it differs. - CarPlay ships only with Apple's category-gated entitlement (see the TestFlight note); the code compiles and runs in the simulator regardless.
Agent Ops Backlog/ (the plan), docs/notes/ (recon, decisions, threat model,
control-plane, event contract, distribution, TestFlight), specs/ (specs).
MIT © 2026 Tobias Gunn.
