The triage layer that Linear's free plan lacks. It ingests the error backlog from Linear, enriches each context-poor item from Sentry/PostHog, helps a tech lead reach actionable verdicts, keeps its own stateful record of those decisions, and writes them back to Linear only on confirmation.
One long-running Deno 2 process is the whole backend (embedded Claude agent +
Overlay store + scheduler + API/SSE), serving a Vite + React SPA
(TanStack Router/Query + TanStack AI). Overlay on node:sqlite. No external
DB/broker/hosted backend. Zero --unstable-* flags; scoped permissions only.
See CONTEXT.md (domain glossary), prds/0001-*.md (the PRD), and docs/adr/
(decisions). Vertical slices S00–S12 live in issues/.
deno task build # build the web SPA into web/dist
deno task start # boot the process (serves SPA + /health + /api on localhost:8787)
deno task dev # dev loop (--watch)
deno task check # type-check
deno task test # unit testsBoots with zero credentials using fixture adapters + a deterministic stub agent, so the whole pipeline is demonstrable offline. Set env vars to switch to live integrations:
| Env var | Effect |
|---|---|
ANTHROPIC_API_KEY |
use real Claude for enrichment / drafting / chat (else stub) |
LINEAR_MCP_URL |
use the real Linear MCP adapter (ingest + write-back) instead of fixtures |
SENTRY_MCP_URL |
use the real Sentry MCP adapter for enrichment |
POSTHOG_MCP_URL |
use the real PostHog MCP adapter (best-effort impact) |
PORT / HOST / DB_PATH |
server bind + sqlite path (defaults: 8787 / 127.0.0.1 / ./data/overlay.db) |
PASS_STALE_HOURS |
catch-up Pass staleness threshold (default 12) |
CAPTURED_TASK_AGING_HOURS |
when a Captured Task is flagged "going stale" (default 72) |
Boundary modules follow a port / adapter pattern: a clean port interface, a real MCP adapter (configured by env, fails gracefully when absent), and a fixture adapter (default) so dev + tests never touch live services.
- Linear Ingest (
src/linear) — pull error issues, parse the Sentry deep-link join key. - Signal Resolver (
src/signal) — group Linear Issues into Signals (Triage Items). Strong match (same Sentry id) auto-merges; weak match is a HITL suggestion only (durable via aliasing). Err toward not-merging (ADR 0002). - Enrichment (
src/enrichment+src/agent) — follow the Sentry link, pull metrics/stacktrace, Claude reasons out a root cause (no Seer). - Verdict Engine (
src/verdict) — pure proposed verdict from enrichment + history; proposed→confirmed is the only path to a side effect. - Write-back (
src/writeback) — only a confirmedactionableverdict posts the enrichment summary as a Linear comment + sets status (+ assignee = Owner). Idempotent. - Pass + scheduler (
src/pass) —runPass()sequences ingest→resolve→enrich→propose→change-detection; catch-up-on-launch via a sqlite watermark (noDeno.cron). - Regression (
src/verdict+src/overlay/changes.ts) — a dispatched Signal recurring after going quiet auto-reopens toproposed; nothing written until re-confirmed. - Digest (
src/digest) — three ranked blocks: needs-decision, changed-since-last-Pass, going-stale (impact × recency × SLA). - Captured Tasks (
src/captured-task) — manual request stream; Claude drafts the Linear Issue; no Signal/Verdict, staleness only. - Chat deep-dive (
src/chat+web/src/chat) — TanStack AI chat reusing the same embedded agent; MCP host-side, creds never reach the browser.
Slices S00–S12 implemented and tested (137 unit tests). The weak-match heuristic
(S09) ships as a conservative documented default pending human review —
see docs/weak-match-heuristic.md.
MIT © Walter Andrade — see LICENSE.