Sandbox
@AlgoNoRhythm/Flare

Graph IDE and MCP server for agent coding

Flare is a graph-first IDE for agentic coding. It shows files as nodes, imports as edges, and pairs that view with a terminal, task board, review panel, and MCP tools so an agent can work against the same project state you see.

290 stars33 forksTypeScriptUpdated 12d ago
Who it's for

Builders who run Claude Code, Codex, or other terminal agents on a codebase and want shared project context.

What it delivers

You can watch agent edits land on a live repo graph, then review, route, and revert them from one place.

What it does

Live repo graph

Shows every file as a node and imports as edges, with lenses for activity, hotspots, risk, tests, coverage, reuse, unread files, and cycles.

Terminal-backed agent workflow

Keeps a terminal under the graph where you run Claude, Codex, or other agents while Flare watches their writes and updates the map in real time.

Task and decision board

Lets you create tasks from graph selections, copy briefs for an agent, record design decisions, and park questions instead of blocking work.

Review cockpit

Groups writes into bursts, shows who changed what, what was checked, what smells appear, and lets you revert files or whole bursts.

MCP server and project tools

Exposes project state through MCP so agents can list tasks, read working agreements, record intent, ask questions, and fetch repo info.

Cross-agent coordination

Tracks multiple agents by session, watches channel posts about taken files, and marks contention when two agents touch the same work.

Command and risk tracking

Classifies observed commands, flags destructive ones, and raises alerts for risky file changes, coverage gaps, and other review issues.

How to get it

  1. 1Requires Node 20 or newer.
    npm install
    npm run build     # bundle main process (esbuild) + renderer (vite)
    npm start         # launch the desktop app
  2. 2They are also ad-hoc signed and un-notarised. Notarising needs a paid Apple Developer…
    xattr -dr com.apple.quarantine /Applications/Flare.app
  3. 3To build one yourself
    npm run dist      # installer for the platform you are on, into release/
    npm run dist:dir  # unpacked, for a quick look
  4. 4Run it on the platform you are building for. Flare's terminal is a native module that…
    npm version 0.2.0 && git push --follow-tags
  5. 5On Windows, WSL2 is enough to test the Linux build properly: WSLg supplies a display, so…
    cp -r /mnt/c/path/to/Flare ~/flare && cd ~/flare && npm ci
    npx playwright install chromium
    npm test && npx playwright test            # 633 unit + 80 e2e, on Linux
    npx electron-builder --linux --publish never
  6. 6Development mode (hot reload for the renderer)
    npm run dev

README

Flare

A graph-first IDE for agentic coding — desktop app, or served to a browser from the machine the agent runs on.

The main surface is a live graph of your codebase — every file is a node, imports are edges — with a full terminal underneath where you run claude, codex or opencode. As the agent edits files, the graph updates in real time; every change burst is snapshotted into a local shadow history you can diff against and revert to, per file or as a whole tree.


Flare in a minute: opening a folder in the graph, the blast radius of a shared file, four lenses, a task drawn round two files with a box-select, an agent picking that task up over MCP and doing it while the map updates, and the alert Flare raises when it also rewrites a file the rest of the app imports

You run the agent in Flare's terminal, and Flare watches: it maps the repo from the source, attributes every write to whoever made it, and pulls you in when something important changes. The agent takes work from the board and asks its questions there, so the two of you are looking at the same project rather than at a chat log.

What you get

Flare open on its own source with the Activity lens on: shared/insights.ts is hovered and every file that imports it is lit as an amber ray, while the top bar counts the risky changes and the files waiting for review

Flare open on its own source — 99 nodes, 326 edges. The Activity lens shades each file by how recently it changed, and hovering shared/graph.ts lights every file that imports it in amber: the blast radius of one file, without reconstructing it from a grep. Bottom right, an alert Flare raised on its own about src/App.tsx — nothing covers it, and with two agents live it says mixed rather than guessing which of them wrote it.

Three views of the same graph

