{"slug": "marvin-open-source-macos-ai-coding-ide-that-learns-from-its-own-sessions", "title": "Marvin – Open-source macOS AI coding IDE that learns from its own sessions", "summary": "Robert Ilisei released MARVIN, an open-source macOS AI coding IDE that uses a single assistant with enforced phases and a knowledge graph to reduce first-message context from 566K to ~13.4K tokens, cutting token costs to about 1/27th. The app, currently at v0.1.104, runs locally with a bundled sidecar and requires Anthropic credentials, available via Homebrew as 'marvin-ai'.", "body_md": "**M** oderately **A** dvanced **R** obotic **V** irtual **I** ntelligence **N** etwork.\n\nA pair-programming AI assistant. You drive vision and business decisions. MARVIN drives architecture, infrastructure, code, tests, docs, and security.\n\nYou say *\"let's build the login page\"* — MARVIN dives in: reads the codebase,\nproposes the schema + wiring + tests, executes with explicit confirms, commits.\n\n\"Here I am, brain the size of a planet, and they ask me to build a login page.\" — MARVIN, probably\n\nA real session on MARVIN's own repo, unedited: two graph queries before the first file read, an answer with file and line citations, 19 seconds.\n\n[One assistant, enforced discipline — a design for AI pair-programming that survives real projects]Why AI coding assistance decays on real projects, and the four bets MARVIN makes against the current grain:\n\nOne assistant with enforced phases— not an agent team; subagents are structurally unable to writeThe knowledge graph before the file read— structural answers at ~1/27th the token cost (measured on this repo), with`file:line`\n\ncitationsDeterministic contracts at the tool gate— enforced, not politely requested in the promptLocal-first, no backend— inference straight to Anthropic; credentials never leave your machineWith measured results (first-message context: 566K → ~13.4K tokens), five architecture diagrams, and anonymized transcripts from real production sessions. The exhaustive companion — every subsystem down to the code — is the\n\n[Technical Reference]. Both are also available as PDFs:[white paper]·[technical reference].\n\nMARVIN has two components that work together:\n\n| Component | Location | Role |\n|---|---|---|\nmacOS app |\n`macos/` |\nNative SwiftUI app — IDE shell, chat, file tree, source control, terminal, diff viewer |\nSidecar |\n`sidecar/` |\nNext.js 16 server on `:3030` — Claude Agent SDK runner, tool policy, git API, file API, session storage |\n\nThe Swift app talks to the sidecar over `localhost:3030`\n\n. In a brew install the sidecar is bundled inside `MARVIN.app/Contents/Resources/`\n\n(alongside a pinned Node 22 runtime) and spawned by the SwiftUI process on launch; quitting MARVIN cleans it up. See [ADR-0023](/RobertIlisei/MARVIN/blob/main/docs/decisions/0023-brew-distributable-bundled-sidecar.md).\n\nReleases.Homebrew installs the latest tagged release (currentlyv0.1.104).`main`\n\nand`development`\n\nare fast-forwarded together at each release;`development`\n\nis where in-progress changes land between them. To build from source on either branch,`git checkout <branch>`\n\nthen`bin/marvin install-macos-app`\n\n.\n\n```\nbrew tap RobertIlisei/marvin\nbrew install --cask marvin-ai\n```\n\nThat's it. MARVIN.app appears in `~/Applications`\n\n, the bundled sidecar starts with the app, quitting MARVIN cleans it up. No Swift, Node, pnpm, Xcode, or Apple Developer account required on your machine.\n\nFirst launch — one-time Gatekeeper step (macOS 26+).MARVIN is ad-hoc signed (no paid Apple Developer Programme membership). On first double-click macOS shows \"Apple could not verify…\": clickDone, then openSystem Settings → Privacy & Security, scroll to theSecuritysection, find \"MARVIN.app was blocked from use…\", and clickOpen Anyway. This whitelist persists for the life of the install — you only do it once. ([ADR-0027]has the technical detail.)\n\n**You'll need Anthropic credentials** to use it — either run `claude login`\n\n(the Claude CLI handles it) or paste an API key in MARVIN → Settings → Authentication.\n\n**Updates:** `brew upgrade --cask marvin-ai`\n\n. **Uninstall:** `brew uninstall --cask marvin-ai`\n\n(add `--zap`\n\nto also wipe `~/.marvin`\n\n).\n\nNote: the cask token is\n\n`marvin-ai`\n\n, not`marvin`\n\n— the plain token is taken by the unrelated \"Amazing Marvin\" productivity app in the official homebrew-cask repo.\n\nIf you've cloned the repo and want to build locally:\n\n```\nbin/marvin install-macos-app   # build → ~/Applications/MARVIN.app\nbin/marvin uninstall-macos-app # remove app (both ~/Applications and legacy /Applications)\n```\n\nDefault install mode is **bundled** (per ADR-0023) — same shape as the brew artefact. Pass `--launchd`\n\nfor the legacy mode that runs the sidecar from the source repo via a user-agent plist.\n\nRequires `xcodegen`\n\n+ Xcode, **or** just the Swift Command Line Tools (`xcode-select --install`\n\n). If `xcodegen`\n\nis missing, `swift build`\n\nis used automatically as a fallback — no Developer account needed in either path.\n\n`main`\n\nand `development`\n\ntrack together at each release; `development`\n\ncarries any work in progress between releases ([ADR-0028](/RobertIlisei/MARVIN/blob/main/docs/decisions/0028-multi-graph-architecture.md) multi-graph landed this way). Build either from source:\n\n```\ngit clone https://github.com/RobertIlisei/MARVIN.git ~/marvin\ncd ~/marvin\ngit checkout development   # or: main\nbin/marvin install-macos-app\n```\n\n**Back to the signed release artefact** at any time:\n\n```\nbrew install --cask marvin-ai\n```\n\n`graphify-out/knowledge/`\n\nis gitignored and harmless to leave behind when switching branches.\n\n| Requirement | How to get it |\n|---|---|\n| macOS 14+ | System update |\nXcode ≥ 15 or Swift CLT |\n`xcode-select --install` |\nxcodegen (optional, preferred) |\n`brew install xcodegen` |\n\n| Requirement | How to get it |\n|---|---|\nNode.js ≥ 22 |\n`brew install node@22` |\n\n`npm install -g pnpm`\n\n`npm install -g @anthropic-ai/claude-code`\n\n`claude auth login`\n\n— or set `ANTHROPIC_API_KEY`\n\nin env**Optional:**\n\n`npx playwright install chromium`\n\n— needed for browser automation (MARVIN shells out to`npx playwright`\n\nwhen a turn needs a browser)`pip install graphifyy`\n\n— needed for the knowledge graph (`/graphify`\n\n, graph-aware chat)\n\nAfter `claude auth login`\n\n, also visit [claude.ai](https://claude.ai) once with the same email to accept the latest Consumer Terms — the CLI returns 400 until you do.\n\n```\npnpm install                    # once — installs deps across all packages\nbash scripts/setup.sh           # once — prompts for optional deps (Playwright, graphify)\nbash scripts/install-skills.sh  # once — installs skills to ~/.claude/skills/ (clones upstream on demand)\n\nbin/marvin start                # production mode (builds if stale, then starts)\nbin/marvin stop\nbin/marvin restart\nbin/marvin status               # auth + model + data dir\nbin/marvin logs                 # tail .marvin/dev.log\nbin/marvin doctor               # preflight checks only, no start\nbin/marvin help\n```\n\nFor raw Next.js (no pid tracking, skips preflight):\n\n```\npnpm build && pnpm start\ncd macos\nxcodegen generate               # regenerate MARVIN.xcodeproj from project.yml\nopen MARVIN.xcodeproj           # then build + run in Xcode\n```\n\nOr with swift build (Command Line Tools only, no Xcode IDE):\n\n```\ncd macos\nswift build -c release\n# The install script assembles the .app bundle from the SPM output automatically.\nbin/marvin install-macos-app    # build + install + launchd\n# Terminal 1 — sidecar in the foreground\nbin/marvin start\n\n# Terminal 2 — open the built app\nopen ~/Applications/MARVIN.app\n# or for a faster edit-rebuild-run loop while working on the Swift side:\ncd macos && xcodebuild -scheme MARVIN -configuration Debug build && open build/...\n```\n\n**Single assistant, not an agent team.** Published research on sequential coding tasks shows multi-agent autonomy degrades quality up to ~70 % and amplifies error rates 17× in flat-topology setups. MARVIN is one assistant moving through an 8-phase workflow in one conversation, with the user as continuous overwatch.**Plan-first, execute-second, verify-third.** Sketch the approach, ship, then verify. In-flight + shipped work tracked in.`docs/roadmap.md`\n\n**Per-project isolation.** MARVIN holds zero cross-session knowledge about other projects. Memory, ADRs, and knowledge graph live inside each user project, not in MARVIN's own data dir — and the running IDE only ever reads or builds the*active project's*graph, never its own source.**Built on a knowledge graph it maintains for you.** Queries[graphify](https://github.com/safishamsi/graphify)first on architecture/impact questions (**27.5× cheaper** than reading raw files — measured with`graphify benchmark`\n\n, 2026-08-15), and builds/refreshes the active project's code + knowledge graphs itself (AST-only, free) so they're always current (ADR-0041).**Memory is durable facts, not a log.**`.marvin/memory.md`\n\nis a curated, one-line-per-fact index written only through the`remember`\n\ntool — invariants and gotchas the next session can't re-derive from ADRs, git, or the changelog (ADR-0042).**It learns from its own sessions — and proposes, never rewrites.** Once a night a read-only pass over a project's transcripts finds the failures that repeat across sessions (and the same act done right, so each carries a rate), proposes a rule at three sessions, and — if you approve — enforces it at the tool gate and measures whether it held. No model reads a transcript; nothing changes without your click (ADR-0105). The measurement behind it is also why code review and security audit are now enforced at`git commit`\n\ninstead of requested in the prompt (ADR-0104).\n\n**macOS app**\n\n- 🍎 Native SwiftUI IDE shell — 3-pane layout (file tree · chat · brain/graph)\n- 📁 File tree with icons, click-to-open, context menu (create / rename / delete / move)\n- 🗒️ Syntax-highlighted file viewer (Swift, TS, JS, Go, Rust, JSON, YAML, Markdown, images)\n- 🔎 Find in file — ⌘F / ⌘G / ⇧⌘G / ⌘E in the editor, plus a header button\n- 🌿 Source control — stage/unstage, commit, push, pull, fetch, diff viewer, branch line\n- 🔍 Project-wide search — ripgrep-backed, include glob filter, replace all\n- 🔣 Symbol search and file history\n- 🏗️ Build task panel — run build tasks, see diagnostics inline\n- 🧩 Problems panel — diagnostics from a bounded, ignore-aware sweep of the whole tree (tsc · eslint flat + legacy · biome · ruff · go vet · cargo · swift build · maven), project-local wrappers preferred, fast checks automatic and minute-scale builds on demand. Grouped by file, severity chips that filter, rows jump to\n`file:line:col`\n\n, and three distinct empty states — never-run, no-toolchain-found, genuinely-clean - 🔌 Language server client — diagnostics from the\n**buffer**, not from disk, so the list describes the file as it is now rather than as it was last saved (ADR-0099). Full-text sync, a three-strike crash budget, and a missing server surfaced*as a diagnostic*rather than as silence - ⌨️ Command registry — the menu bar, the\n**⇧⌘P command palette** and the ⌘/ shortcut sheet are three renderings of one array, so a binding cannot drift between them. Save All · Revert · New Text File · Auto Save · Word Wrap · Toggle Line/Block Comment · Move/Copy/Duplicate Line · Expand/Shrink Selection · Go to Bracket · Go to Line · Next/Previous Problem · Next/Previous Change · Back/Forward · Run Active File - 🧭 Outline · Timeline · Tasks — the sidebar sections VS Code has, built language-agnostically: the outline reads the\n**knowledge graph** rather than tree-sitter (which covers 12 languages and would silently do nothing in the rest), and Tasks is a generic runner rather than the reference's Java-only Maven panel - 🛑 Stop Session & All Work (⇧⌘.) — Stop cancels the turn; this cancels the turn\n**plus** the background jobs and scheduled wakeups it leaves behind, which otherwise outlive it and can start a new turn on their own. Confirmation names the scope by count, and the whole thing is scoped to one session - ⌨️ Embedded terminal (PTY-backed)\n- 🕐 Session history — click any past session in the header to restore it\n- 🧠 MARVIN brain — live animated state indicator (idle / thinking / tool / writing / error)\n- 📎 Image paste in chat (⌘V, screenshots, dragged images)\n- 🌓 Light / dark theme — respects system preference\n- ✅ Agent change review — VS Code / Cursor-style: a live \"N files changed\" strip while MARVIN edits opens its own resizable window with a side-by-side (original │ modified) diff, line numbers, and a Split/Inline toggle. Per-hunk / per-file accept-reject against pre-agent baselines (rejecting restores\n*your*uncommitted state, not git HEAD); committing a change clears it from the review the way it leaves VS Code's Source Control list (ADR-0034) - 🎚️ Per-role reasoning effort — independent Low→Max effort pickers for the executor and the advisor (ADR-0033)\n- 🧭 Ask · Agent · Plan modes — read-only Ask (enforced at the gate), full-autonomy Agent, and plan-first Plan that drafts a plan + live to-do checklist and waits for your approval before executing (ADR-0036). Cursor-style controls live in the input box; chat tabs open/close and persist per project\n- 🗂️ Two-tier to-do / plan — a neutral\n**Task list** for bare`TodoWrite`\n\nruns vs a purple**Plan — <title>** that persists, ticks off in place, and saves to`.marvin/plans/<slug>.md`\n\nopened in the editor (\"Open plan\"); a completed plan collapses instead of re-prompting to approve (ADR-0036 two-tier addendum). The executor tags each`TodoWrite`\n\nitem`[N]`\n\n(plan step) /`[N.M]`\n\n(sub-task) so tasks link to the right step by a stable key, sub-tasks roll up to complete their parent (a step is done only when all of its are), and the**active plan + live status is re-injected into the model's context every turn**— so MARVIN never loses the plan across a chat switch or context compaction (ADR-0049 · ADR-0050 · ADR-0051) - ❓ Clickable decisions — when the model hits a real fork it calls\n**AskUserQuestion** and you pick from native option buttons (single/multi-select + \"Other\"); your choice returns to the model as the tool result, in every mode (ADR-0040) - 🧩 Per-project skill enablement — the fingerprint picks the installed skills relevant to\n*this*project and tells MARVIN to ignore the rest; per-skill toggles in the Skills pane (ADR-0037) - ⬇️ Fetch skills from Git — \"Add from GitHub\" pulls a skill from any repo, a\n`…/tree/…`\n\nsub-path, or a plugin marketplace (ADR-0039); clone-and-copy only, never executes the repo - 🛰️ Event-based background jobs —\n`run_background_job`\n\nruns a build/test/deploy past the turn and fires a real follow-up turn when it exits (no more orphaned \"I'll be notified\" promises); shell`&`\n\n/`nohup`\n\ndenied at the gate (ADR-0038). The completion turn now renders in an**idle** session without a switch/relaunch — a per-project announce channel re-attaches the app to any server-initiated turn (ADR-0043), with a \"background job running\" chip so in-flight is distinct from done - 📋 Project backlog — a durable parking lot for the \"noticed in flight, not in scope\" follow-ups that used to evaporate with the chat:\n`backlog_add`\n\nparks them (consent-gated at the scope-met handoff), they resurface in next session's context, and a macOS panel + tray chip lets you browse / Done / Dismiss /**Promote to plan**. A parking lot the user revisits — never a queue agents pull from (ADR-0044) - 🧹 Backlog review (\n`/groom`\n\n·**Review** button · View ▸ Backlog ⌘⇧B) — a backlog that only grows stops being read, so MARVIN reviews it: near-duplicates the exact-title dedup can't see, auto-captures nobody ever triaged, items untouched for weeks, references to files that no longer exist, HIGH items left sitting.**Read-only by construction**— it reports, you decide; the report carries that instruction*with the data*, not just in the prompt. Findings render as badges on the rows they concern (ADR-0063) - 🏷️ Backlog classification —\n`kind`\n\n(bug · feature · investigate · test · docs · chore) alongside severity, plus— a blocked bug and a blocked feature are both blocked, and an item waiting on an accountant shouldn't look pickable. Both change what the groomer nags about: a bug ages at a lower bar, while`blocked`\n\n/`blockedOn`\n\nas its own axis`investigate`\n\nand`blocked`\n\nitems are never called stale. No backfill — existing items stay`unspecified`\n\nrather than take a guessed label (ADR-0064) - 🌙 Practice pane — Findings · Working · Rules · Runs: what MARVIN keeps getting wrong (and right) across this project's sessions, scored, with approve / dismiss /\n**fixed in MARVIN** per finding, run-now, backtest and a nightly schedule. The four built-in gates are rows you can re-tier or switch off; score weights fit from real outcomes on a click; a read-only model can draft a rule's wording from aggregates. A project with fewer than three sessions shows a calibration counter and offers rules**proven in your other projects** to adopt (ADR-0105 ·[guide](/RobertIlisei/MARVIN/blob/main/docs/guides/practice.md))\n\n**Web sidecar**\n\n- 🔒 Structural confirm gate — every Edit/Write/Bash pre-flight, auto-mode audit log\n- 🚢 Ship-review gate —\n`pr-review`\n\n/`security-audit`\n\nenforced at`git commit`\n\nfrom the diff the commit seals: boundary paths (auth · creds · CI · sudoers ·`.env`\n\n· shell scripts · migrations) need both, >3 files or >50 lines needs`pr-review`\n\n, docs-only and lockfiles pass; two denies per skill per turn, then allow and log (ADR-0104) - 📏 Practice rules — rules you accepted enforce at\n`prompt`\n\n/`nudge`\n\n/`deny`\n\nfrom a data table in the design hooks, a deny only where a machine-checkable discharge exists; a recurrence after acceptance is`regressed`\n\n, a quiet window`confirmed`\n\n(ADR-0105) - ⏰ Self-scheduled wakeups — MARVIN's \"I'll check back in 10 minutes\" is real: the\n`schedule_wakeup`\n\ntool arms a bounded server-side timer that starts an actual follow-up turn (ADR-0031); background-and-forget Bash is gate-denied so a build can't finish unreported (ADR-0032) - 💸 Cost tracker — daily/weekly/lifetime spend per project\n- 🔀 Monaco diff viewer — see exactly what MARVIN is about to do before allowing\n- 🧰 Model picker — executor + advisor slots, live model list from Anthropic\n- 🌐 Browser automation — by default MARVIN drives real browsers against\n`localhost`\n\n/ LAN URLs by shelling out to`npx playwright`\n\n(one-shot captures + full`playwright test`\n\n). Opt-in,**off by default**: a gated Playwright** MCP**server (ADR-0045) for first-class, stateful`browser_*`\n\ntools (navigate → snapshot → click → assert) — observation auto-runs, interaction/navigation confirm, and`browser_run_code_unsafe`\n\nis denied - 🔄 Resume across reloads — closing the window doesn't kill a running turn\n- 📊 Graph-aware chat — in-process MCP exposes\n`graph_summary`\n\n,`graph_search`\n\n,`graph_neighbors`\n\n,`graph_path`\n\n; MARVIN builds + refreshes the active project's code and knowledge graphs itself (AST-only, free) so they stay current (ADR-0041) - 🧠 Durable-facts memory — a\n`marvin-memory`\n\nMCP (`remember`\n\n/`recall`\n\n) is the enforced write path for`.marvin/memory.md`\n\n: one fact per file + a one-line index, with caps + content-class guards so it can't bloat into a redundant log;`/memory-compact`\n\ndistills an existing one (ADR-0042)\n\n```\nmacos/                         # SwiftUI macOS app (Xcode / SPM)\n  MARVIN/                      # Swift sources\n  project.yml                  # xcodegen manifest\n  Package.swift                # SPM manifest (swift build fallback)\nsidecar/                       # Next.js 16 sidecar, port 3030\n  src/\n    app/api/                   # REST endpoints (chat, git, files, sessions, health)\n  packages/\n    runtime/                   # Agent SDK runner, auth, session, cost, models, confirm gate\n    tools/                     # Tool policy — auto / confirm / deny\n    project-context/           # Spec + ADR + memory + graph-header injection\n    graphify-bridge/           # Knowledge-graph read + in-process MCP server\n    git-watch/                 # Per-workDir commit stream watcher\n    ui/                        # shadcn primitives\nbin/\n  marvin                     # Lifecycle CLI (start/stop/status/logs/doctor/install/uninstall)\nscripts/\n  install.sh                 # Remote one-liner installer (curl | bash)\n  uninstall.sh               # Remote one-liner uninstaller\n  setup.sh                   # Interactive optional-dep prompts\n  install-skills.sh          # Install skills to ~/.claude/skills/ (clones upstream on demand)\ndocs/\n  decisions/                 # ADRs\n  roadmap.md                 # In-flight + shipped features\n  history/CHANGELOG.md       # Chronological record\n```\n\n**macOS app**\n\n- Swift 5.10 · SwiftUI · Observation framework\n- STTextView (code editor) · SwiftTreeSitter (syntax highlighting)\n- URLSession (loopback HTTP to sidecar)\n\n**Web sidecar**\n\n- Next.js 16 · TypeScript · Tailwind 4 · shadcn/ui\n`@anthropic-ai/claude-agent-sdk`\n\n0.3 — with`TodoWrite`\n\nopted back in and in-process MCP servers`alwaysLoad`\n\n([ADR-0073](/RobertIlisei/MARVIN/blob/main/docs/decisions/0073-agent-sdk-0-3-upgrade.md))- pnpm workspaces · Turbo\n- In-process MCP server:\n`marvin-graph`\n\n(browser automation is via`npx playwright`\n\nshell-out, not an MCP)\n\n**v0.1.102–0.1.104 — the practice loop, the ship-review gate, and a night of measuring MARVIN against itself.** A session audit ([ADR-0104](/RobertIlisei/MARVIN/blob/main/docs/decisions/0104-ship-review-gate.md)) found every mechanical rule held and every prompt-only one did not: `.gitlab-ci.yml`\n\n, a script that fetches secrets, a production sudoers grant and SMTP credentials shipped across **eight pushes with pr-review and security-audit invoked 0×** — the same ~0× the 2026-05-22 audit measured for soft-nudge language. The review skills are now enforced at\n\n`git commit`\n\nby a gate that reads the diff. Then the general form of that audit became a feature ([ADR-0105](/RobertIlisei/MARVIN/blob/main/docs/decisions/0105-practice-loop.md)): a nightly, read-only pass over a project's transcripts runs deterministic extractors for repeat failures (unreviewed boundary commits, graph-first skipped, stalled turns, missing handoffs, skills read by hand instead of invoked, reviews whose findings went unacted, plans left behind, commands re-run verbatim) and their paired successes, scores them with weights fit from outcomes, proposes a rule at three sessions, enforces an approved one at\n\n`prompt`\n\n/ `nudge`\n\n/ `deny`\n\n, and measures whether it held. The first backtest on a real project — **397 sessions in 11 s**— produced six proposals; three were MARVIN's own and were fixed in the runtime the same night. v0.1.103 made the four hand-written gates rows the Practice pane controls; v0.1.104 adds the cold start (a calibration counter, and rules proven in your other projects offered for adoption), the\n\n[Practice guide](/RobertIlisei/MARVIN/blob/main/docs/guides/practice.md), and three fixes from the first report: a bare project-local skill name rewritten to its plugin-namespaced form at the gate (29 \"Unknown skill\" failures, every success namespaced), an advisory nudge on an identical re-run of a failed command, and a once-per-turn block on a three-edit turn under a plan whose checklist never moved. Also: a transcript made unloadable by half an emoji (a UTF-16 slice through a surrogate pair — three fixes, nothing lost), and a chat at 100 % CPU because every row re-laid-out on every streamed event (\n\n`ChatMessageRow`\n\nwas not `Equatable`\n\n).**v0.1.87–0.1.98 — IDE parity, and four bugs that only measurement found.** Two halves. The first is parity with the reference IDE (Antigravity, a VS Code fork), audited item by item into a [parity matrix](/RobertIlisei/MARVIN/blob/main/docs/reference/ide-parity.md): a **language-server client** ([ADR-0099](/RobertIlisei/MARVIN/blob/main/docs/decisions/0099-lsp-client-for-live-diagnostics.md)) so diagnostics come from the buffer rather than from disk — verified against a real `sourcekit-lsp`\n\n, which reported a type error on an **unsaved** edit while the file on disk still said otherwise, the exact capability a CLI runner cannot have; a **command registry** making the menus, the ⇧⌘P palette and the ⌘/ sheet three renderings of one array (it immediately surfaced two double-bound keys); **source control** reaching the reference's feature set, including four routes that had shipped with *zero* callers — the branch name was a `Text`\n\n, so the feature was complete, tested, documented and unreachable; a **Problems panel** that searches the whole tree rather than the repo root, where \"found nothing\" had been rendering as \"your code is clean\"; and a tranche of self-contained editor commands. The second half is a lesson worth more than the features: **four bugs in a row were diagnosed wrongly from reading source, and settled immediately once something was measured.** A file tree drawing over the title bar took three wrong guesses about ScrollView ideal heights before a geometry probe said *container at y=52, tree at y=0* — not too tall, 52pt too high, exactly the title bar, because `VSplitView`\n\ndoes not inherit the safe area. An app frozen at 100 % CPU with two sessions open was a width latch with **no deadband**: collapsing changed the measured width, and one threshold in both directions let it cross back, each cycle re-forming the split view's panes. A Stop-All button was permanently disabled because it gated on a property nothing had set since the WebView was removed. And two sessions that looked \"interconnected\" had genuinely separate conversations — distinct SDK session ids per transcript — but collided on the **working tree**, which Golden Rule 1 forbids and nothing enforces. Also shipped: `CLAUDE.md`\n\nis finally injected into project context (it never had been), chat prose is selectable across lines, and `Stop Session & All Work`\n\ncancels the jobs and wakeups a turn leaves behind.\n\n**v0.1.77–0.1.86 — a day of failures that looked like nothing happening.** Ten releases, one recurring shape. ** ADR-0097 — verify against what runs.** The Claude-plan usage bars survived two previous fixes because the SDK never resolves\n\n`claude`\n\nfrom `PATH`\n\n: it spawns the native binary its own package links to, and the bundler picked that with `find | head -n1`\n\n, linking **0.2.113** beside a 0.3.251 SDK. Every turn ran a CLI 138 versions behind while the About panel confirmed the right one. The same pass found\n\n`Skill`\n\nhad been called **29 times across every transcript ever recorded, failing every time, with zero successes**— the pane listed skills the loader had skipped, because\n\n`description:`\n\nis the load-bearing frontmatter key and the registered identity is always the directory. **That upgrade removed**\n\n[ADR-0098](/RobertIlisei/MARVIN/blob/main/docs/decisions/0098-the-rail-must-outlive-the-tool-surface.md)— a rail keyed on vendor tool names is only as durable as those names.`Grep`\n\n/`Glob`\n\n; all four graphify-first guards keyed on them with no `Bash`\n\nbranch, so searching moved where the rail is blind — **15 of 18 Bash calls search-shaped against 2 graph calls**.\n\n**And a run of silent failures:** a\n\n`ScrollView`\n\nunder a frame with no `idealHeight`\n\nmeasured the whole transcript (eight 61-second hangs); the bottom panel mounted tabs only on an `activeTab`\n\n*change*, so opening it on the selected tab gave an empty pane with no shell; extended thinking rendered as\n\n`unhandled block: thinking`\n\n; `_ = try await URLSession.data(for:)`\n\ntreated an HTTP 500 as success, so Discover ran two minutes and showed nothing; `which(\"tsc\")`\n\nunder a Finder-launched app's bare `PATH`\n\nreturned `[]`\n\n, rendered as \"No problems detected\"; and the terminal broke on project switch — sessions keyed by `workDir`\n\n, SwiftUI keeping the representable's identity, `updateNSView`\n\nswapping the session but not the view. Skills work on OpenRouter (`tools: []`\n\n, and the proxy answers `count_tokens`\n\nwith an estimate rather than a fabricated zero).**v0.1.65 — the SDK catches up, and two things that only looked broken.** Agent SDK\n\n**0.2.113 → 0.3.245**(\n\n[ADR-0073](/RobertIlisei/MARVIN/blob/main/docs/decisions/0073-agent-sdk-0-3-upgrade.md)) — MARVIN was behind the end of its own 0.2 line, on a version predating\n\n`TodoWrite`\n\n's deprecation. Every 0.3 default that would change behaviour is pinned back with its reason: `TodoWrite`\n\nopted in over the Task tools so the plan spine keeps receiving snapshots; all five in-process MCP servers `alwaysLoad`\n\n, because 0.3 defers MCP tools behind `ToolSearch`\n\nand the graphify-first hooks would deadlock a turn with no `graph_*`\n\ntools. Verified live on Sonnet 5. **\"I lost all my sessions\"**(\n\n[ADR-0072](/RobertIlisei/MARVIN/blob/main/docs/decisions/0072-session-list-must-not-parse-transcripts.md)) — nothing was lost: the session list\n\n`JSON.parse`\n\nd 2.6 GB per request (23 s), the client cancelled and restarted it on every layout rebuild, and hydration waited on it. Scan + cache: 36 ms; hydration no longer depends on the list. **\"MARVIN is skipping plan steps\"**(\n\n[ADR-0068](/RobertIlisei/MARVIN/blob/main/docs/decisions/0068-plan-dedupe-provenance-and-negative-claims.md)add. 4) — a 10-step plan was tracked as 16 because its\n\n`Sources:`\n\nbibliography parsed as steps and one URL was `in_progress`\n\n; the parser now stops at a reference heading. Skills and plugins can be **updated**, not just installed (\n\n[ADR-0071](/RobertIlisei/MARVIN/blob/main/docs/decisions/0071-install-provenance-and-update-path.md)); pane actions moved out of the window toolbar, with tooltips.\n\n**v0.1.56–0.1.64 — stability, backlog review, and find-in-file.** Four app-killing crashes traced and fixed. The **file tree** was retired off SwiftUI's `OutlineGroup`\n\nentirely ([ADR-0061](/RobertIlisei/MARVIN/blob/main/docs/decisions/0061-file-tree-flat-list-not-outlinegroup.md)): four separate fixes each closed one way for its outline coordinator to disagree with AppKit, and the fourth crash was *caused* by the third — so the tree now flattens to a plain row list and the whole failure class is structurally gone. A second crash resisted two fixes aimed at a mechanism inferred from the stack alone, so MARVIN now **captures the exception itself** ([ADR-0062](/RobertIlisei/MARVIN/blob/main/docs/decisions/0062-update-constraints-loop-identified-mitigated.md)) — name, reason and symbols to `~/Library/Logs/MARVIN/exceptions.log`\n\n— which identified it on the first occurrence as AppKit's non-converging-layout breaker, now survived rather than fatal. The **check-back guard** stopped swallowing timed promises ([ADR-0055](/RobertIlisei/MARVIN/blob/main/docs/decisions/0055-checkback-promise-auto-arm-guard.md) addendum): a background dev server counted as follow-through for \"I'll check in ~2.5 minutes\", though it never exits and so never reports. **Backlog review** ([ADR-0063](/RobertIlisei/MARVIN/blob/main/docs/decisions/0063-backlog-groomer-review-not-execute.md)) and **classification** ([ADR-0064](/RobertIlisei/MARVIN/blob/main/docs/decisions/0064-backlog-kind-and-blocked.md)) landed read-only: the groomer reports, you decide. **Find in file** returned (⌘F), and `bin/marvin doctor`\n\nstopped telling you to kill your own running app.\n\n**v0.1.55 — verify-then-remediate contract: bounded self-fix, gated scope-fix.** MARVIN's Phase 6/7 loop had a \"verify, then what?\" gap — it walked the Definition of Done but had no explicit contract for what to do when a check failed. Now split by failure class. **Phase 6 (mechanical):** typecheck / test / build failures MUST self-remediate without asking — capped at 3 attempts per milestone with an early **no-progress stop** (identical errors twice = spinning → stop), then an honest failure report; MUST NOT claim landed, weaken the DoD, or skip the failing check. **Phase 7 (scope):** an unmet DoD bullet gets **surface-and-offer** — state the gap plus the one concrete next step, then gate (\"one gap, one gate\"); MUST NOT loop back into Phase 6 unprompted. A fully autonomous retry-until-DoD mode was deliberately *not* built — it institutionalizes the Golden-Rule-8 \"helpful spiral\"; revisit only as an explicit opt-in with its own ADR, cost budget, and progress metric. Prompt-only change in `personality.ts`\n\n; also fixed 9 pre-existing typecheck errors in `can-use-tool-dispatch.test.ts`\n\n(readonly-array fixture vs the SDK's mutable `PermissionUpdate[]`\n\n).\n\n**v0.1.54 — the IDE no longer resets on a transient health blip.** The window \"kept resetting\" mid-work — pane layout, file-tree expansion, terminal, editor, chat scroll all snapping to default. `ContentView.mainContent`\n\nswitches its whole view tree on `health.state`\n\n, and `HealthMonitor.pollOnce`\n\nflipped to `.offline`\n\non any single failed `/api/health`\n\npoll (3 s timeout, no hysteresis) — a healthy-but-busy sidecar answering slowly tore down and rebuilt the entire IDE. Fix: demote to `.offline`\n\nonly after **3 consecutive** misses (hold `.online`\n\n/`.connecting`\n\nthrough blips), poll fast while misses are pending so a genuine outage still surfaces in seconds, and bump the poll timeout to 5 s.\n\n**v0.1.53 — backlog \"Promote to plan\" actually plans.** Promoting a backlog item did nothing: `promoteBacklog`\n\nsent \"Implement this item…\" in whatever mode was active and never switched to Plan mode — but the turn-completed ingest only mints a tier-2 Plan + approval chip when `mode == \"plan\"`\n\n— and if a turn was in flight `sendControl`\n\n's `!isSending`\n\nguard silently dropped it while the panel closed anyway. Now it switches to Plan mode and asks MARVIN to present a plan inline (read-only first), and queues the request when busy instead of dropping it.\n\n**v0.1.52 — file-tree crash fixed.** The app trapped (`EXC_BREAKPOINT`\n\nin `OutlineListCoordinator.recursivelyDiffRows`\n\n) during a file-tree row diff: `FileNode.outlineChildren`\n\nreturned a non-nil empty array `[]`\n\nfor empty directories, but SwiftUI's `OutlineGroup`\n\nexpects `nil`\n\n(leaf) or a non-empty array — an agent mutating files mid-session flipped a node into the `[]`\n\nshape and the next diff crashed. Empty dirs now return `nil`\n\n(leaf). A companion build fix: the install smoke-probe now reaps the forked `next-server`\n\nworker (it bound the probe port and survived the parent kill) so installs stop leaking orphan sidecars.\n\n**v0.1.51 — plan-in-context: the model is aware of the active plan every turn.** The plan was UI-only state — a strip rehydrated from the transcript, never injected into the model's prompt — so after a chat switch or context compaction the model lost the plan while the strip still showed it (\"MARVIN stopped tracking / won't continue it\"). The client now sends a compact `planContext`\n\nsnapshot (title + `[x]/[~]/[ ]`\n\nsteps + sub-tasks, marked authoritative) every turn, and the runtime appends it as a `<system-reminder>`\n\n**suffix on the user message** — the uncached volatile tail, so it's prompt-cache-safe (Anthropic's caching rules) and never persisted to `turn.user`\n\n. Mirrors how Claude Code re-injects its todo list. ADR-0051.\n\n**v0.1.49–0.1.50 — plan integrity.** A Plan-mode turn that hit a transient **529 Overloaded** got its error text ingested as a plan (no `# Plan`\n\nheading → fallback title \"Plan\" → `plan.md`\n\n), hijacking the active plan; the turn-completed ingest is now gated on `PlanCard.isPlan`\n\n(0.1.49). And a step could read \"done\" while all its sub-tasks were still open — completion is now a hard invariant: a step with sub-tasks completes **iff every sub-task is completed** (0.1.50). ADR-0046 / ADR-0049 addenda.\n\n**v0.1.44–0.1.45 — plan-step join key + Continue anchoring.** Tasks linked to plan steps by *fuzzy text match*, so a reworded `TodoWrite`\n\nitem landed as an orphan and the plan never advanced. The executor now tags each item `[N]`\n\n(plan step) / `[N.M]`\n\n(sub-task), giving a stable join key, with upward roll-up (sub-tasks done → parent done) — ADR-0049. And the **Continue** control re-injects the active plan's concrete steps + a \"resume only this, don't re-audit the project\" guardrail, so a paused plan resumes itself instead of triggering a whole-project re-audit — ADR-0050.\n\n**v0.1.46–0.1.48 — browser/MCP + background-job polish.** The Playwright MCP didn't start under a Finder-launched app (minimal launchd PATH → bare `npx`\n\nENOENT'd); PATH is now enriched at the sidecar launch *and* on the spawned server's env (0.1.46). MCP-vs-CLI browser selection became a deterministic MUST trigger instead of a soft nudge (0.1.47). And a long-running background job (a dev server) SIGTERM'd on app quit no longer fires a spurious \"job did NOT succeed\" turn that resurfaced on every relaunch — shutdown/stop signals are treated as \"stopped, not finished\" (0.1.48). ADR-0045 / ADR-0038 addenda.\n\n**v0.1.43 — full session history via incremental paging.** Restoring a session on cold start loaded only the last 200 `cli.event`\n\nlines (`hydrate(tail:200)`\n\n+ the server's `turns.slice(-tail)`\n\n) — and since one exchange spans many events, that was just the last few turns, with no signal it had been clipped. The server now reports `truncated`\n\n/`totalTurns`\n\n; the client paints the last 200 lines instantly, then a top-of-list control loads the **next 200** (or jumps to the **full log**) on demand, with a live \"N of M lines\" count. Fast first paint plus user-controlled completeness — the full transcript is always reachable, and the 120 MB worst case is never auto-loaded. ADR-0048.\n\n**v0.1.42 — plan persistence + review-window fixes + backlog capture-at-discovery.** Three changes. **(1) Plan persists across chat switches** ([ADR-0046](/RobertIlisei/MARVIN/blob/main/docs/decisions/0046-plan-as-durable-spine.md) follow-up): the plan strip was in-memory/session-scoped, so switching chats or relaunching lost it; `replay`\n\nnow reconstructs the plan + checklist from the transcript on session load (last `# Plan`\n\nreply + latest `TodoWrite`\n\nfor step progress), and a later `TodoWrite`\n\nreconciles into the restored plan instead of orphaning as a task list. **(2) Review window** ([ADR-0034](/RobertIlisei/MARVIN/blob/main/docs/decisions/0034-agent-change-review-checkpoints.md) bugfix): a newly-written file (one all-added hunk) showed a half-empty side-by-side and hung the window; added/deleted files now render single-column with a banner, the diff flattens to a virtualized row-level `LazyVStack`\n\n, and a >1500-line diff is gated behind \"Show anyway\" (mirrors GitHub/VS Code). **(3) Backlog capture-at-discovery** ([ADR-0047](/RobertIlisei/MARVIN/blob/main/docs/decisions/0047-backlog-capture-at-discovery.md)): \"noticed in flight\" items were lost when a turn ended without a handoff; a new `provisional`\n\nstatus + `backlog_add … provisional:true`\n\nauto-park a discovery the instant it's noticed, with a keep/dismiss review at the handoff.\n\n**v0.1.41 — plan as the durable spine.** Two plan-tracking bugs: a `TodoWrite`\n\nemitted mid-plan wholesale-replaced the checklist, so sub-tasks erased the plan's steps and a sub-task-only list fired a false \"Plan complete\"; and a second plan overwrote the single plan slot, making the original untrackable. The active plan now owns hierarchical steps — incoming `TodoWrite`\n\ns **reconcile** into them (matched step → status update, unmatched item → nested sub-task) instead of replacing the list, completion is computed over top-level steps only, and plans live in a revision-aware session list with a strip picker so prior plans stay navigable. `personality.ts`\n\n+ the approve-to-execute instruction now require a full carry-forward `TodoWrite`\n\n(never a partial list). ADR-0046, revising ADR-0036.\n\n**v0.1.40 — fix: AskUserQuestion's \"Send choice\" did nothing.** The interactive decision sheet (ADR-0040) registered its confirm with the default **5-minute** auto-deny timeout — the one meant for permission confirms. A human weighing detailed options for >5 min was silently auto-DENIED (the turn proceeded ignoring the choice; the registry entry was deleted), so a later \"Send choice\" click hit a dead confirm and did nothing. AskUserQuestion is the model explicitly blocking on a human decision, so it now registers with NO auto-deny timer — it waits for you; the turn's `finally`\n\n(`clearTurnConfirms`\n\n) + Stop unwind an abandoned one. Regression test in `confirm-registry-timeout.test.ts`\n\n.\n\n**v0.1.39 — Playwright MCP, opt-in + gated.** MARVIN's first EXTERNAL (stdio) MCP server (`npx @playwright/mcp@latest`\n\n), off by default. The gate previously blanket-allowed every MCP tool — safe for the in-process graph/memory/backlog servers, unsafe for Playwright's code-exec/egress tools. A `mcpToolPolicy`\n\nnow classifies the `playwright`\n\ntools (observation auto · interaction/navigation confirm · `browser_run_code_unsafe`\n\ndeny), the subagent read-only invariant restricts scouts to observation, and a `playwrightEnabled`\n\ntoggle is threaded to the web Setup popover + macOS Settings ▸ Browser (ADR-0045).\n\n**v0.1.38 — Project backlog.** A durable, per-project parking lot for *actionable* \"noticed in flight, not in scope\" follow-ups that used to evaporate with the chat. A `marvin-backlog`\n\nMCP (`backlog_add`\n\n/ `list`\n\n/ `resolve`\n\n, content-class enforced) + `GET/POST/PATCH /api/backlog`\n\nshare one store (file-per-item + index, mirroring memory); open items re-inject into next session's context; a macOS panel + tray chip gives Done / Dismiss / Promote-to-plan. Consent-gated capture; a parking lot, never a queue agents pull from (ADR-0044).\n\n**v0.1.37 — server-initiated turns reach an idle client.** Background-job completion (ADR-0038) and timed wakeups (ADR-0031) fire a real turn server-side, but the idle app only attached to a turn's stream on session hydrate — so the completion turn ran into the bus with no listener and was invisible until a session switch. A per-project always-on SSE (`/api/chat/announce`\n\n) now re-attaches the idle app to any server-started turn, with a \"background job running\" chip (ADR-0043).\n\n**v0.1.33–0.1.36 — turn-lifecycle hardening + context panel.** One live turn per session (`POST /api/chat`\n\nreturns `409`\n\ninstead of evicting a running turn, and eviction aborts the displaced agent — v0.1.33); **Stop** is authoritative (`cancelLiveTurn`\n\nforce-ends a wedged turn so the session can't lock — v0.1.34); a click-to-open **context-usage panel** on the status-bar `ctx`\n\nchip with a per-category breakdown from live SDK usage (v0.1.35); and a fired wakeup yields to a live interactive turn instead of evicting it (v0.1.36). (v0.1.34 also ended a stray-tag version divergence, resetting the line to 0.1.x.)\n\n**v0.1.32 — memory as a curated durable-facts layer.** A real project's `.marvin/memory.md`\n\nhad bloated to 419 KB / ~99 % redundant with ADRs, git, and the changelog (the model mirrored its Ship summaries into it). memory now holds ONLY what the next session can't re-derive from those — invariants, gotchas, constraints, external facts. A new in-process ** marvin-memory** MCP (\n\n`remember`\n\n/ `recall`\n\n) is the *enforced*write path: one fact →\n\n`.marvin/memory/<slug>.md`\n\n+ a one-line index, supersede-by-name, with length caps + content-class guards that reject activity/status. `personality.ts`\n\ncarries a MUST/MUST-NOT firm surface; a **command distills an existing log. The Scope-met chip is retargeted to**\n\n`/memory-compact`\n\n`.marvin/session-notes.md`\n\nso it can't pollute the index. ADR-0042.**v0.1.31 — \"Prompt is too long\" fixed.** On a mature project the first message overflowed the model's 200 K window — `buildProjectContext`\n\ninjected every ADR in full + the whole memory.md (~566 K tokens measured). Two layers (ADR-0041): MARVIN now **builds/maintains the active project's graphs** (code + knowledge, AST-only/free, scoped to the project — never its own repo), and the first-message context is **budgeted** — ADRs as a titles index (details via the knowledge graph + targeted reads), memory as a recent tail, curated docs whole. Measured 566 K → ~13 K tokens.\n\n**v0.1.30 — interactive AskUserQuestion + Node-24 CI.** When the model hits a real decision it calls **AskUserQuestion** and MARVIN renders the options as clickable buttons (single/multi-select + \"Other\"), returning your pick to the model as the tool result — instead of prose \"(a)/(b)\" you could only answer by typing. Routed through the existing confirm channel in every mode (ADR-0040). Also bumped every release-workflow action to its Node-24 major ahead of GitHub's cutoff.\n\n**v0.1.27–29 — two-tier to-do / plan polish.** The checklist strip splits into a neutral **\"Task list\"** (bare `TodoWrite`\n\n, no plan) and a purple **\"Plan — <title>\"** (plan-backed, ticks off in place); a presented plan is auto-written to `.marvin/plans/<slug>.md`\n\nand opened in the editor pane (\"Open plan\"); the plan title/filename derive from the `# Plan`\n\nheading wherever it sits (no more garbage slugs); and a completed plan no longer shows a contradictory \"Approve & execute\" chip. ADR-0036 (two-tier addendum). Plus the Homebrew \"MARVIN.app is damaged\" fix — the cask now strips `com.apple.quarantine`\n\nin a `postflight`\n\n(modern Homebrew quarantines casks by default; ad-hoc bundle + quarantine reads as \"damaged\" on macOS 26).\n\n**v0.1.26 — The plan card.** Plan-mode plans render as a structured, collapsible Cursor-style **plan card** (title, step count, styled headings/steps/code) instead of a plain-text bubble — the plan-mode prompt mandates a `# Plan — <title>`\n\nopening heading, detected live and on transcript replay. Approving seeds the To-dos checklist from the plan's steps, and the paused chip now names the next step and what there concretely is to review (the stopping error, or the changed-file count).\n\n**v0.1.25 — Plan-mode UX polish.** Session-scoped strips (no stale plan in a new chat); Approve/Continue as hidden control actions (no fake user message in the chat); **Save plan** to a Markdown file you can follow alongside the chat; collapse/dismiss the checklist (auto-collapses when done); and the checklist relabeled **\"To-dos\"** — it's the task tracker (used in any mode), while the plan stays a distinct inline message + file.\n\n**v0.1.24 — Plan mode decoupled, chat strip tray.**\n\n**Plan mode**(ADR-0036 rev) — a read-only planning turn on your chosen** advisor**model presents a numbered plan** inline**in the chat (no modal); an**\"Approve & execute\"** chip then runs it in a separate**Agent** turn on your**executor** model. Models routed by role; no re-planning.**Chat strip tray**— the plan checklist, changed-files Review, and session controls now live in one opaque, divider-separated tray that no longer overlaps the message log.\n\n**v0.1.23 — Background jobs, fetch skills from Git, Plan follow-through.**\n\n**Background jobs**(ADR-0038) —`run_background_job`\n\nruns a long command past the turn and fires a real follow-up turn on exit with the result; shell backgrounding is denied at the gate.**Fetch skills from Git**(ADR-0039) — \"Add from GitHub\" installs a skill from any repo, a`…/tree/…`\n\nsub-path, or a plugin marketplace (clone + copy only).**Plan-mode follow-through**(ADR-0036) — the plan persists in the chat and becomes the tracked to-do checklist (○→◌→✓); the prompt requires live`TodoWrite`\n\nupdates.**Skills pane** reorganised by state: active here · installed-off-here · recommended to add.\n\n**v0.1.22 — Modes, Cursor-style chat surface, skill enablement.**\n\n**Ask · Agent · Plan modes**(ADR-0036) — a`mode`\n\naxis orthogonal to the auto/gated strategy. Ask is read-only (hard-denied at the gate); Plan runs under the SDK's plan mode and surfaces an approval card before executing; Agent is the unchanged default. The model's`TodoWrite`\n\nrenders as a live checklist.**Cursor-style chat surface**— mode + reasoning controls moved into the input box; chat tabs you can open and close, persisted per project.** Per-project skill enablement**(ADR-0037) — installed ≠ active: a core/domain catalog + fingerprint default names the skills relevant to this project and tells the model to ignore the rest (20→7 on this repo). Skills-pane toggles +`.marvin/skills.json`\n\n.\n\n**v0.1.21 — Change-review diff editor.**\n\n**VS Code / Cursor-style diff editor**— the review surface is its own resizable window: side-by-side original │ modified, line numbers, and a Split/Inline toggle (v0.1.20). The editor's diff gutter now tracks lines exactly on scroll — markers come from STTextView's real layout geometry, cached, instead of a line-height guess that drifted (v0.1.21). And**committing a change clears it from the review** the way it leaves VS Code's Source Control list — a committed change is an accepted one (`reconcileCommitted`\n\n, drops only, never rewrites a baseline). ADR-0034.**Agent change review**— the permission gate snapshots every file's pre-image on first agent touch per session; accept advances the baseline, reject reverse-applies to disk — never`git discard`\n\n, which would destroy uncommitted user work. v1 blind spot: Bash-driven mutations aren't pre-imaged. ADR-0034.**Per-role reasoning effort**— the advisor is a registered agent definition carrying its own model + effort, settable independently of the executor (the SDK's`advisorModel`\n\noption turned out to be unwired; the agents-map registration is what actually works). ADR-0033.**Self-scheduled wakeups**—`schedule_wakeup`\n\n/`cancel_wakeup`\n\n/`list_wakeups`\n\nMCP tools backed by a bounded, persistent, boot-re-armed scheduler; a fired wakeup starts a real turn that resumes the session. Bash`run_in_background`\n\nis gate-denied (the runtime can't deliver completion notifications, so the capability shouldn't exist). ADRs 0031, 0032.**The bundled app owns its port**— launch reclaims`:3030`\n\nfrom any stale sidecar before spawning, and`/api/health`\n\nreports the serving process's app version, so \"new app on disk, old code in memory\" can't recur. ADR-0035.\n\n**v0.1.6 — Brew-installable, project-aware.**\n\n**Brew cask**—`brew install --cask marvin-ai`\n\nproduces a working IDE on a fresh Mac with no Swift / Node / pnpm / Xcode required. Bundled Node 22 + Next.js standalone sidecar inside`MARVIN.app/Contents/Resources/`\n\n(ADR-0023).**Project-aware skill recommendations**— fingerprint detector emits namespaced tags (`framework:next`\n\n,`architecture:multi-tenant`\n\n,`test:playwright`\n\n, …) from a project's manifests + memory file; the suggestion engine maps tags to skills you can either install user-global or build project-local. ADR-0024.**Skills pane**— fourth tab in the left pane (Files / Search / Source Control / Skills): suggestions for the current project, your user-global skill catalog, and project-local skills. One-click \"park all\" closes the audit loop. ADR-0025.\n\n**v1.3 — Fully native IDE surface (shipped 2026-05-05).**\n\nThe WebView is gone. The macOS app is a pure SwiftUI IDE shell backed by the Next.js sidecar over loopback. Full feature parity with the web-era UI plus IDE features the browser couldn't provide:\n\n**WebView removed**— all UI surfaces are native Swift; no Tauri, no WKWebView** Syntax highlighting**— tree-sitter grammars for Swift, TS/TSX, JS/JSX, Go, Rust** Image preview**— binary image files (PNG, JPEG, GIF, WebP, HEIC) open inline** Image paste**— ⌘V in chat accepts screenshots and dragged images** Find in files**— ripgrep-backed with glob filter and replace-all** Push / pull / fetch**— full remote ops in the source control panel** Session history**— clock menu in chat header restores any past session** Right-pane resize**— min-width fixed so brain + chat never overlap other panes\n\nSee [ docs/roadmap.md](/RobertIlisei/MARVIN/blob/main/docs/roadmap.md) and\n\n[.](/RobertIlisei/MARVIN/blob/main/docs/history/CHANGELOG.md)\n\n`docs/history/CHANGELOG.md`\n\n**First diagnostic — always:**\n\n```\ncurl -s http://localhost:3030/api/health | jq .\n```\n\n| Symptom | Likely cause | Fix |\n|---|---|---|\n`auth.mode: \"none\"` |\nNo credentials detected | `ANTHROPIC_API_KEY` in env, or `claude auth login` |\n`binaryError` in `/api/health` |\nClaude CLI not on PATH | `npm install -g @anthropic-ai/claude-code` or set `MARVIN_CLAUDE_BIN` |\nEvery turn → `400 Consumer Terms` |\nAnthropic account hasn't accepted latest Terms | Open\n|\n\n`EADDRINUSE :::3030`\n\n`lsof -iTCP:3030 -sTCP:LISTEN`\n\n→ kill it`cd <workDir> && /graphify .`\n\n`~/Library/Logs/MARVIN/sidecar.log`\n\nfor the cause; relaunch MARVIN`No module 'STTextView'`\n\n`cd macos && swift package resolve`\n\n`ANTHROPIC_API_KEY`\n\ndirectly**Lifecycle helpers:**\n\n```\nbin/marvin status   # auth + model + data dir\nbin/marvin doctor   # preflight checks\nbin/marvin logs     # tail .marvin/dev.log\n```\n\n**Still stuck?** Open an issue at [github.com/RobertIlisei/MARVIN/issues](https://github.com/RobertIlisei/MARVIN/issues) with `/api/health`\n\noutput, the last 20 lines of `~/Library/Logs/MARVIN/sidecar.log`\n\n, and your macOS version.\n\n[White paper](/RobertIlisei/MARVIN/blob/main/docs/whitepaper/WHITEPAPER.md)— the design position, the evidence, and the results;[Technical Reference](/RobertIlisei/MARVIN/blob/main/docs/whitepaper/TECHNICAL-REFERENCE.md)is the exhaustive companion (both also as[PDF](/RobertIlisei/MARVIN/blob/main/docs/whitepaper/WHITEPAPER.pdf)/[PDF](/RobertIlisei/MARVIN/blob/main/docs/whitepaper/TECHNICAL-REFERENCE.pdf))[Overview](/RobertIlisei/MARVIN/blob/main/docs/getting-started/overview.md)— what MARVIN is, who it's for[Quickstart](/RobertIlisei/MARVIN/blob/main/docs/getting-started/quickstart.md)— install → first session[Modes & workflows](/RobertIlisei/MARVIN/blob/main/docs/guides/workflows.md)— Ask / Agent / Plan with worked examples, and how MARVIN takes decisions[Practice](/RobertIlisei/MARVIN/blob/main/docs/guides/practice.md)— how MARVIN learns from its own sessions: findings, rules, tiers, verification, and the pane that manages them[Architecture](/RobertIlisei/MARVIN/blob/main/docs/getting-started/architecture.md)[HTTP API reference](/RobertIlisei/MARVIN/blob/main/docs/reference/api.md)[ADRs](/RobertIlisei/MARVIN/blob/main/docs/decisions)— design decisions\n\nEvery release zip published since v0.1.x is signed with [minisign](https://jedisct1.github.io/minisign/). The signature lives next to the zip on each GitHub Release as `MARVIN-<version>-arm64.zip.minisig`\n\n.\n\n**Public key** (pinned here, in the [ homebrew-marvin](https://github.com/RobertIlisei/homebrew-marvin#release-signing) tap's README, and in\n\n[):](https://github.com/RobertIlisei/homebrew-marvin/blob/main/Casks/marvin-ai.rb)\n\n`Casks/marvin-ai.rb`\n\n```\nuntrusted comment: minisign public key 0794CFDFA5E629D5\nRWTVKeal38+UBwQ3tC8ETdPZkv8fFLchoXdtwi7UI9XMhaJWuUwx4QAQ\n```\n\nThe same key is mirrored in [ .minisign-pubkey](/RobertIlisei/MARVIN/blob/main/.minisign-pubkey), in the\n\n[tap's README, and in](https://github.com/RobertIlisei/homebrew-marvin#release-signing)\n\n`homebrew-marvin`\n\n[as the](https://github.com/RobertIlisei/homebrew-marvin/blob/main/Casks/marvin-ai.rb)\n\n`Casks/marvin-ai.rb`\n\n`MARVIN_MINISIGN_PUBKEY`\n\nconstant. Three pinned copies across two repos — a tap-repo compromise that swapped the cask's pubkey would be visibly inconsistent with this repo's record.**Verify a downloaded release:**\n\n```\nbrew install minisign\nVERSION=0.1.9   # whichever version you downloaded\ncurl -fLO \"https://github.com/RobertIlisei/MARVIN/releases/download/v${VERSION}/MARVIN-${VERSION}-arm64.zip\"\ncurl -fLO \"https://github.com/RobertIlisei/MARVIN/releases/download/v${VERSION}/MARVIN-${VERSION}-arm64.zip.minisig\"\ncurl -fLO https://raw.githubusercontent.com/RobertIlisei/MARVIN/main/.minisign-pubkey\nminisign -V -p .minisign-pubkey -m \"MARVIN-${VERSION}-arm64.zip\"\n```\n\nA successful verify prints `Signature and comment signature verified`\n\nand exits 0. If the signature doesn't verify, **do not install the artefact** — and please open an issue, because either:\n\n- the tap repo or the release was tampered with, or\n- our private key was lost (in which case we'll publish a rotation announcement, also signed)\n\nSee [ADR-0026](/RobertIlisei/MARVIN/blob/main/docs/decisions/0026-release-artefact-signing-minisign.md) for the full signing model, the threat shapes this defends against, and the key-rotation policy.\n\nThe cask install path (`brew install --cask marvin-ai`\n\n) does not yet auto-verify the signature — Phase 2 of ADR-0026 will add a `preflight`\n\nstep. Until then, manual verification is the canonical path for users who care.\n\n[MIT](/RobertIlisei/MARVIN/blob/main/LICENSE) · © 2026 Robert Ilisei", "url": "https://wpnews.pro/news/marvin-open-source-macos-ai-coding-ide-that-learns-from-its-own-sessions", "canonical_source": "https://github.com/RobertIlisei/MARVIN", "published_at": "2026-09-03 09:50:05+00:00", "updated_at": "2026-09-03 10:22:41.666857+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "artificial-intelligence"], "entities": ["Robert Ilisei", "MARVIN", "Anthropic", "Homebrew", "Next.js", "SwiftUI", "Node.js"], "alternates": {"html": "https://wpnews.pro/news/marvin-open-source-macos-ai-coding-ide-that-learns-from-its-own-sessions", "markdown": "https://wpnews.pro/news/marvin-open-source-macos-ai-coding-ide-that-learns-from-its-own-sessions.md", "text": "https://wpnews.pro/news/marvin-open-source-macos-ai-coding-ide-that-learns-from-its-own-sessions.txt", "jsonld": "https://wpnews.pro/news/marvin-open-source-macos-ai-coding-ide-that-learns-from-its-own-sessions.jsonld"}}