swarm / companies/lantern/company.toml

raw file 8251 bytes
# ─────────────────────────────────────────────────────────────────────────────
# Lantern Systems — a Rust browser-agent harness, connected over your LAN.
# Product: `harnessd` — a daemon any node on the network (Tailscale or plain
# LAN) can talk to, that drives a browser with an LLM agent loop and streams
# everything: events, screenshots, traces, nothing cloud-hosted, ever.
# The build gate is REAL: [verify] = cargo build + cargo test on the repo.
# ─────────────────────────────────────────────────────────────────────────────

[company]
name = "Lantern Systems"
mission = "Ship the local-first browser agent harness: a Rust daemon on your own network that any machine can reach over Tailscale or plain LAN — LLM-driven browsing with server-side sessions, token auth, live event streams, screenshots and traces. If it doesn't compile on main, it doesn't exist — and if it talks to the cloud, it's fired. HOUSE RULE: `cargo check` runs the moment any commit lands; read it fix it in-session before the full gate sees you."
product = "lantern-agent: `harnessd` binary + HTTP/WS API (sessions, tasks, tool-call event stream), a Browser abstraction (real Chromium + a scripted mock for CI), an LLM agent loop (OpenAI-compatible models, e.g. the team llama.cpp box), token auth, screenshots, trace logs."
stack = "Rust (axum, tokio, serde, ureq). Tests run against the scripted mock browser - no real browser in CI. Chromium/CDP lands later behind the same trait."

[verify]
# The build gate the whole company lives and dies by: compile + contract
# tests + a /healthz smoke. judge.sh prints FAIL lines naming owner files.
command = "cd work/project && sh judge.sh"
timeout_secs = 600

# Per-commit reflex: cargo check — the team's minimum bar before claiming
# anything is done. Errors land in work/project/check_report.md + mail.
[verify_fast]
command = "cd work/project && cargo check --quiet 2>&1 | head -30"
timeout_secs = 120

# Ten years of civilization, five people.

[[people]]
name = "Nia Odum"
role = "Team Lead / API Design"
personality = "API-contract zealot. Writes the route table before anyone writes rust, reviews every diff against it, and says 'contract is code' in meetings. Ships compile-green small changes. Protects the daemon's public surface: renaming a route = incident. Allocates browser-work to Rufus only when the mock is passing. Keeps the tailscale-ready setup as a stated product promise, not docs fluff."
is_manager = true

[[people]]
name = "Kazimir Novak"
role = "Systems & Networking Engineer"
personality = "Lantern's TLS tokens, bind addresses, proxy config are his. Allergic to localhost-only defaults ('it must bind 0.0.0.0 or it is a toy'). Speaks in exact curl commands. Wrote our token-auth scheme and defends it like a castle. Distrusts async code that cannot be reasoned about in sequence; draws sequence diagrams for every endpoint."
is_manager = false

[[people]]
name = "Rufus Whitley"
role = "Agent Loop Engineer"
personality = "Lives inside the tool-call protocol: strict JSON schemas, retries with backoff, and 'the agent must never be surprised by its own output'. Obsessed with the action vocabulary; will argue for an hour about whether `click` should be `click_at(x, y)` or `click(selector)` and has a documented opinion. Keeps the agent's failure modes as explicit enum variants, never with plain strings."
is_manager = false

[[people]]
name = "Imelda Cruz"
role = "QA / Test Architect"
personality = "Treats the scripted mock browser as the test contract: scripts pages as fixtures, hunts flakes on sight, treats 'it works locally' as an insult. Her mock fixture DSL is ruthless and she writes a new adversarial case for every bug we ship. Refuses to pass any review whose source of truth is only a passing demo; a test file must move."
is_manager = false

[[people]]
name = "Bea Lindqvist"
role = "Docs & Developer-Care"
personality = "Writes the README, the curl examples, and the actual getting-started path a stranger could follow on a Tailscale join in under five minutes. Bounces any PR that adds a flag without an example. Keeps the 'bells and whistles' checklist: if it's shipped, it's documented, with a curl that proves it."
is_manager = false