Switchable from the toolbar or the command palette. Each honours the active lens, the selection, collapsed directories and the search filter.

  • Canvas (default) — dependency cards on a pannable board, ordered left-to-right by dependency depth (SCC-condensed, crossing-reduced, wrapped into bands so a long chain never becomes an unreadable strip): foundations left, entry points right. Cards carry the filename, a lens-coloured rail and badges (complexity, coverage %, untested, TODOs, cycles). Hovering traces imports in blue and importers in amber; shift+click traces the path between two files; cards can be dragged and their positions persist. Zooming out swaps the cards to a plate skin (semantic zoom) so the shape of the repo still reads.
  • Wheel — every node sits on one ring ordered by directory, dependencies cross the middle as bundled chords, and cluster bands are labelled around the outside. Drag to spin, alt+wheel to rotate, scroll to zoom, shift+drag to pan, ctrl+drag to box-select. Click a node to pin its dependency directions; hover a cluster band to isolate that directory; click a band to collapse or expand it.
  • Districts — a squarified treemap where area is lines of code and shade is the active lens. The fastest read on "how big is this repo and where does the mass sit"; selecting a file outlines everything it touches.

The Wheel view: every file on one ring, dependencies crossing the middle as chords

The Wheel answers the one question the canvas cannot: what talks to what across the whole repo at once. A file whose chords fan across the entire disc is load-bearing whether or not anyone documented it that way. Node dots take the active lens, cluster bands are coloured by directory.

