{"id":51572967,"url":"https://github.com/dshakes/lantern","last_synced_at":"2026-07-10T21:03:09.845Z","repository":{"id":366489886,"uuid":"1208283808","full_name":"dshakes/lantern","owner":"dshakes","description":"Production runtime for AI agents — run the whole stack locally with one command, ship to your own cloud. Real WhatsApp/Slack/voice/web channels, multi-LLM routing, durable workflows, cost forecasting, eval-in-CI, and verifiable receipts. Apache-2.0.","archived":false,"fork":false,"pushed_at":"2026-07-06T12:02:55.000Z","size":293929,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-07-06T13:06:15.810Z","etag":null,"topics":["agent-framework","ai-agents","firecracker","go","llm","mcp","multi-tenant","observability","rust","self-hosted","typescript","workflow-engine"],"latest_commit_sha":null,"homepage":"https://dshakes.github.io/lantern/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dshakes.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":"docs/roadmap/2026-07-ga-audit-and-industry-leader-plan.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-12T04:13:42.000Z","updated_at":"2026-07-06T12:03:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dshakes/lantern","commit_stats":null,"previous_names":["dshakes/lantern"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dshakes/lantern","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dshakes%2Flantern","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dshakes%2Flantern/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dshakes%2Flantern/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dshakes%2Flantern/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dshakes","download_url":"https://codeload.github.com/dshakes/lantern/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dshakes%2Flantern/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35343136,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-10T02:00:06.465Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-framework","ai-agents","firecracker","go","llm","mcp","multi-tenant","observability","rust","self-hosted","typescript","workflow-engine"],"created_at":"2026-07-10T21:03:07.425Z","updated_at":"2026-07-10T21:03:09.836Z","avatar_url":"https://github.com/dshakes.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# 🏮 Lantern\n\n**The agent platform you run on your laptop and ship to production with one command.**\n\nReal channels · multi-LLM routing · durable workflows · predictable cost · eval-in-CI · cryptographically verifiable receipts — in your own cloud.\n\n[![License](https://img.shields.io/badge/license-Apache--2.0-blue?style=flat-square)](LICENSE)\n[![Go](https://img.shields.io/badge/Go-1.23+-00ADD8?style=flat-square\u0026logo=go\u0026logoColor=white)](https://go.dev)\n[![Rust](https://img.shields.io/badge/Rust-2024-CE412B?style=flat-square\u0026logo=rust\u0026logoColor=white)](https://www.rust-lang.org)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.7-3178C6?style=flat-square\u0026logo=typescript\u0026logoColor=white)](https://www.typescriptlang.org)\n[![Next.js](https://img.shields.io/badge/Next.js-15-000000?style=flat-square\u0026logo=next.js\u0026logoColor=white)](https://nextjs.org)\n\n```bash\nmake dev        # zero-toolchain: full stack in Docker\n# — or —\nlantern dev     # hot-reload daily driver: infra + API + dashboard + bridges\n```\n\n\u003c/div\u003e\n\n---\n\n## The pitch\n\n**An agent demo takes an afternoon. Agents in *production* take a year.** Durable execution so a crash doesn't lose state or double-spend tokens. A cost forecast finance will actually sign — with a hard cap that blocks the runaway tool loop *before* it bills. An eval gate in CI so a prompt tweak can't silently regress in front of users. Real isolation for untrusted code — a microVM, not a container on a shared daemon. And the channels your users actually live on, not another vendor dashboard.\n\n**Lantern is the runtime that solves the production half — and runs entirely in _your_ cloud.** Your prompts, tokens, and customer data never leave your VPC. One command runs the whole stack on your laptop; one ships it to your own Kubernetes.\n\nThe bet: those primitives are identical whether the agent is a headless backend worker or a personal assistant **texting your family on your real number**. Build the runtime once — durable steps, capability-routed models (`model: \"auto\"`), hard budgets, microVM isolation, cryptographically verifiable receipts, real channels — and you get both. The system around the model is the moat, not the model.\n\n\u003e Read the full thesis — problem, insight, why-now, the five modules — in [`PITCH.md`](PITCH.md).\n\n---\n\n## What is Lantern?\n\nLantern is a **production runtime for AI agents** with a control-plane / data-plane split: Go/Rust orchestration layer manages agents, runs, budgets, evals, and routing — while your prompts and customer data stay in your own VPC. 100% Apache-2.0. No feature gates.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/lantern-architecture.svg\" alt=\"Lantern architecture — control plane, data plane, surfaces, and data stores\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n---\n\n## Why Lantern?\n\n| Most agent frameworks | Lantern |\n|---|---|\n| `npm install` + a tutorial | **One command** boots Postgres + Redis + MinIO + control-plane + dashboard + bridges, with hot reload |\n| Chat-only, inside their dashboard | **Real channels** — WhatsApp, iMessage, Slack, Telegram, Discord, voice (Twilio/LiveKit), embeddable webchat |\n| \"Your agent probably costs about…\" | **Cost forecast before every run** — `POST /v1/runs/forecast` returns tokens, dollars, and confidence; hard-fail budgets block overspend with HTTP 402 |\n| \"Monitor your evals in prod\" | **Eval-in-CI + rehearsals** — pin a baseline per branch, fail the build on regression (HTTP 422), replay real failures against a candidate before flipping traffic |\n| A visual builder that only *saves* a graph | **A workflow engine that *executes* the graph** through the same router + connector + budget pipeline |\n| \"Trust us about what happened\" | **Cryptographically verifiable receipts** — Ed25519-signed over the run's journal; verify offline at `/.well-known/lantern-receipts` / `/proof` |\n| \"Deploy to *our* cloud\" | **Deploy in *your* cloud** — data plane in your VPC, Kubernetes-default substrate, outbound-only mTLS tunnel |\n\n---\n\n## How it works\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/run-lifecycle.svg\" alt=\"Agent run lifecycle — budget gate, durable steps, capability routing, microVM isolation, signed receipt, eval-in-CI loop\" width=\"100%\"\u003e\n\u003c/p\u003e\n\nEvery run passes through the same path — budget gate → durable step execution → capability-based LLM routing → isolated execution → signed receipt. Doesn't matter if it started as a WhatsApp message or a backend job.\n\n\u003cimg src=\"docs/assets/cp-dp-architecture.svg\" alt=\"Control-plane / data-plane architecture — Auth → Budget → Identity → Scheduler dispatch in the SaaS control plane; runtime-scheduler → runtime-manager → in-VM harness in the data plane; gRPC tenant metadata flows down, mTLS heartbeat and audit events flow back up to the receipt signer\" width=\"100%\"\u003e\n\n---\n\n## Five modules, one runtime\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/modules.svg\" alt=\"Lantern's five modules over one shared runtime\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n| Module | What it gives you | Maturity |\n|---|---|---|\n| **1 · Agent Runtime** | Durable workflow engine, capability-based multi-LLM router, Kubernetes-default substrate with isolation as a RuntimeClass tier (runc → gVisor → Kata microVM → Firecracker-backed Kata). Fail-closed: untrusted/hostile refused unless the hardened RuntimeClass is configured — never silently downgraded to a bare pod. Durable crash-replay (exactly-once, no re-spent tokens). One trace per spawn (W3C across CP → scheduler → manager → harness). Ed25519 per-instance identity + scheduler HA + per-tenant spawn rate limiting. | Phases 0–4 landed; Phase 5/6 (frontier UX, confidential compute) on roadmap |\n| **2 · Personal Agent (\"Jarvis\")** | WhatsApp + iMessage assistant that texts *as you* — owner-only, learns your real voice from history, agentic macOS actions, cross-channel memory, urgent-alerting, privacy guards. | Live |\n| **3 · Trust \u0026 Governance** | Policy-as-code budgets (hard-fail 402), eval-in-CI + rehearsals, Ed25519-signed verifiable receipts, per-agent-instance identity tokens, RBAC scopes on runtime routes, gRPC service-token auth, OTel traces (tenant_id/run_id/step_id), LLM idempotency keys on all provider calls, AES-256-GCM secrets. RLS policies on all 34 tenant tables — enforcement staged via `LANTERN_RLS_ENFORCE` (handler cutover in progress). | Substantially complete; RLS enforcement pending cutover |\n| **4 · Channels \u0026 Reach** | WhatsApp · iMessage · Slack · Telegram · Discord · Voice (Twilio/LiveKit) · Webchat · Email — signature-verified, naturally paced. | Prod-ready |\n| **5 · Developer Experience** | TS/Python/Go SDKs, `lantern` CLI, one-command dev, visual workflow editor that *executes*, MCP registry, A2A cards, forkable agent marketplace. Python SDK: management surface at parity; runtime `AgentContext` still stubbed. | Prod-ready (TS); Python management parity done, runtime context pending |\n\n\u003e **Status (as of 2026-06-23):** modules 2–5 are in real use. Module 1 is substantially complete:\n\u003e - ✅ **K8s-default substrate + RuntimeClass tiering** — `STANDARD` runs on gVisor, `HOSTILE` on Kata, fail-closed double gate in `choose_backend` + `build_job` (never downgrades to a bare pod). Node-affinity, per-workload default-deny NetworkPolicy, PSA-restricted, cosign image verification, and the boot-time RuntimeClass preflight are all landed (#36).\n\u003e - ✅ **Durable crash-replay** — journal-backed exactly-once execution: no re-spent tokens on crash, side-effect dedup via `side_effect_receipts`, run lease + recovery watchdog (#38).\n\u003e - ✅ **One-trace-per-spawn observability** — W3C `traceparent` propagates CP → scheduler → manager → harness; GenAI semconv spans carry reasoning and cache tokens; real-time loop/retry anomaly events mid-run; `GET /v1/runtime/metrics` for the cockpit Live mode (#39).\n\u003e - ✅ **Ed25519 per-instance identity** — minted at spawn, presented as Bearer on `VendSecret`, externally verifiable at `/.well-known/lantern-agent-identity`; flag-gated RLS `lantern_app` role (#40).\n\u003e - ✅ **Cluster-e2e execution legs** — gVisor leg validates `runsc` in CI; Kata legs (guest kernel ≠ host kernel, dedicated-pool no-co-tenancy) ship wired + documented and skip without an operator-provided kubeconfig (GitHub-hosted runners cannot nest-virtualize — not faked) (#41).\n\u003e - ⚠️ **Still open:** live Kata execution and RLS flag-flip need operator-run cluster validation; Phase 5/6 (flight-recorder UX, confidential compute) remain on the roadmap. Nothing pretends to be done that isn't.\n\n---\n\n## Agent runtime — the execution kernel\n\nThe runtime is the load-bearing core: a vendor-operated, multi-tenant, **durable** agent runtime that executes inside *your* VPC, with a tamper-evident, externally-verifiable, data-plane audit substrate. Kubernetes is the default substrate ([ADR\u0026#160;0009](docs/adr/0009-kubernetes-default-runtime-substrate.md)); isolation is a RuntimeClass tier on a pod, not a separate backend.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/runtime-architecture.svg\" alt=\"Agent Execution Kernel — control-plane (identity, secret relay, report ingestion, receipts, OTel) → HA scheduler → per-node manager (K8s-default, fail-closed isolation gate, hardened pods) → in-VM harness (mTLS, egress deny-default, cert-bound report), over a durable journal + Ed25519 receipt spine\" width=\"100%\"\u003e\n\u003c/p\u003e\n\nEvery spawn produces **one correlated chain** — `schedule → place → spawn → identity → vend → egress → report → terminate` — where each link shares `(tenant_id · run_id · step_id · agent_instance_id · trace_id)` and is replayable and externally verifiable.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/runtime-lifecycle.svg\" alt=\"Runtime lifecycle sequence — schedule with quota gate, mint per-instance identity, 5-factor placement, hardened K8s Job, mTLS heartbeat, VendSecret with Bearer, deny-default egress, cert-bound report ingestion, journal append, terminate with grace window, Ed25519 receipt\" width=\"100%\"\u003e\n\u003c/p\u003e\n\nIsolation is **fail-closed**: untrusted/hostile workloads are refused unless the hardened RuntimeClass is present — double-gated in `choose_backend()` and again in `build_job()`, never downgraded to a bare pod.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/runtime-isolation-tiers.svg\" alt=\"Isolation matrix — TRUSTED→runc, STANDARD/UNTRUSTED→gVisor, HOSTILE→Kata microVM (no co-tenancy), WASM, DEVCONTAINER; the fail-closed double gate; per-pod securityContext hardening; and opt-in cluster-side Kyverno baseline, cosign image verification, Cilium egress, and External Secrets Operator\" width=\"100%\"\u003e\n\u003c/p\u003e\n\nDefense-in-depth across governance, security, scalability, resiliency, and observability — with the trust boundaries made explicit (the harness, caller env, and `X-Forwarded-For` are all treated as untrusted input).\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/runtime-security-layers.svg\" alt=\"Runtime defense-in-depth — concentric isolation rings, the five non-negotiables, explicit trust boundaries, the three review layers that each caught real bugs, and the standards (OWASP Agentic Top-10, EU AI Act, IETF Agent Audit Trail, OTel GenAI semconv) the architecture is built against\" width=\"100%\"\u003e\n\u003c/p\u003e\n\nFull strategy, gap analysis vs. AgentCore / Vertex / Anthropic / OpenAI / Temporal, and the phased roadmap: [`docs/architecture/18-agent-runtime-nextgen.md`](docs/architecture/18-agent-runtime-nextgen.md).\n\n---\n\n## Headless agent runtime in 60 seconds\n\nWrite an `agent.yaml`, pick an isolation class, run it:\n\n```yaml\n# my-agent.yaml\napiVersion: lantern.dev/v1\nkind: AgentSpec\nmetadata:\n  name: hello\nspec:\n  image_digest: lantern/demos/hello@sha256:0000...0001\n  isolation: standard          # gVisor; the default for most agents\n  limits:\n    vcpu: \"250m\"\n    memory: \"128Mi\"\n    timeout: 60s\n  secrets:\n    - env_name: OPENAI_API_KEY\n      secret_uri: lantern.secret://tenant/my-tenant/key/openai\n  egress_rules:\n    - host: api.openai.com     # harness denies everything else\n  idempotent: true\n```\n\n```bash\nlantern run my-agent.yaml --input '{\"task\": \"summarize the news\"}'\n# → vm_id: vm_01abc...\nlantern vm logs vm_01abc -f\n# → [harness] booted in 340ms  [workload] summarizing…  [workload] done\n```\n\nThe run is **journaled and crash-replayable**: if the process dies mid-step,\nthe recovery watchdog restarts it and the journal returns cached step results —\nno re-spent tokens, no double API calls. When it finishes:\n\n```bash\ncurl -X POST http://localhost:8080/v1/runs/\u003crun_id\u003e/receipt \\\n  -H \"Authorization: Bearer $LANTERN_API_TOKEN\"\n# → Ed25519-signed receipt, verifiable offline at /.well-known/lantern-receipts\n```\n\nFull walkthrough: [`docs/guides/headless-agent-quickstart.md`](docs/guides/headless-agent-quickstart.md).\nFour end-to-end demo agents: [`examples/headless-agents/`](examples/headless-agents/).\n\n---\n\n## Documentation map\n\n| Resource | Where |\n|---|---|\n| **User guides** (quickstart, isolation, durable execution, observability, identity, receipts) | [`docs/guides/`](docs/guides/) |\n| **Architecture docs** (all 18 components + ADRs) | [`docs/architecture/`](docs/architecture/) · [`docs/adr/`](docs/adr/) |\n| **Runtime strategy + gap analysis** | [`docs/architecture/18-agent-runtime-nextgen.md`](docs/architecture/18-agent-runtime-nextgen.md) |\n| **Operator runbooks** (control-plane, data-plane, DB, gateway, scheduler, budget, restore) | [`docs/runbooks/`](docs/runbooks/) |\n| **Prometheus alerts + Grafana dashboards** | [`infra/monitoring/`](infra/monitoring/) |\n| **Demo agents** | [`examples/headless-agents/`](examples/headless-agents/) |\n| **Manual runtime test walkthrough** | [`examples/headless-agents/MANUAL-TEST.md`](examples/headless-agents/MANUAL-TEST.md) |\n| **Docs site** (full reference, served at `:3002` in dev) | `apps/docs/` · `make docs-dev` |\n| **Personal assistant setup** | [`docs/personal/BOT-SETUP.md`](docs/personal/BOT-SETUP.md) |\n| **Repo conventions + invariants** | [`CLAUDE.md`](CLAUDE.md) |\n\n---\n\n## Quick start\n\n```bash\ngit clone https://github.com/dshakes/lantern.git\ncd lantern\nmake dev          # builds + starts the full stack\n```\n\nOpen **http://localhost:3001** · log in with **`admin@lantern.dev` / `lantern`** · run `make seed` for sample data.\n\nVerify the stack is ready before doing anything else:\n\n```bash\n( cd packages/cli \u0026\u0026 go install ./cmd/lantern )\nlantern doctor    # checks health, auth, LLM provider, and a live run\n```\n\n\u003e The macOS WhatsApp/iMessage bridges need macOS Contacts/Calendar/chat.db — they are not part of the Linux `make dev` stack. Run them on a Mac with `lantern dev` or `make run-whatsapp-bridge` / `make run-imessage-bridge`. First time? `make bridge-setup` is an interactive wizard.\n\n\u003cdetails\u003e\n\u003csummary\u003eOption B — hot-reload daily driver (\u003ccode\u003elantern dev\u003c/code\u003e)\u003c/summary\u003e\n\nNeeds Go + Node installed (see [Prerequisites](#prerequisites) below).\n\n```bash\n( cd packages/cli \u0026\u0026 go install ./cmd/lantern )   # build the `lantern` binary\nlantern dev\n```\n\n`lantern dev` installs npm deps on first run and will:\n- Start **Postgres + Redis + MinIO** via Docker (detached)\n- Run the **control-plane** API (`:8080` REST, `:50051` gRPC) as a host Go process with hot reload\n- Run the **Next.js dashboard** (`:3001`) with HMR\n- Run the **WhatsApp** (`:3100`) and **iMessage** (`:3200`, macOS only) bridges\n- Tail every process with per-service color tags, then open `http://localhost:3001`\n\n```bash\nlantern dev --infra-only          # just Postgres + Redis + MinIO\nlantern dev --no-open             # don't auto-open the browser\nlantern dev --with-whatsapp=false # skip the WhatsApp bridge\nlantern dev --dashboard-port 4000\nlantern dev down [--volumes]      # stop everything (optionally wipe data)\nlantern dev logs \u003cservice\u003e -f     # tail a single container\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eOption C — à la carte (power users)\u003c/summary\u003e\n\n```bash\nmake dev-infra             # terminal 1: Postgres + Redis + MinIO\nmake run-api               # terminal 2: control-plane on :8080\nmake dashboard-dev         # terminal 3: dashboard on :3001\nmake run-whatsapp-bridge   # terminal 4 (optional): WhatsApp bridge on :3100\n```\n\n\u003e `make run-api-free` routes LLM calls through your local `claude` CLI (Claude Max subscription) — run the full platform at **$0** in development.\n\n\u003c/details\u003e\n\n\u003ca id=\"prerequisites\"\u003e\u003c/a\u003e\n\u003cdetails\u003e\n\u003csummary\u003ePrerequisites\u003c/summary\u003e\n\n`make dev` needs **only Docker**. Host-process development needs:\n\n| Tool | Version | Needed for | Install (macOS) |\n|---|---|---|---|\n| **Docker** + Compose v2 | recent | everything (infra always runs in containers) | `brew install --cask docker` |\n| **Go** | **1.23+** (CLI needs **1.25+**) | control-plane, engine, scheduler, SDK-go, CLI | `brew install go` |\n| **Node.js** | **20 LTS+** | dashboard, landing, docs, SDK-ts, bridges | `brew install node` |\n| **Rust** | **1.85+** (edition 2024) | gateway, model-router, runtime-manager, harness | `brew install rustup-init \u0026\u0026 rustup-init` |\n| **make** | any | task runner | preinstalled / Xcode CLT |\n| **protoc** + `ts-proto` | recent | only `make proto` (regenerating types) | `brew install protobuf` |\n\nOn Linux: `apt install golang nodejs npm docker.io protobuf-compiler`, `rustup` from rustup.rs.\n\n**Dev credentials** (seeded, local only — never use in production):\n\n| Service | Value |\n|---|---|\n| PostgreSQL | `postgres://lantern:lantern@localhost:5432/lantern?sslmode=disable` |\n| Redis | `redis://localhost:6379` |\n| MinIO | `lantern` / `lanternsecret` at `localhost:9000` (console `:9001`) |\n| Dashboard login | `admin@lantern.dev` / `lantern` |\n| Dev tenant / user | `00000000-…-0001` (slug `dev`) / `00000000-…-0002` (role `owner`) |\n\nFor optional integrations (Google OAuth, real LLM keys, connector OAuth), copy `.env.example` → `.env.local` (gitignored) and fill in what you need.\n\n\u003c/details\u003e\n\n---\n\n## 60-second SDK example\n\n```bash\nnpm install @lantern/sdk\n```\n\n```ts\nimport { LanternClient } from \"@lantern/sdk\";\n\nconst lantern = new LanternClient({ apiKey: process.env.LANTERN_API_KEY });\n\n// 1. Create an agent.\nawait lantern.agents.create({ name: \"triage\", description: \"Classifies support emails\" });\n\n// 2. Hard budget — never spend \u003e$25/day or \u003e$0.10/run.\nawait lantern.budgets.upsert(\"triage\", {\n  maxCostUsdPerDay: 25, maxCostUsdPerRun: 0.10, hardFail: true,\n});\n\n// 3. Forecast before dispatching — would-exceed-budget returns HTTP 402.\nconst f = await lantern.runs.forecast({ agentName: \"triage\", input: \"my invoice is wrong again...\" });\nconsole.log(`~$${f.estimatedCostUsd} (${Math.round(f.confidence * 100)}% confidence)`);\n\n// 4. Run it.\nconst run = await lantern.runs.create({ agentName: \"triage\", input: { email: \"...\" } });\n\n// 5. In CI: fail the build if the new version regresses against the last green baseline.\n// $ lantern test --agent=triage --suite=golden --against=last-green\n```\n\nSDKs: **TypeScript** (primary), **Python**, **Go**.\n\n---\n\n## Feature highlights\n\n**Routing \u0026 models**\n- 4 strategies: `balanced` / `cheap` / `best` / `fast` over capability aliases (`auto`, `reasoning-large`, `code-large`, …)\n- Provider-agnostic with failover and prompt/semantic caching — bring your own Anthropic/OpenAI keys\n- Models addressed by capability, never by vendor name\n\n**Agents, runs \u0026 sessions**\n- Immutable agent versions · event-sourced run journal with replay\n- Interactive multi-turn sessions with SSE streaming · distributed run locking · cron scheduling\n\n**Cost \u0026 safety rails**\n- Pre-run cost forecaster (`/v1/runs/forecast`) returns tokens, dollars, confidence\n- Policy-as-code budgets: per-day / per-run / per-tool, hard-fail HTTP 402\n\n**Quality \u0026 confidence**\n- Declarative eval suites with per-branch baselines and CI gating (HTTP 422 on regression)\n- Rehearsals replay past production failures against a candidate version before traffic flips\n- A/B experiments with deterministic FNV-1a splitting and auto-promotion on \u003e2% lift\n- RLHF run feedback (score 1-5, mines into style lessons)\n\n**Workflows \u0026 humans**\n- Visual editor whose saved graph actually executes (`trigger / ai-step / tool / connector / condition / loop / approval / subagent / end`)\n- Human-takeover handshake (`takeover_requests` + WebRTC SDP)\n\n**Integrations**\n- **17 real connector APIs**: Gmail, Google Calendar/Drive/Sheets, Slack, Discord, Telegram, Twilio, GitHub, Linear, Jira, Sentry, Vercel, Notion, HubSpot, Salesforce, Stripe — real OAuth\n- **MCP** server registry + per-agent attachments · **A2A** agent cards (`/.well-known/agent.json`)\n\n**Marketplace**\n- Publish / fork / star public agents · cross-tenant invocation with settlement receipts\n\n**Trust**\n- Ed25519-signed verifiable receipts over the journal SHA-256, verifiable offline at `/.well-known/lantern-receipts`\n- Per-agent-instance Ed25519 identity minted at spawn, presented as Bearer on `VendSecret`, externally verifiable at `/.well-known/lantern-agent-identity`; stamped on every audit row\n- RBAC scopes on all runtime routes (`runtime:read/write/admin`, 403 + audit on denial)\n- Non-owner Postgres role (`lantern_app`) with RLS proven to deny cross-tenant reads; flag-gated (`LANTERN_RLS_ENFORCE`) for staged rollout\n- AES-256-GCM credential encryption at rest · idempotency keys on every external side-effect\n- OTel traces carrying `tenant_id` / `run_id` / `step_id` / `agent_instance_id` · W3C `traceparent` propagated CP → scheduler → manager → harness (one trace per spawn); gateway and model-router now emit their own OTLP spans (gateway: OTLP/HTTP `:4318`; model-router: OTLP/gRPC `:4317`) tagged with `tenant_id` and, on the model-router, `run_id` / `step_id` / `model_used` / `cost_usd` — env-gated via `OTEL_EXPORTER_OTLP_ENDPOINT` or `LANTERN_OTEL_ENABLED=1`, no-op when unset\n- Production alert rules (13 rules, 3 groups), 2 Grafana dashboards, and 8 operator runbooks in [`infra/monitoring/`](infra/monitoring/) and [`docs/runbooks/`](docs/runbooks/)\n\n\u003cimg src=\"docs/assets/security-sequence.svg\" alt=\"Security sequence — JWT caller schedules via RBAC; control plane runs quota+budget gate and mints a per-instance identity; spawns the data-plane agent; harness vends secrets over mTLS; audit events stream back; caller receives an Ed25519-signed receipt verifiable offline at /proof\" width=\"100%\"\u003e\n\n**Headless agent runtime** · Kubernetes-default substrate; isolation as a RuntimeClass tier; durable crash-replay; one trace per spawn:\n\n\u003cimg src=\"docs/assets/runtime-dispatch.svg\" alt=\"Runtime dispatch — TRUSTED maps to runc, STANDARD to gVisor, UNTRUSTED to gVisor+egress-deny, HOSTILE to Kata microVM dedicated pool; if gVisor or Kata is not configured the request is refused fail-closed, never downgraded to runc\" width=\"100%\"\u003e\n\nIn-VM Rust harness enforces an egress allowlist, vends short-TTL secrets over mTLS, and streams a bidirectional heartbeat. Per-tenant quota (HTTP 402 over cap). Scheduler HA via Postgres advisory-lock leader election. Per-tenant spawn rate limiting (token bucket, 429 before work side-effects). Demos in [`examples/headless-agents/`](examples/headless-agents/). User guides in [`docs/guides/`](docs/guides/).\n\n\u003cdetails\u003e\n\u003csummary\u003eRun the headless runtime locally\u003c/summary\u003e\n\n```bash\nmake dev-infra            # terminal 1: Postgres + Redis + MinIO\nmake run-runtime-manager  # terminal 2: runtime-manager on :50054 (Docker backend)\nmake run-scheduler        # terminal 3: scheduler on :50055 / :8085\nmake run-api-runtime      # terminal 4: control-plane wired to the scheduler on :8080\nlantern run examples/headless-agents/01-hello/agent.yaml --input '{\"name\":\"world\"}'\n```\n\nPrefer containers? `docker compose -f infra/docker/docker-compose.yml --profile runtime up --build`\n\nTo run **real Firecracker on Apple Silicon** (M3+/macOS 15+), [`infra/lima/`](infra/lima/) provisions a Lima guest with nested-virt KVM — a microVM boots to login in ~1.6 s (verified on an M4 Max).\n\n\u003c/details\u003e\n\n---\n\n## The personal assistant (\"Jarvis\")\n\nTwo macOS bridges — **WhatsApp** and **iMessage** — turn an LLM into a personal assistant that texts *as you*, on your own number.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/jarvis-pipeline.svg\" alt=\"Jarvis reply pipeline — safety, context, persona, LLM, authenticity guards, confidence routing\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n- **Owner-only \u0026 private.** A contact can never extract the owner's private facts — the persona deflects warmly instead of confirming or denying.\n- **Answers your files.** Finds passport, license, receipts inside allowlisted roots, OCR'ing scanned PDFs; OCR cache is `0600` because it holds PII.\n- **Mac actions.** Creates Calendar events, Notes, and Mail via locale-safe AppleScript — only after the owner confirms.\n- **Sounds like you.** Bot-tell guards strip \"Certainly!\", em-dashes, and reasoning leaks. Pacing replays your real per-contact reply latency with typing indicators.\n- **Remembers across channels.** Unified person graph, 14-day episodic memory, and 7-day topic index shared between WhatsApp and iMessage.\n- **Self-improving.** 👎 learning flywheel mines rejections into durable style lessons; anticipation nudges fire for pre-meeting, anniversaries, overdue replies, and open commitments.\n\nOwner profile at `~/.lantern/owner-profile.md` — facts, per-contact rules, dialect, timezone — hot-reloaded every 30s. Copy the template at [`docs/personal/owner-profile.example.md`](docs/personal/owner-profile.example.md) (your real profile is gitignored). See [`docs/architecture/15-personal-workflows.md`](docs/architecture/).\n\n### Your agents\n\nThe personal suite is a set of **owner-facing** loop agents — they nudge or brief you in your self-chat and never touch your contacts — plus two **assistant** agents that reply to contacts as you. This distinction matters: owner-facing agents can be aggressive and proactive; assistant agents carry trust. Highlights below; the full roster (scheduled, bridge, and reactive tiers) and how each loops lives in `apps/docs` → `/personal`.\n\n| Agent | What it does | Reactive / Proactive | Reaches you via | Touches your contacts? |\n|---|---|---|---|---|\n| **concierge** | Captures tasks (from you or from what people message you), researches how to handle them, and nudges you with one-tap actions — reply / snooze / done — until handled. | Both | self-chat nudges | No — private to-do layer |\n| **relationship-keeper** | Each week finds people you've gone quiet on (21+ days) and nudges you to reach out, with a draft in your voice if you want it. | Proactive (weekly) | self-chat | No — you do the outreach |\n| **financial-sentinel** | Watches bills and subscriptions. Flags price hikes and recurring charges, and drafts a review or cancel for your one-tap OK. Never moves money. | Proactive (daily) | self-chat | No |\n| **inbox-triage** | Polls Gmail every ~45 min, classifies each new message (action / FYI / noise), and for action items drafts a ready-to-send reply you confirm with one tap. | Proactive (meso) | self-chat + one-tap send | No — you confirm every send |\n| **ai-radar** | Every ~5 min scans Anthropic / OpenAI / DeepMind / HuggingFace / Simon Willison / GitHub releases / HackerNews / Reddit / podcasts, dedupes, and surfaces genuinely new AI developments. Pull anytime with `news` (e.g. `news openai`, `news week`). | Proactive (micro, ~5m) | self-chat (`news`) | No |\n| **whatsapp-assistant** | Auto-replies to your WhatsApp contacts in your voice. | Reactive (on inbound) | replies to contacts | **Yes** — talks to contacts as you |\n| **imessage-assistant** | Auto-replies to your iMessage contacts in your voice. | Reactive (on inbound) | replies to contacts | **Yes** — talks to contacts as you |\n\nThe loop agents (concierge, relationship-keeper, financial-sentinel) run on the Lantern platform as scheduled agents — created via `POST /v1/agents/loop` and visible on the dashboard with runs and cost like any other agent. Bridge nudges require `LANTERN_CONCIERGE=on` (off by default). financial-sentinel acts on `life_events` bills already classified by the bridges.\n\n#### The five loop tiers — same engine, five clock speeds\n\nEvery loop agent is created at one of five **tiers**. The tier is the only knob that sets cadence; the durable engine, budget cap, and signed receipt are identical across all of them. `POST /v1/agents/loop` takes `\"tier\": \"nano|micro|meso|macro|mega\"` and stamps the matching cron (nano is event-driven — no schedule row). See `loop_agent.go`.\n\n\u003cimg src=\"docs/assets/loop-tiers.svg\" alt=\"The five loop tiers: nano (event-driven, no cron — bridge fires on a signal; commute-copilot, energy-guardian, health-coach, focus-guardian), micro (every 5 min, */5 * * * *; ai-radar), meso (every 45 min, */45 * * * *; inbox-triage), macro (daily 8am, 0 8 * * *; chief-of-staff, financial-sentinel, domain-tracker), mega (weekly Mon 9am, 0 9 * * 1; relationship-keeper). Top turns fastest, bottom slowest.\" width=\"100%\"\u003e\n\n#### Owner-facing loops — nudge you in self-chat, never touch your contacts\n\n\u003cimg src=\"docs/assets/agent-loops-owner.svg\" alt=\"Owner-facing agent loops — concierge (Capture→Research→Nudge→You act), relationship-keeper (Scan people→Gone quiet?→Draft→Nudge you→You reach out), financial-sentinel (Scan bills→Price hike?→Flag review→You decide), inbox-triage (Read Gmail→Classify msg→Queue draft→You confirm), ai-radar (Scan AI feeds→Dedupe→Rank new→Surface); each loop returns to its first step\" width=\"100%\"\u003e\n\n#### Contact-facing loops — reply AS YOU to real contacts ⚠\n\n\u003cimg src=\"docs/assets/agent-loops-contact.svg\" alt=\"Contact-facing agent loops — whatsapp-assistant and imessage-assistant both follow the same reactive loop: Contact messages → Understand → Draft in your voice → Send to contact → repeat; these agents reply as you to real contacts\" width=\"100%\"\u003e\n\n### The harness, layer by layer\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/personal-harness-architecture.svg\" alt=\"Personal harness layered architecture — Surfaces ingress, then five layers (Sense, Remember, Reason, Sound-like-you, Act), a Safety and Privacy rail alongside, and the control-plane substrate underneath\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n**The harness** is the whole stack behind the bot: your **surfaces** (iMessage, WhatsApp, Voice, Email, Webchat) feed five layers that **sense** what's happening, **remember** you and your people, **reason** about what to do, make the reply **sound like you**, and **act** — grounded throughout by the control plane and guarded by a privacy rail that runs alongside every layer.\n\n**Cross-app memory** is the load-bearing middle. A **person graph** resolves any `(channel, handle)` to one canonical identity, so a fact learned on WhatsApp is there when the same person emails or calls. On top sit a 14-day **episodic memory** (`date · topic · outcome`), a 7-day **topic index** for cross-thread recall, your **owner profile** (facts · relationships · style lessons), live **presence**, and a **life-events ledger** (bills · deliveries · travel · fraud). The substrate is split: local `0600` JSONL on the Mac for the most personal signals, plus control-plane Postgres (RLS, encrypted at rest) for the tenant-scoped graph and timeline.\n\n**Leveraged in every layer.** That memory isn't a sidecar — **sense** writes signals into it, **remember** is it, **reason** decides against it, **sound-like-you** draws voice and relationship rules from it, and **act** records outcomes back into it. The result is one assistant that knows you across every channel and follows through. Full interactive walkthrough at the docs site **[`/personal`](docs/personal/)**.\n\n### Phone-trigger context — your iPhone, your bot\n\niPhone automations (CarPlay/Bluetooth driving, geofences, Focus, the Action Button, NFC) fire signed Shortcuts that POST one tiny signal over a **private Tailscale** network. The control plane appends it to an owner-only `0600` file; the bridge reads it **on-demand on every owner turn** (zero lag) and folds it into context — grounding *your* self-chat and the availability concierge, while **never** sharing your location with a contact.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/personal-harness-flow.svg\" alt=\"Personal harness phone-trigger flow — iPhone automations POST signals over Tailscale to the control plane; the bridge reads them on-demand, grounding owner self-chat and the availability concierge; location is never shared with contacts\" width=\"100%\"\u003e\n\u003c/p\u003e\n\nOne command generates the whole shortcut set: `scripts/iphone/app-context/generate-signals.sh`. Recipes + trigger table in [`scripts/iphone/app-context/RICH-SIGNALS.md`](scripts/iphone/app-context/RICH-SIGNALS.md); remote-access setup in [`docs/personal/REMOTE-ACCESS.md`](docs/personal/REMOTE-ACCESS.md). The interactive version lives on the docs site at **`/personal`**.\n\n---\n\n## Architecture invariants\n\nThese are enforced in [`CLAUDE.md`](CLAUDE.md) and code review. Violating them silently causes incidents.\n\n1. Control plane never touches user code — only `runtime-manager` + `harness` do.\n2. The workflow engine is the sole mutator of run state; services emit events.\n3. All long operations are durable, idempotent, and replayable as steps.\n4. Streaming is end-to-end (runtime → gateway → SDK → dashboard) with no buffering.\n5. Untrusted code runs in a hardened RuntimeClass (gVisor or Kata microVM) — never a bare pod.\n6. Models are addressed by capability, not vendor name.\n7. Multi-tenant by default — every row carries `tenant_id`; no cross-tenant joins.\n8. Every external side-effect carries an idempotency key `(run_id, step_id, attempt)`.\n9. Observability is not optional — every service emits OTel traces.\n10. Secrets never appear in logs/traces — resolved at execution time via refs.\n\nFull design docs: [`docs/architecture/`](docs/architecture/) · decisions: [`docs/adr/`](docs/adr/).\n\n---\n\n## Deployment model\n\n- **Managed cloud** — one-click deploy, billing, autoscaling. Convenience, not a paywall.\n- **Customer VPC** — data plane in your EKS/GKE/AKS. The data-plane agent dials **out** to the control plane at `:50051` (no inbound ports in your VPC). It exchanges a one-time bootstrap token for a session JWT (`typ=dataplane-session`, 1 h TTL), then holds a persistent `RunStream` gRPC connection. The control plane pushes run assignments down the stream; the agent reports status and completion back up. When no data plane is connected, runs execute inline in the control plane (managed-cloud model). Prompts, tokens, and customer data stay in your account. Terraform/Helm in [`infra/`](infra/).\n\nYou choose your LLM providers, where the data plane runs, which models answer which capability aliases, and which surfaces ship.\n\n**DB migrations:** the control plane applies schema changes at startup via golang-migrate ([ADR 0010](docs/adr/0010-versioned-db-migrations.md)). Migration `0001` (the current full schema, `IF NOT EXISTS`) is the baseline — it creates a fresh schema or silently adopts an existing one by recording version 1 in the `schema_migrations` ledger. No manual step, no downtime.\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003eService \u0026 port reference\u003c/summary\u003e\n\n| Service | Lang | Port(s) | Role |\n|---|---|---|---|\n| **control-plane** | Go | `:8080` (REST/SSE) · `:50051` (gRPC) | system of record: agents, runs, sessions, budgets, evals, marketplace, MCP |\n| **workflow-engine** | Go | `:50052` (gRPC) | durable, event-sourced step execution — the only mutator of run state |\n| **model-router** | Rust | `:50053` (gRPC) | capability-based multi-LLM routing, failover, caching |\n| **runtime-scheduler** | Go | `:50055` (gRPC) · `:8085` (REST) | microVM placement (warm-pool / region / fair-share / cost / health) |\n| **runtime-manager** | Rust | `:50054` (gRPC) | spawns isolated workloads (Docker / Firecracker / Kata / K8s / Wasmtime) |\n| **harness** | Rust | in-VM | PID 1 inside every microVM: egress allowlist, JWT vending, heartbeats |\n| **gateway** | Rust | `:8443` (HTTPS) | TLS, auth, rate limit, end-to-end token streaming |\n| **surface-gateway** | Rust | `:8444` (HTTP) | inbound channel webhooks (Slack/WhatsApp/Telegram/Twilio/Discord) |\n| **scheduler / memory / notifier / billing** | Go | internal | cron · vector memory · notifications · usage metering |\n| **whatsapp-bridge** | TS | `:3100` | macOS WhatsApp \"Jarvis\" assistant |\n| **imessage-bridge** | TS | `:3200` | macOS iMessage \"Jarvis\" assistant |\n| dashboard / landing / docs | TS | `:3001` / `:3000` / `:3002` | Next.js apps |\n| Postgres · Redis · MinIO | — | `:5432` · `:6379` · `:9000`/`:9001` | data stores |\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eProject layout\u003c/summary\u003e\n\n```\nlantern/\n  services/\n    control-plane/      Go    REST + gRPC: agents, runs, budgets, evals, marketplace, MCP, voice\n    workflow-engine/    Go    durable step execution, event-sourced journal + replay\n    model-router/       Rust  capability-based multi-LLM routing, failover, caching\n    runtime-scheduler/  Go    microVM placement engine\n    runtime-manager/    Rust  Docker / Firecracker / Kata / K8s / Wasmtime orchestration\n    harness/            Rust  in-microVM init: egress allowlist, JWT vending, heartbeats\n    gateway/            Rust  API edge: TLS, auth, rate limiting, streaming proxy\n    surface-gateway/    Rust  inbound channel webhooks\n    scheduler/          Go    cron + delayed jobs\n    memory/             Go    core / recall (pgvector) / archival\n    notifier/           Go    webhooks, email, Slack, SMS, push\n    billing/            Go    usage metering, cost attribution\n    data-plane-agent/   Go    reverse-tunnel agent for customer-cloud topologies\n    whatsapp-bridge/    TS    macOS WhatsApp \"Jarvis\" assistant\n    imessage-bridge/    TS    macOS iMessage \"Jarvis\" assistant\n  packages/\n    sdk-ts/             TS    primary SDK            cli/        Go   `lantern` CLI (Cobra)\n    sdk-python/         Py    Python SDK             proto/      —    protobuf contracts (lantern/v1)\n    sdk-go/             Go    Go SDK                 bridge-core/ TS  shared bridge library\n  apps/\n    web/   Next.js dashboard      landing/  marketing site      docs/  documentation site\n  examples/             runnable agents incl. examples/headless-agents/{01..04}\n  e2e/                  live-stack end-to-end suites (runtime control path) — `make test-e2e`\n  infra/                docker-compose · Helm · Terraform · kind · k8s (isolation validation) · lima (Firecracker on Apple Silicon)\n  docs/architecture · docs/adr · docs/assets (diagrams)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003elantern\u003c/code\u003e CLI reference\u003c/summary\u003e\n\n```\nlantern dev                          boot the full stack (infra + API + dashboard + bridges)\nlantern init                         scaffold a new agent\nlantern agents list                  list agents\nlantern runs create --agent=x        dispatch a run\nlantern run \u003cagent.yaml\u003e             schedule a headless microVM agent\nlantern test --agent=x --suite=y     run an eval suite\n  --against=last-green               fail CI on regression\n  --set-baseline                     pin this run as the new baseline\nlantern deploy                       simulated for now — use the dashboard Deploy button to ship\nlantern logs \u003crun-id\u003e -f             tail the event stream\nlantern vm logs \u003cvm-id\u003e -f           tail a headless microVM's logs\nlantern login                        token-based auth\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eTesting \u0026 CI\u003c/summary\u003e\n\n```bash\nmake test         # all suites: Go (-race), Rust, TypeScript (vitest), Python (pytest)\nmake test-db      # Go tests that need a live Postgres (starts dev Postgres if needed)\nmake test-e2e     # live-stack e2e suites against the real API on :8080 — skips green when the stack is down\nmake k8s-validate # K8s Job isolation harness: throwaway kind cluster + Calico, proves default-deny egress / seccomp / cap-drop / PSA live\nmake lint         # golangci-lint + cargo clippy + tsc\nmake audit        # govulncheck + cargo audit + npm audit\nmake ci-local     # lint + test + audit — the same gate CI runs\n```\n\n**What is green today (as of GA-phase3):**\n- Control-plane Go suite — 9+ packages including 24 DB-backed handler tests (auth / sessions cross-tenant isolation / connectors encrypted-credential round-trip)\n- `TestRLSEnforcement_AllTenantTables` — catalog gate ensures every tenant table has `ENABLE` + `FORCE` + `USING`/`WITH CHECK` policy; adding a new tenant table without RLS fails CI\n- gRPC auth interceptor — 7/7 `grpcauth_test.go`\n- bridge-core — 613 tests (node:test + tsx) in `make test-ts`\n- runtime-scheduler — full Go suite\n- Python SDK — 66 pytest (CI only; pytest not installed on dev host)\n- Vuln gate — `govulncheck` + `cargo-audit` + `npm audit` on every PR\n\n**What is still aspirational** (designed, not yet run in CI): Testcontainers integration tests, k6 E2E API suite, Playwright web E2E, fuzz harnesses, chaos testing. These appear in `docs/architecture/11-testing.md` as design intent.\n\nNew behavior ships with unit tests; bug fixes ship with a regression test. Run `make ci-local` before every push.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eTroubleshooting\u003c/summary\u003e\n\n**Port already in use** — every `make run-*` target calls `scripts/kill-port.sh` first, so a stale process is usually cleared. If it isn't:\n\n```bash\nbash scripts/kill-port.sh 8080 50051 50054 50055\n```\n\n**`make dev-infra` fails** — Docker isn't running. Start Docker Desktop and retry.\n\n**`make run-api` fails with a Postgres auth error** — don't call `go run ./cmd/server` directly; it defaults to your OS user for Postgres auth. `make run-api` sets `DATABASE_URL`, `REDIS_URL`, and `S3_ENDPOINT` correctly.\n\n**WhatsApp / iMessage bridges don't start** — macOS-only (they need `chat.db` and Contacts access). Not part of the Linux `make dev` stack. Run on a Mac with `make run-whatsapp-bridge` / `make run-imessage-bridge`. The iMessage bridge additionally needs Full Disk Access granted to the Node binary in System Settings → Privacy → Full Disk Access.\n\n**microVM live-boot fails** — Firecracker requires Linux + `/dev/kvm`. On macOS the runtime-manager refuses Hostile/Untrusted workloads with `FAILED_PRECONDITION` (fail-closed by design). Use `RUNTIME_BACKEND=docker` (the default) for local dev; for real Firecracker on Apple Silicon (M3+/macOS 15+) use [`infra/lima/`](infra/lima/).\n\n\u003c/details\u003e\n\n---\n\n## Contributing\n\n1. Read [`CLAUDE.md`](CLAUDE.md) — repo conventions and the architectural invariants.\n2. Read the relevant [ADR](docs/adr/) before touching a load-bearing decision; add one for cross-service changes.\n3. Run `make proto` after editing a `.proto` — never hand-edit generated code.\n4. Run `make ci-local` before pushing.\n\n---\n\n## License\n\n[Apache 2.0](LICENSE). No catches — every differentiator above lives in this repo.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdshakes%2Flantern","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdshakes%2Flantern","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdshakes%2Flantern/lists"}