- Go 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Vendor wire inspection (device-auth.js, device-identity.js, refresh-attempt.js) shows the gateway validates requestId as an RFC 4122 v4 UUID and expects timestamp as a JSON number / whole Unix seconds in the signed payload. Mirrors the vendor device-refresh-attempt.json persistence so retries reuse the same requestId for the same refresh token and clear it on success. Updates protocol docs and resolves open-question #23. |
||
| cmd | ||
| docs | ||
| examples | ||
| internal | ||
| .gitignore | ||
| CONTRIBUTING.md | ||
| go.mod | ||
| go.sum | ||
| ilands-openrunner.log | ||
| LICENSE | ||
| logs.txt | ||
| README.md | ||
ilands-openrunner
A clean-room, open-source iLands Runner written in Go. It connects an agent to the iLands gateway over the same live/heartbeat channel the official runner uses, runs any ACP harness behind a pluggable adapter, and gives ACP harnesses the same "first-class" treatment the official runner gives its supported harnesses (preflight probes, workspace artifacts, capability catalog, tool bridging).
Status: implementation in progress (M3/M4 minimum slice + warm harness). The gateway client, run loop, ACP harness adapter, and tool surface are implemented and unit-tested; a live end-to-end heartbeat turn has been proven against the test agent (run accepted → committed →
end_signalled→ready). The warm harness server (Phase 1) is implemented and unit-tested, pending one live verification. See Roadmap.
Status (M3/M4 slice)
Implemented and tested locally (go build ./... && go vet ./... && go test ./...):
- Gateway client (M2, live) —
doctor,auth activate/resumeagainst the production edge without touching any existing agent; the accepted activation proof format was derived black-box and is recorded indocs/protocol.md§4.1 (including the non-obvious rule thattimestampis a JSON number of Unix seconds). Unit tests run the same contract against a local fake gateway that cryptographically verifies every proof. - Run loop —
daemonholds the runner-live WebSocket (ticket → dial → backoff ladder), executes one heartbeat run at a time (duplicate runIds are re-acked, concurrent ones rejected, steers answereddelivered:false), appends a run ledger entry, commits the workspace journal once per session, and reportsruntime-status(ready/harness_*). - Harness adapter — generic ACP client over stdio (
initialize→session/new→session/prompt, permission auto-answer, chunk accumulation), terminal-signal race forend_heartbeat, spawn isolation (per-agentXDG_CONFIG_HOME, shared runner data/state/cache). - Warm harness server (Phase 1) — one long-lived
opencode acpprocess per daemon, spawned and initialized at connect (--harness-keep-warm, default on), reused across runs with single-flight turns, restarted on death or workspace config change, released after--harness-idle-ttl; sessions are fresh per run by default,--harness-session=reusekeeps one session up to a reuse cap withsession/compactprobe and rotation fallback. This deviates from the vendor's per-turn spawn (documented below and indocs/harness-contract.md§2): process boot dominated turn latency. - Tool surface — nine iLands tools with strict validation, per-run send
breaker,
replyTo="current"binding, prepare → sandbox-rpc executor with idempotency headers and 64 KiB result cap; themcpsubcommand serves them over stdio MCP exactly as the workspaceopencode.jsonregisters it. Run identity is resolved per tool call from the active-run record (fail closed without a valid one), so the warm harness can serve many runs. - Workspace — per-agent git repo (one commit per session), rendered
opencode.json(MCP registration + unattended permission policy),AGENTS.md, run prompt files.
Not yet: warm-server live verification (restart the daemon, message Void), refresh proof live (open-question #23), PATH shims, skill materialization, preflight/catalog first-class layer, second harness.
Decisions
| Decision | Choice |
|---|---|
| License | MPL-2.0 (LICENSE) |
| Provenance | Clean-room. Observed protocol behavior is reimplemented; no code, prompt prose, or binary assets are copied from the proprietary official runner. See CONTRIBUTING.md. |
| Harness model | One generic ACP client + per-harness "first-class" descriptors (opencode first, others pluggable). |
| Process model | One warm ACP process per daemon-agent (spawned at connect, reused across runs, idle-released). Deviation: the official runner spawns a fresh opencode acp per turn; keeping the process warm removes ~21 s of observed boot cost per turn. Documented in docs/harness-contract.md §2. |
| Official runner relationship | Separate, independent project. The official Node runner remains the production runner for our own agent — this project never replaces it automatically. |
Vendor CLIs (ilands, dl) |
Downloaded on first run from the official gateway, cached locally, never mirrored in this repository or in our releases. Redistribution permission from PawLogic to be requested later. Operators may point at their own copy via PATH. |
| Skills | Canonical bundle (41 top-level skills, 53 SKILL.md, 222 files, 4.16 MiB) is fetched with the vendor pack on first run, integrity-checked against a digest manifest, never mirrored. Agent-authored skills live in a durable skills-local/ that bundle updates never wipe (a deliberate divergence from the official runner's wipe-on-update). |
| Publication | Repo is private; publish only on explicit instruction. |
| Where | Local ./ilands-openrunner, private remote ilands-meka/ilands-openrunner on git.merith.xyz (branch main). |
Roadmap
| Phase | Deliverable | Gate |
|---|---|---|
| 0 | Repo bootstrap: LICENSE, README, CONTRIBUTING, private remote |
this repo |
| 1 | Specification set (the docs below) | done |
| 2 | Go: gateway MVP — device auth, live ticket, WebSocket, frame codec | done — activation spike against the live gateway |
| 3 | Go: run loop + generic ACP + first-class opencode profile, incl. skill materialization + discovery links + skills-local/ |
run loop + ACP + warm harness server implemented; live heartbeat turn proven on the test agent; warm-server live verify pending; skills not yet — we are here |
| 4 | Go: tool surface (compat RPC, MCP server, PATH shims) | prepare/RPC + MCP server implemented; live tool receipts + shims pending |
| 5 | Go: first-class layer — preflight engine, catalog, status machine, service install, skill doctor checks + global skill/plugin install | doctor passes on a clean machine |
| 6 | Second ACP harness | proves "any ACP harness" |
| 7 | CI, arm64/amd64 releases, docs, publish | tagged v0.1.0 |
Documents
| Document | Contents |
|---|---|
docs/protocol.md |
Wire contract: WebSocket frames, REST endpoints, proofs, local state files, open unknowns. |
docs/harness-contract.md |
The adapter interface, the ACP profile, and what "first-class support" means per harness. |
docs/tools.md |
The agent tool surface: compat RPC, MCP bridge, PATH shims, vendor CLI policy. |
docs/architecture.md |
Package layout, run lifecycle, status state machines, process model. |
docs/open-questions.md |
Behaviors we cannot observe from the client, and the decisions still owed. |
Scope notes
- Single agent per daemon. Two runners bound to the same agent fight over the
device slot (the gateway closes the older socket with
4001), so development uses a separate test agent. - Wire harness claim. The gateway only accepts a certified harness vocabulary on
activation; the runner therefore exposes a configurable
wireHarnessclaim while running whatever harness is configured locally. - Not a fork. No shared history, no shared source, no shared assets with the official runner.