Features

  • Folders that open one level at a time — a folder card holding more files than fits on a screen unfolds into its sub-folders, not into four hundred cards. A src/ that is 90% of the repo therefore has a middle state: it opens into src/app, src/features, src/libs… with the dependencies between them drawn, and each of those opens again. Folding it back remembers how far you had drilled.

  • Lenses — recolour the same layout by Clusters, Activity, Hotspots (churn × complexity), Risk, Tests, Coverage, Instability, Reuse, Unread or Cycles. Whichever is active, a strip under the toolbar explains how to read the colours and shows the matching scale.

  • Everything is discoverable — a VS Code-style File / View / Graph / Go / Help menu bar, a ? cheat sheet listing every click, drag and shortcut for the current view, and a tooltip on every control saying what it does rather than what it is called. What acts on the view — pointer mode bottom-left; centre, fit, zoom and the cheat sheet bottom-right — sits on the canvas corners rather than in a toolbar strip above it.

  • Control panel — the collaboration, in three sections. Tasks is a kanban of work written to be handed to an agent: a card's primary action is Copy for agent, which emits the brief plus the files it names plus what the graph knows about them ("29 files downstream, 0% covered, in an import cycle"), so the agent starts from the map instead of spending half its context rediscovering it. File a card straight from a graph selection with right-click → New task with these files. Lanes are yours — add, rename, reorder or remove them; removing one rehomes its tasks rather than dropping them.

    Design decisions is for the architectural calls an agent makes without being asked — a module boundary, a dependency taken on, a data shape that will spread, a refactor across several files. It records them with decision_record before the code that assumes them and they land as proposed, for you to agree or decline with a reason; an agent cannot agree with its own proposal. Whether it then keeps building on one or leaves the work that rests on it is your call, set in the routine.

    Questions is what it needs from you, parked rather than blocking. Each question names the tasks it holds up, so the rest of the board stays workable; the agent picks up something else and halts only when everything left is waiting on an answer. Answer it in the panel and the agent reads it back over MCP.

    All three are queryable over MCP, so an agent can run its own loop: tasks_list (optionally by lane) to pick up work, task_get for the exact brief a human would have pasted, task_update to log progress and move the card to review, task_create to file follow-up work it finds but shouldn't do now, decision_record, question_ask, and working_agreement when it is unsure whether to keep going. Everything shows up in the panel live.

  • A routine, so it doesn't stop at the first question — the ⚙︎ Routine wizard sets what the assistant does when it runs out of work: check the board again rather than stopping, record design decisions you have not agreed to — and either keep building on them or park the work that rests on them — and park questions instead of halting on them, plus any house rules you type. It renders the working agreement the agent actually reads — generated from the switches, so turning one off removes its rule, and editable, because the switches cover what every project wants and nothing of what yours wants said in its own words. It stores it with the project, where working_agreement returns it along with the state of the board: how many cards are waiting to be picked up, how many are already in progress, how many are blocked, what is waiting on you, and which card to take next.

    That last part is written for more than one agent at a time. A card is only offered if it is still sitting in the first lane — moving it to in-progress is how an agent claims it, and no agent is ever pointed at a card another one has started.

    The last switch is the one that doesn't depend on the agent remembering any of the others: check the board when it tries to stop. Flare answers your assistant's stop hook with the state of the board, so a session that tries to end while a card is still workable is handed that card instead, by name. It adds a Stop hook to .claude/settings.local.json — local to your machine, not committed — and takes it out again when you switch it off. Only ever once per stop, so a session can always end, and never a card someone else has already started.

    Several agents on one board is the case all of this is built for: the panel and every agent write through one place, and a write made against a board that has moved on since is rebased rather than believed — so a click in the panel cannot delete the card an agent filed a second earlier.

  • Channel — a room the agents talk in — several agents on one repo do not collide because they are careless; they collide because nothing tells them what the others are already inside. Each one sees a clean tree, opens the file its task points at, and finds out about the other when you read a diff where two changes have been folded together with no seam.

    Flare cannot lock the file. It watches a filesystem rather than sitting in front of one, so a lock could only be a request an agent is free to ignore — and one that silently fails open is worse than none, because everyone downstream believes it held. What it can do is give them somewhere to talk, and then draw what was said on the map. The Channel tab is that room:

    Claude 2  taking   shared/graph.ts, shared/resolver.ts
                       moving the workspace lookup out of the resolver
    Codex 1   asking   @Claude 2 — is shared/graph.ts free? I need the edge
                       builder for the cycle fix
    Claude 2  done     shared/resolver.ts — all yours
    

    Three habits, and the tool descriptions ask for all three: say what you are taking before you start (chat_post with kind: "taking" and the paths — files or whole folders), read the room when you finish something (chat_read, which hands back only what you missed), and ask by name when you want a file someone has spoken for. You are in the room on the same terms: type into it from the panel and the agents read it back over MCP.

    Nothing is refused. Two agents may both say they are taking the same file — and when they do it is drawn as contention rather than resolved behind their backs, at the top of the tab and as a two-tone mark on the graph, because the two of them settling it is the only thing that actually settles it. An agent that writes a file another agent had spoken for is not blocked either; the crossing lands in the review with both names on it. Everything an agent says lapses on its own, so a session that is killed mid-edit does not hold a folder for the rest of the afternoon.

    It reads as a chat, because it is one: bubbles, consecutive lines from one speaker grouped under one name, your own posts on the right, and each agent carrying a geometric mark — ● ◆ ▲ — assigned with its colour and never apart from it, so the ▲ agent is the same amber one on the card, in the review and in the room. The tool descriptions ask the agents to write prose a colleague could read rather than status codes, and the prose is what the bubble leads with.

    Every line about files also opens. Everything said here is a claim, and Flare is the only participant that watched what followed — so a turn expands into what actually happened to the files it named: which the speaker went on to write and when, which it never touched, and who else wrote one of them afterwards. That last line cannot be got any other way, and the message it crossed is where you are already looking when you want it.

    The tab is also where you find out whether any of it is working. A busy feed is not evidence of coordination, so the header carries the number that is: how many of the files the agents wrote this session had been announced here first, with a button that selects the ones that were not. Beside it, who is in the room, what each said it is taking, and which of them has never once called chat_read — an agent that posts and never listens looks exactly like coordination right up until two of them collide. The transcript filters by agent, by kind and by text, and every path in it is a click to the graph.

  • Claude 1, Claude 2, Codex 1 — the identity everything above rests on. A process list cannot tell two claude sessions apart (both are equally "running" in every sample) and neither can the board (it attributes by path, so an agent editing a file on someone else's card is recorded as them). The MCP session can: it is minted on initialize, echoed back on every request, and impossible for another client to answer to. Flare names each one from the tool it says it is plus the next free number, and that name then follows it everywhere — the ring on a node, the author of a change burst, the parties in a crossing, the row in the roster. Numbers are never reused inside a session, because a "Claude 1" that becomes a different agent halfway through would merge two of them in every sentence that mentions it.

    In the review, that shows up as a chip per agent above the change list — name, files written, how many of its changes nothing has checked — and clicking one narrows the list to that agent's work. One agent leaving all of its changes unverified is a fact about that agent, and it is invisible when its bursts are interleaved with two others' down a scrolling list.

  • Review cockpit — the tab that answers the questions a file-by-file diff can't. Changes are grouped into bursts (one batch of writes by one author), and each burst shows:

    • what actually checked it. The IDE sees both the file writes and the commands run in its terminals, so it can say "the tests ran, then two more files were edited and nothing re-ran" — the states are verified / failed / checked, then edited again / never checked, always quoting the output line the verdict came from.

    • who did it. Not "an agent" — Claude 2, in its own colour, with what it was doing beside the name. With three of them on one repo that is the difference between a list of changes and a list you can act on.

    • what it was trying to do. Agents call the record_intent MCP tool before editing — or say it in the channel, which counts as the same thing; otherwise the burst says so plainly, because reviewing an agent's diff makes you the first human to see that code with nothing explaining why it exists.

    • what the session was about. Everything else in the panel is derived from what Flare watched; this is the one thing it has to be told, because the answer does not exist in any single burst. It exists as a story, and the only participant who knows the story is the agent that lived it — so it is asked for, over MCP, before the session ends. session_summary takes a headline and chapters: a line of prose per piece of work and the files each one covers, and they sit at the top of the review, over the diff they are about.

      Not on trust, though. Flare watched the writes, so it binds every chapter to the bursts underneath it and reports the three ways a story and a session disagree: a chapter naming files that never changed (work described that did not happen — the one kind of wrong you cannot catch from a diff, because there is no diff to catch it in), files that changed and no chapter accounts for, and chapters covering work nothing has verified. That audit goes back to the agent in the tool's reply as well as onto the screen, so the usual outcome is that it fixes its own summary before anyone reads it:

      Your chapters account for 2 of the 3 files you changed.
        "Left the workspace cache alone" names shared/cache.ts, which never
        changed — say what you actually did to it, or drop it.
        Not mentioned anywhere: src/components/ReviewPanel.tsx.
      
    • which files deserve attention. Every file is tiered read carefully / read / skim from blast radius, coverage, cycles and complexity, with the reason spelled out ("9 files break if this is wrong", "no test covers it"), so a 30-file change doesn't get 30 equal glances. The tier is a heading over its group rather than a badge on every row, and on a big change the skim group starts folded.

    • agent smells. Rules for the shortcuts agent changes take and human ones don't: a test edited in the same burst as the code it covers, assertions deleted, .skip/.only added, lint or type suppressions introduced, coverage thresholds lowered, complexity spikes, files left with no importers, abstractions extracted for a single caller.

    • one-click undo. Every burst has a snapshot: revert a file, revert the burst, or jump back to the last state whose checks passed.

    • walkthrough — step the graph through a burst's files worst-risk first, approving as you go.

  • Risky changes come and find you — the review tab is a tab, so a load- bearing file rewritten while you were reading the graph goes unnoticed until you go and look. Those changes queue behind a chip in the top bar instead, beside the review count: a number you can see from across the room, and the cards one click under it, newest first, staying put until answered. Review opens the change on its row in the review panel, Dismiss stops that card, Dismiss all clears the queue. Dismissing an alert is not approving the change — the file stays flagged, unread and exactly as the agent left it.

    It is a chip rather than a floating panel because there is no corner for one. The bottom-right is the terminal, where a card hides the output of the very agent whose change it is reporting on; the top-right is where every tab keeps its own controls, so a panel there sits on + Lane, on Re-layout, on the channel's composer, and swallows the clicks meant for them. A queue that is usually non-empty during an agent session cannot be a panel. The transient toasts keep that corner — they have no controls at all, so the whole stack is click-through and can never eat the next thing you press. The bar is the careful tier plus something absolute (real dependents, a cycle, real complexity, no test at all), so a repo where nothing is load-bearing stays quiet rather than popping a card for its least boring file.

  • Comprehension debt, measured — the Unread lens paints every file that changed this session and no human has opened since; approving does not clear it, opening the file does. Insights shows the repo-level percentage.

  • Every command classified — the command log labels each observed command read / writes / verify / network / destructive, filterable, with the pass/fail verdict next to verification runs. Destructive commands (rm -rf, git reset --hard, push --force, npm publish, …) raise an alert and trigger a snapshot.

  • Coverage ingestion — drop an lcov.info (vitest/jest --coverage, nyc, pytest-cov…) in coverage/ or the project root and it's picked up live: a Coverage lens appears, per-file percentages land in the details panel and hover cards, and real coverage replaces the test-linkage heuristic inside the review-risk score.

  • Drill-downs — collapse any directory into an aggregate meta-node (click its legend chip or double-click the node); expand any file into its functions/classes with symbol-level edges. Shift-click two nodes to highlight the import path between them.

  • Cross-agent tracking — the process tree of every terminal is watched for claude / codex / opencode / aider / …; changes made while an agent runs are attributed to it (coloured node rings, trails on the graph, "changed by" in details), and every shell command run in the terminals lands in the Commands log (▤ button in the terminal bar, persisted per project). That is the terminal half of it — the MCP half, which is what tells two claudes apart and puts a mark on the files each of them is inside, is the room above.

  • Command palette — Ctrl+K: fuzzy-jump to any file, > for commands, recent projects. Ctrl+B sidebar, Ctrl+W close tab, Ctrl+0 fit graph, Ctrl+=/− zoom, Esc collapses focus/drill-down. Full list under > keyboard shortcuts.

  • Insights — a unified metrics + issues view: per-file risk/hotspot/ refactor composites, blast radius, churn (git + session), coverage, TODOs, co-change coupling; severity-ranked rules (regression-risk, god-file, agent-thrash, coverage-gap, cycles, dead code…) with a critical-alert badge and toasts.

  • Reuse — how cleanly each file would come out if you lifted it into a package, 0–100, plus one number for the whole repo. It counts the four things that actually stop you: talking to the host (fs, sockets, a database), being bound to a framework, dragging a large share of the repo along, and sitting in an import cycle. Being widely imported is not a penalty — a util forty files depend on is the most reusable thing you have, which is the opposite of how risk reads the same number. Unlike the other composites it is an absolute scale rather than a ranking within the repo: if everything imports fs, the least-bad file has not become reusable. The mixed-concerns rule points at the files where logic is trapped behind the plumbing and worth separating.

  • MCP server for your agents — one shared, localhost-only endpoint for the whole machine, however many Flare windows are open. Each instance runs a private ephemeral server and registers in a per-pid file registry; whichever instance holds the well-known port (default 7345, FLARE_MCP_PORT) acts as the gateway and routes …/mcp/<slug> — the same stable per-project slug the browser server uses — to the owning instance, proxying when needed and taking over the port when the holder exits. Bare /mcp works with a single session; with several it points the agent at list_projects. Connect agent, in the terminal bar, opens a dialog with the two steps — and they are genuinely two. Registering the server is a config change you make once per machine, and it is different for each of the three: a command for Claude Code, TOML for Codex, JSON for opencode, in different files in different places.

    claude mcp add --transport http flare http://127.0.0.1:7345/mcp/<slug>
    

    The second step is the one that is easy to skip and shouldn't be: the line you open the agent with. Attaching the tools does not make an agent read them, and everything this project expects — taking a card before starting it, saying in the channel which files it is about to edit, writing the session down before it stops — comes back from one call. So the dialog hands you a message to paste, with the endpoint in it, that says to make that call first:

    This project is open in Flare, which is on MCP at http://127.0.0.1:7345/mcp/<slug>.
    
    Start by calling `working_agreement` — it says how this project wants you to
    work, what is on the board, and who else is in here. Then take the card it
    points you at.
    

    It is deliberately short. A paragraph restating the protocol would be a second copy of it, going stale the moment you change the ⚙︎ Routine — and the agent is about to be handed the current version by the tool itself.

    Tools: graph_overview, file_info, dependents, dependencies, find_path, issues, top_files, search, impact_of (what breaks + which tests to run before changing files), recent_activity, verification_status (did my changes actually get checked?), record_intent (state the goal before editing, so the human reviewing the diff isn't reconstructing it), the board tools — tasks_list, task_get, task_update, task_create — the collaboration tools: decision_record, decisions_list, question_ask, questions_list, and working_agreement for what to do next — and the tools for working alongside other agents: chat_post, chat_read and agents_list. The agent asks the IDE about the codebase instead of re-deriving it.

  • Workspace restore — tabs, lens, active view, panel sizes, collapse state, node positions and window bounds all persist per project.

  • Live change tracking — a debounced watcher re-parses changed files and patches the graph in place. Changed-but-unreviewed nodes are marked in warning-orange with a heat decay, so an agent's progress is visible as it works.

  • Review queue — every file changed since your last checkpoint is flagged. Nothing is gated: an agent writes straight to disk, so reviewing is deciding what to keep. Dismiss clears the marker and changes nothing; revert puts the files back. Review next walks them worst-risk first, and each node shows its blast radius (transitive dependents), import counts and symbols.

  • Shadow history ("git of local changes") — a hidden git repo (separate GIT_DIR, your worktree) auto-commits every change burst. Timeline panel lists snapshots; diff any file against any snapshot, revert one file or restore the whole tree. Your real repo is never touched.

  • Git integration — branch + per-file status in the tree and graph, diff vs HEAD in a Monaco diff editor.

  • IDE basics — file tree, Monaco editor (VS Code's editor) with Ctrl+S save and external-change reload, multiple terminals (xterm.js + node-pty) running real shells.

  • Light and darkView ▸ Theme, following your desktop unless you pin one. A theme is a single block of tokens in src/styles.css: the neutral ramp runs surface→ink rather than dark→light, so the ~460 places the stylesheet names a step do not change when a theme is added. The three things that draw outside CSS — the graph, the editor and the terminal — read those same tokens rather than carrying palettes of their own, and tests/palette.test.ts holds the line: colours only inside a palette, none in the roles, and every theme declaring the same tokens so a half-written one fails loudly instead of rendering with holes in it.

Testing

npm test          # 633 vitest unit tests (parser, resolver, graph, scanner, git, shadow, store, reuse, roster, channel)
npm run e2e       # 80 Playwright tests: 56 driving the real Electron app, 24 driving a browser
npm run verify    # build + unit + e2e

Architecture

One implementation, two transports. electron/core.ts is all of Flare's behaviour with no window and no Electron: a map of channels to handlers, and an onEvent callback. The desktop main process and the browser server are adapters that only translate — neither names a channel, so a feature added to the core reaches both without a second edit. tests/singleSource.test.ts enforces that, and it is why serving Flare to a browser did not fork the codebase.

  • shared/ — pure engine: import parser (comment/string-safe lexer + regex), module resolver, incremental graph builder with patch diffing, project scanner. No Electron dependencies; fully unit-tested.
  • electron/core.ts — the backend: project session (scan → graph → watcher → events), git service, shadow-history service, PTY service, agent monitor, MCP server, persisted per-project store (node positions, review state). Plain Node. The desktop-only bits — folder picker, OS clipboard, window buttons — are injected as an optional CoreHost.
  • electron/main.ts + preload.ts — the desktop adapter: a window, its remembered bounds, the macOS menu, and a generic contextBridge bridge.
  • server/ — the browser adapter: serves the built dist/ and carries the same calls and events over one websocket, riding on the ports the MCP server already owns so one instance needs exactly one port. A supervisor holds the port and serves the start screen; each project it is asked for becomes a session process of its own at /<slug>/. Everything it serves, websocket included, is behind the token in server/auth.ts.
  • src/api.ts — the typed client both transports share; the only line that differs between desktop and browser is which transport it is handed.
  • src/ — React renderer: the three graph views (CanvasView, WheelView, DistrictsView) over a shared render model and lens palette, Monaco editor/diff, xterm terminals, file tree, details panel, timeline, review banner.

Node ↔ renderer flow: chokidar batch → re-parse → graph diff → evt:graphPatch → graph patch + heat, plus debounced git status refresh and shadow snapshot.

Run it

Requires Node 20 or newer.

npm install
npm run build     # bundle main process (esbuild) + renderer (vite)
npm start         # launch the desktop app

Install it (Windows / macOS / Linux)

Built releases are on the releases page:

PlatformDownloadNotes
WindowsFlare-<version>-Windows-x64.exeNSIS installer, per-user, choose your own directory. A .zip is there too if you would rather not install anything.
macOS, Apple siliconFlare-<version>-macOS-arm64-beta.dmgBeta — see below.
macOS, IntelFlare-<version>-macOS-x64-beta.dmgBeta — see below.
LinuxFlare-<version>-Linux-x86_64.AppImagechmod +x and run. A .deb and a .tar.gz are published too.

The macOS packages still say beta in their filename, but for a narrower reason than they used to.

They have now run on a Mac. The full suite — 544 unit tests and 78 end-to-end tests, Electron and browser — passes on macOS 14, and the packaged .app is booted out of its own DMG and checked for a working terminal before a release goes out, the same bar Windows and Linux are held to. What is not covered is Apple silicon specifically: the hardware behind this project is Intel, so the arm64 package is built and signed but has never been launched. That is what the beta label is now for.

They are also ad-hoc signed and un-notarised. Notarising needs a paid Apple Developer account, so Gatekeeper will still refuse the first launch — the signature is there to satisfy the loader, not Gatekeeper. Open it once with right-click → Open, or clear the quarantine flag:

xattr -dr com.apple.quarantine /Applications/Flare.app

To build one yourself:

npm run dist      # installer for the platform you are on, into release/
npm run dist:dir  # unpacked, for a quick look

Run it on the platform you are building for. Flare's terminal is a native module that ships as a prebuilt binary per platform and architecture, and npm installs only the one for the machine doing the installing — so a Linux package built on Windows contains the Windows binary and opens no terminal at all. That is what the release workflow's one-runner-per-platform matrix is for (.github/workflows/release.yml); tag a version and it builds all four:

npm version 0.2.0 && git push --follow-tags

It uploads to a draft release, so nothing is public until the artifacts are all there and someone has looked at them. The title bar is platform-aware: custom controls on Windows/Linux, native inset traffic lights on macOS.

On Windows, WSL2 is enough to test the Linux build properly: WSLg supplies a display, so the desktop suite runs against real Electron and the AppImage actually boots. Work inside the WSL filesystem rather than /mnt/cnpm ci against the Windows tree from Linux replaces node_modules with Linux binaries and breaks the Windows checkout.

cp -r /mnt/c/path/to/Flare ~/flare && cd ~/flare && npm ci
npx playwright install chromium
npm test && npx playwright test            # 633 unit + 80 e2e, on Linux
npx electron-builder --linux --publish never

Development mode (hot reload for the renderer):

npm run dev

Flare opens to a start screen listing your recent projects — arrow keys and Enter, or Ctrl+O to pick a new folder. The last project you had open is the first row, so restoring it is one keystroke rather than an assumption. FLARE_PROJECT=<path> skips the start screen and opens that project directly.

Run it in a browser (any remote machine)

Flare's review cockpit works by watching the process tree under its own terminals, so the backend has to run on the machine the agent runs on. When that is not your laptop — a VM, a dev container, a build box, a cloud workstation, anything you reach over SSH or a forwarded port — serve it instead of installing it:

npm install
npm run serve                          # or `npm run serve -- /path/to/project`
Flare — http://127.0.0.1:7345/?token=oq_F45fBJGdMTK4NJdm6y53n7-lHezBd
  the token is asked for once per browser — ~/.flare/web-token
  open it to pick a project — each one gets its own url

The port is the start screen. Open it and you get Flare's own start screen — the same one the desktop app opens to, laid out the same way: the projects you have opened before, and a folder browser that walks the filesystem on that machine (the desktop keeps the system dialog as well, on Ctrl+O). Pick one and it starts a session for it and takes you to its URL:

http://127.0.0.1:7345/api/

From there it is the same IDE: the graph, the editor, the review cockpit, and a real terminal on the remote machine.

The terminal does not wait for the round trip. A shell on another machine echoes what you type one network hop later, and at 80ms that is a terminal that feels underwater. Every key still goes out the moment it is pressed — Tab completion, history search and whatever agent is running in there all need the raw stream — but the character is drawn locally first and the shell's echo is treated as confirmation, the way mosh does it: only at a visible cursor on the main screen, undone before any output is applied so nothing can double, and switched off by itself for anything that does not echo (a password prompt, a full-screen program). It measures the echo delay as it goes and does nothing while the delay is short, so the desktop window behaves exactly as before. Underneath, keystrokes travel as one-way frames nobody acknowledges, terminal output is batched per event-loop turn instead of per pty read, and the socket a session's tab is proxied over runs with Nagle's algorithm off.

One port, many projects. The url is the folder name — /api/, not /api-3f21b8/. It is assigned once and remembered, so it stays the same across restarts and reboots; two projects sharing a folder name get qualified by their parent (/side-api/) rather than by a hash. Each project runs as its own process with its own terminals and its own agents, so several can stay open in several tabs without touching each other. Whichever process holds the port routes to the others; when it exits another takes over and every URL keeps working. Agents connect over that same port at /mcp/<slug>, so a restricted machine only ever has to expose one.

Getting to the port. Flare listens on 127.0.0.1 by default and tells you so — a loopback URL is useless from the laptop you are actually sitting at, so it prints the machine's real addresses too and says what to do about them:

Flare — http://127.0.0.1:7345/?token=oq_F45fBJGdMTK4NJdm6y53n7-lHezBd
  reachable from this machine only. From your laptop, either
    ssh -L 7345:127.0.0.1:7345 you@workbench
    or restart with --host 0.0.0.0 for http://10.128.0.7:7345/?token=…

A tunnel or your cloud IDE's port forwarding exposes nothing and works anywhere. Flare's asset and websocket URLs are page-relative, so it also runs unmodified behind a path prefix — jupyter-server-proxy's /proxy/7345/, a VS Code tunnel, an nginx location block — with no configuration.

The token. Behind this port are your files, your history and a live shell, so the browser side asks for a token — the one in the URL above. It is generated on first run and kept in ~/.flare/web-token, so the printed URL keeps working across restarts; --token <value> or $FLARE_TOKEN sets your own. Opening a URL that carries it stores a cookie, so it is asked for once per browser and never appears in an address bar again; a URL without one gets a box to paste it into. Scripts can send it as Authorization: Bearer or X-Flare-Token. --no-token (or $FLARE_NO_TOKEN=1) turns the whole thing off, for a tunnel you trust or a proxy that already authenticates.

Agents are outside it: /mcp/<slug> stays open, because a token there would break every claude mcp add line already written into a config file. It is loopback-only unless you widen the host.

--host 0.0.0.0 (or $FLARE_HOST) listens on every interface and prints the URLs that will answer, hostname first. Do this only on a network you trust: the token is the only thing in front of a filesystem and a shell, and the MCP endpoint moves with it. The per-instance private ports stay on loopback either way; only the shared one moves.

The URL of the machine, whatever shape it takes. Every hosted environment addresses a forwarded port differently, and none of those addresses appear in the VM's own interfaces — so Flare derives the shape from the environment rather than assuming one:

where it runsthe URL it prints
your PC, a bare VMits hostname and real addresses
GitHub Codespaceshttps://<codespace>-7345.app.github.dev/
Gitpodhttps://7345-<workspace>.gitpod.io/
JupyterHub, jupyter-server-proxyhttps://<hub>/user/<you>/proxy/7345/

Project slugs are appended to whichever it found, so the printed URL is the one you can actually paste:

Flare — https://hub.example.com/user/malte/proxy/7345/
  api → https://hub.example.com/user/malte/proxy/7345/api/

Anything else behind a proxy Flare cannot see takes --public-url (or $FLARE_PUBLIC_URL, which sessions inherit). A bare host gets the port appended; a value that already carries a port, a path prefix, or https is used exactly as given.

State lives in ~/.flare ($FLARE_USERDATA to move it), the token included; --port or $FLARE_PORT changes the shared port.

The terminal's PTY module is the only native dependency; everything else is pure JS, so on an unfamiliar machine that is the one thing worth checking:

node -e "require('@lydell/node-pty')"   # silence means the terminal will work

This is not a second app: it is the same dist/ bundle and the same backend as the desktop build, reached over a websocket instead of Electron IPC — see Architecture.

License

MIT — see LICENSE.

Files in the repo

Repository payload21 top-level entries
  • .github
  • build
  • docs
  • e2e
  • electron
  • public
  • scripts
  • server
  • shared
  • src
  • tests
  • .gitignore
  • index.html
  • LICENSE
  • package-lock.json
  • package.json
  • playwright.config.ts
  • README.md
  • tsconfig.json
  • vite.config.ts
  • vitest.config.ts

Discussion (0)

Ask about usage, or say what you built with it

Sign in to join the discussion.

No comments yet. Be the first to say what this is good for.

More connectors

High-performance code intelligence MCP server. Indexes codebases into a persistent knowledge graph — average repo in milliseconds. 158 languages, sub-ms queries, 99% fewer tokens. Single static binary, zero dependencies.

43k

Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code

14k
okf-memory/
okf-agent-memory

Git-native persistent memory for AI coding agents. Implements Google OKF v0.2 with sub-300µs in-memory BM25 search, embedded MCP server, and progressive disclosure. Slashes token bloat by 80% with zero external databases or dependencies. Built in pure Go.

547
tirth8205/
code-review-graph

Local-first code intelligence graph for MCP and CLI. Builds a persistent map of your codebase so AI coding tools read only what matters, with benchmarked context reductions on reviews and large-repo workflows.

31k
2akouwu/
reverify

Stop your AI from making things up — it proposes, deterministic tools decide, every claim checked against ground truth with evidence. Grounded facts and context survive resets. Reverse engineering is the proving ground. MCP server + CLI.

1.1k
t8y2/dbxConnectors

20 MB lightweight cross-platform database client for 90+ databases, including MySQL, PostgreSQL, SQLite, Redis, MongoDB, DuckDB, SQL Server, and Dameng. Built-in AI, MCP Server, CLI, desktop and Docker. | 轻量级跨平台数据库管理工具,支持 MySQL、PostgreSQL、SQLite、Redis、MongoDB、达梦等 90+ 数据库,提供桌面端、Docker、CLI、内置 AI 助手和 MCP Server。

19k