fort

module
v0.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2026 License: MIT

README

Fort

Fort

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.

Two planes, two modes (one binary)

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 for fort serve, leave it out for fort control.

Architecture

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).

Quickstart

# 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 serve

The 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_gate

FORT_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.

Clients

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).
  • Appleui/apple: a shared FortKit package reused by iOS, macOS (menu bar), CarPlay, and watchOS (app + complication). make apple-build compiles them all. Deploy: docs/notes/testflight.md.

Multi-machine (spec 022, spec 024)

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 serve

fort 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.

Manual / hand-managed alternative

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 serve

Unset FORT_MACHINES ⇒ classic single-machine mode. When FORT_MACHINES is set, fort mesh refuses to write to it (it only manages its own file).

What needs you

  • The execution plane spawns real agent CLIs (claude, codex, hermes, openclaw) with your provider keys — see .env.example. The openclaw invocation is a best guess (spec 023) until the CLI is installed and probed; correct one line in exec/native/providers.go if it differs.
  • CarPlay ships only with Apple's category-gated entitlement (see the TestFlight note); the code compiles and runs in the simulator regardless.

Docs

Agent Ops Backlog/ (the plan), docs/notes/ (recon, decisions, threat model, control-plane, event contract, distribution, TestFlight), specs/ (specs).

License

MIT © 2026 Tobias Gunn.

Directories