# Backlog — every acceptance gate is files-on-disk criteria; the [verify]
# command above compiles + tests whatever exists, every commit, every 17:00.

[[backlog]]
id = "T1"
title = "harnessd skeleton: axum server + /healthz + routes table"
description = "Open the repo. work/project must be a cargo project:  src/main.rs serves /healthz and a stubbed route table (POST /sessions, POST /sessions/{id}/task, GET /events/{id}, GET /metrics). Route names are the contract - stolen names are a review-bounce. Keep main() thin; run blocking work via the pool."
area = "systems"
effort_days = 2

[[backlog.acceptance]]
file = "src/main.rs"
min_lines = 40

[[backlog]]
id = "T2"
title = "Browser trait + scripted mock browser"
description = "Define the trait apps drive through: browse, click, type, screenshot, b. Implement MockBrowser in src/mock.rs with scripted fixture pages so Imelda's tests can drive scenarios without a real browser. Trait must be object-safe (Box<dyn Browser>)."
area = "browser"
effort_days = 3

[[backlog.acceptance]]
file = "browser.rs"
min_lines = 30

[[backlog]]
id = "T3"
title = "Agent loop: LLM driver + tool-call JSON schema"
description = "src/agent.rs: run a task against an OpenAI-compatible endpoint (default the team llama.cpp at http://localhost:8085/v1/chat/completions), parse tool-call JSON strictly, dispatch to Browser, loop until 'done' or budget exhausted. Failures are enum AgentError variants with a per-step retry, never strings."
area = "agent"
effort_days = 4

[[backlog.acceptance]]
file = "src/agent.rs"
min_lines = 60

[[backlog]]
id = "T4"
title = "Event stream: SSE + audit log JSONL"
description = "src/events.rs: every session emits structured events (ToolCall, PageEvent, Step, Result, Error) on GET /events/{id} as SSE and to a JSONL audit log sidecar file. Reconnecting clients get replay-from-byte framing or an explicit cursor."
area = "systems"
effort_days = 2

[[backlog.acceptance]]
file = "src/events.rs"
min_lines = 30

[[backlog]]
id = "T5"
title = "LAN-ready: token auth + tailscale story + bind flags"
description = "Kaz's castle: API token from env/config; 401 on mismatch; document the Tailscale/ plain-LAN join in docs/deployment.md (bind 0.0.0.0 default, curl examples from another tailnet node, optionally the `tailscale serve` variant). /metrics with basic counters for the ops page."
area = "systems"
effort_days = 3

[[backlog.acceptance]]
file = "src/auth.rs"
min_lines = 40

[[backlog]]
id = "T6"
title = "Bells: screenshots, session recordings, trace JSONL"
description = "Implement MockBrowser screenshot rendering (PNG/PPM sketch on the fixture), session.replay.jsonl, and a trace JSONL per step (LLM prompt excerpt, tool call, result). This is what makes the harness auditable after the fact."
area = "browser"
effort_days = 3

[[backlog.acceptance]]
file = "src/trace.rs"
min_lines = 40

[[backlog]]
id = "T7"
title = "The gauntlet: contract test suite"
description = "tests/contract.rs drives the mock end-to-end: session lifecycle, agent loop tool dispatch, full event stream shape, auth behavior. Bea's rule: every route behaves per its stub; a test case for every event type. Judge (judge.sh) runs this every commit."
area = "qa"

[[backlog.acceptance]]
file = "tests/contract.rs"
min_lines = 40

[[backlog]]
id = "T8"
title = "Getting-started: docs a stranger can follow"
description = "Bea's README + docs/deployment.md + docs/quickstart.md with a 5-minute path: cargo run harnessd, curl /healthz from a second machine over Tailscale, POST one task, watch the SSE. Every flag documented with an example. No example = not shipped."
area = "docs"
effort_days = 2

[[backlog.acceptance]]
file = "docs/quickstart.md"
min_lines = 20