Path Synopsis
cmd
fort command
Command fort is the fort-native CLI (backlog AO-018): route --dry-run, task add, runs list, run logs, gate, flow, schedule, and serve (the core daemon).
Command fort is the fort-native CLI (backlog AO-018): route --dry-run, task add, runs list, run logs, gate, flow, schedule, and serve (the core daemon).
Package control provides the adapters that plug Fort's deterministic components into the control-plane ports (ui.Dispatcher, ui.FlowRunner).
Package control provides the adapters that plug Fort's deterministic components into the control-plane ports (ui.Dispatcher, ui.FlowRunner).
Package core is the umbrella for Fort's deterministic orchestration modules: rules, router, runtime (the executor interface), task, store, graph, inbox, flow, scheduler, event, and server.
Package core is the umbrella for Fort's deterministic orchestration modules: rules, router, runtime (the executor interface), task, store, graph, inbox, flow, scheduler, event, and server.
config
Package config loads fort-core configuration from the environment with sane defaults (backlog AO-011).
Package config loads fort-core configuration from the environment with sane defaults (backlog AO-011).
engine
Package engine wires the deterministic router to native execution and the state store (backlog AO-015): a submitted task auto-routes, is persisted with its matched rule, and runs natively with zero manual assignment.
Package engine wires the deterministic router to native execution and the state store (backlog AO-015): a submitted task auto-routes, is persisted with its matched rule, and runs natively with zero manual assignment.
flow
Package flow loads and validates Fort flow definitions (YAML) into graph.Flow values (backlog AO-026/027).
Package flow loads and validates Fort flow definitions (YAML) into graph.Flow values (backlog AO-026/027).
graph
Package graph is Fort's deterministic DAG engine (backlog AO-021..025).
Package graph is Fort's deterministic DAG engine (backlog AO-021..025).
inbox
Package inbox sources new tasks from a watched directory and submits them to the engine (backlog AO-015: "watched file/dir" task source).
Package inbox sources new tasks from a watched directory and submits them to the engine (backlog AO-015: "watched file/dir" task source).
machines
Package machines is Fort's static machine registry and deterministic placement (spec 022).
Package machines is Fort's static machine registry and deterministic placement (spec 022).
router
Package router is Fort's deterministic matcher engine (backlog AO-013).
Package router is Fort's deterministic matcher engine (backlog AO-013).
rules
Package rules defines Fort's deterministic routing-rule schema and a strict parser for it (backlog AO-012).
Package rules defines Fort's deterministic routing-rule schema and a strict parser for it (backlog AO-012).
runtime
Package runtime defines the execution seam (backlog AO-014, spec §6.2).
Package runtime defines the execution seam (backlog AO-014, spec §6.2).
scheduler
Package scheduler fires flows on cron schedules and one-shot times (backlog AO-028) — the basis for "assign and walk away" and recurring digests.
Package scheduler fires flows on cron schedules and one-shot times (backlog AO-028) — the basis for "assign and walk away" and recurring digests.
server
Package server is fort-core's local HTTP/WS API (backlog AO-011): /health, graceful shutdown, and the event/command surface the fort-ui module consumes (the live-feed and command routes are added in Phase 3 on top of this).
Package server is fort-core's local HTTP/WS API (backlog AO-011): /health, graceful shutdown, and the event/command surface the fort-ui module consumes (the live-feed and command routes are added in Phase 3 on top of this).
store
Package store is Fort's SQLite state store (backlog AO-016, spec §6.6): run, node_run, route_decision, and an append-only event log.
Package store is Fort's SQLite state store (backlog AO-016, spec §6.6): run, node_run, route_decision, and an append-only event log.
task
Package task defines the Task — the atomic routable unit of work in Fort.
Package task defines the Task — the atomic routable unit of work in Fort.
exec
cluster
Package cluster composes a machine's local runtime with remote runtimes for its peers (spec 022).
Package cluster composes a machine's local runtime with remote runtimes for its peers (spec 022).
fake
Package fake is an in-memory runtime.Runtime for fast, deterministic unit tests (backlog AO-014: "Interface is mockable — a FakeRuntime powers fast unit tests").
Package fake is an in-memory runtime.Runtime for fast, deterministic unit tests (backlog AO-014: "Interface is mockable — a FakeRuntime powers fast unit tests").
gateway
Package gateway is an optional runtime.Runtime decorator (backlog AO-042) that puts spend caps, tracing, and failover in front of any underlying runtime — the role agentgateway/plano play in front of providers.
Package gateway is an optional runtime.Runtime decorator (backlog AO-042) that puts spend caps, tracing, and failover in front of any underlying runtime — the role agentgateway/plano play in front of providers.
meshjoin
Package meshjoin hosts the spec-024 enrollment endpoints on the hub daemon:
Package meshjoin hosts the spec-024 enrollment endpoints on the hub daemon:
native
Package native is Fort's NativeRuntime (backlog AO-014): it spawns agent CLIs itself — no Multica — normalizes their stdout into runtime.RunEvents, injects stdin for Signal (human-in-the-loop), and tracks exit codes.
Package native is Fort's NativeRuntime (backlog AO-014): it spawns agent CLIs itself — no Multica — normalizes their stdout into runtime.RunEvents, injects stdin for Signal (human-in-the-loop), and tracks exit codes.
node
Package node exposes a Fort's local runtime over HTTP so another Fort — the control plane — can dispatch runs to this machine (spec 022).
Package node exposes a Fort's local runtime over HTTP so another Fort — the control plane — can dispatch runs to this machine (spec 022).
relay
Package relay maintains fort serve's outbound tunnel to the 028 gateway: one WebSocket to the broker, per-client-session Noise IK handshakes (exec/relay/secure), and sealed HTTP/SSE service against an injected http.Handler — the transport never imports ui (seam: it moves bytes).
Package relay maintains fort serve's outbound tunnel to the 028 gateway: one WebSocket to the broker, per-client-session Noise IK handshakes (exec/relay/secure), and sealed HTTP/SSE service against an injected http.Handler — the transport never imports ui (seam: it moves bytes).
relay/secure
Package secure is Fort's E2E crypto contract for the relay (spec 028): a Noise IK handshake (X25519) between a client and the daemon's pinned static key, then ChaCha20-Poly1305 AEAD framing.
Package secure is Fort's E2E crypto contract for the relay (spec 028): a Noise IK handshake (X25519) between a client and the daemon's pinned static key, then ChaCha20-Poly1305 AEAD framing.
remote
Package remote dispatches runs to another Fort over HTTP (spec 022).
Package remote dispatches runs to another Fort over HTTP (spec 022).
Package ui is Fort's interface module (backlog Phase 3): the event/command contract (AO-031), the live board (AO-032), the SSE live-feed transport (AO-033), the chat surface (AO-034), the gate inbox (AO-035), and the OpenClaw inbound channel (AO-036).
Package ui is Fort's interface module (backlog Phase 3): the event/command contract (AO-031), the live board (AO-032), the SSE live-feed transport (AO-033), the chat surface (AO-034), the gate inbox (AO-035), and the OpenClaw inbound channel (AO-036).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL