What we shipped recently
A running log of Stackon’s evolution. Every meaningful change lands here.
- v0.99.53Shipped
Meet Jarvis — Stackon Space gets a voice
- Stackon Space opens onto something new: Simple mode, a voice-first stage with a single breathing Stackon mark. Talk to it — or type — and Jarvis does the rest: creates projects, dispatches real, traced Claude Code agents, watches your pull requests, and reports back out loud. Speech recognition runs fully on your machine (local Whisper), and the full workspace — now Advanced mode — stays one toggle away, exactly as you left it.
- Agents that finish stay open, so a follow-up continues the same session with everything it already knows. Whatever needs you finds you: a chime sounds when an agent finishes or blocks, permission prompts land as approve / deny cards on the stage, consequential actions like merging a PR wait for your spoken yes, and steps only you can do appear as a “Waiting on you” checklist under the task’s card. Every task opens into a live, timestamped feed of its agent’s updates. Update from /download.
- v0.99.52Shipped
GitHub, woven into Stackon Space
- Stackon Space now keeps GitHub in your peripheral vision instead of behind a door. A new status chip in the footer always shows your current branch, its open pull request, and a live check-status dot — and one click takes you exactly where that state points: the PR itself, a pre-filled Create PR form for a branch that doesn’t have one yet, or a guided connect checklist if GitHub isn’t set up. Agent-lane cards show their branch’s PR and checks at a glance, too.
- The GitHub button in the header opens a redesigned, roomier GitHub home: your open PRs with checks and review state beside a repo status card, with PR detail, reviews, and merging one click deep. Behind it all, Space now watches your branch and PR status continuously — refreshing when you return to the window, polling while checks are pending, and updating the moment you merge. Update from /download.
- v0.99.51Shipped
Live Preview — see your app inside Stackon Space
- Stackon Space gains a Preview pane: a toggleable rail that renders the web app you’re building, live, right beside your terminals and editor. Start your dev server in a terminal tab and Space detects it — reading your
package.jsonscripts and probing the usual ports — then attaches with one click. Every hot reload your agents trigger shows up instantly. - The pane knows when your server stops (the frame dims with a rescan prompt), remembers the last URL per workspace, and includes Phone / Tablet / Full width presets for quick responsive checks. Toggle it from the footer, the View menu, or the command palette. Update from /download.
- Stackon Space gains a Preview pane: a toggleable rail that renders the web app you’re building, live, right beside your terminals and editor. Start your dev server in a terminal tab and Space detects it — reading your
- v0.99.50Shipped
The full PR conversation, inside Stackon Space
- Stackon Space pull requests now have a Conversation tab alongside Files changed. It’s the whole story of the PR in chronological order — when it was opened, every comment, each review with its verdict, the commits as they were pushed, force-pushes, and the final merge or close.
- You can join the discussion without leaving the app: a composer at the bottom of the timeline posts general PR comments straight through your own GitHub credentials, right next to the inline code review tools that already live in the diff view. Update from /download.
- v0.99.49Shipped
Stackon Space sessions, captured as real traces
- Stackon Space — our native desktop workspace — now records every traced terminal session as a complete Trace: real token cost, the model used, and the agent’s actual reply text for each turn. Open the trace in the web viewer and it updates live as the session runs.
- Interactive prompts are captured faithfully too. When an agent asks you to choose from a menu, the trace shows the question and your selection, and splits the work and cost from before and after your answer into clean, separate turns — and each session closes with a clear End marker. Update from /download.
- v0.99.48Shipped
Open pull requests from Stackon Space
- Stackon Space — our native desktop workspace — can now connect to GitHub and drive your pull requests without leaving the app. A single GitHub button in the header opens everything: connect with the GitHub CLI, see your repo’s open PRs with live check status and review state, and merge or close them in place.
- It’s built for the way agents work. Spin up an agent lane (an isolated branch and worktree), let an agent commit to it, then open a pull request straight from that lane — the branch is pushed and the PR drafted with the title pre-filled from your last commit. Sign-in uses your own
ghcredentials, and lane branches are kept after a merge by default so your parallel work stays intact. Update from /download.
- v0.99.47Shipped
Stackon Space for Windows — signed, direct download
- Stackon Space, our native desktop workspace, is now available for Windows as a direct download — head to /download. It’s the full Stackon ADE in a native window: real terminals, a Monaco editor, your missions and agents, and every session captured as a trace.
- The installer is code-signed (Azure Trusted Signing), so Windows SmartScreen recognizes it instead of warning about an unknown publisher. An .msi is also available for IT and group-policy deployment. The macOS build is next.
- v0.99.46Shipped
User Settings — your profile and two-factor auth
- The account menu’s Settings link now opens a real User Settings page (it used to drop you on Team Members). Set your first and last name, phone, and title in one place — your display name stays in sync automatically. Your account email is shown read-only.
- You can now add two-factor authentication: pair an authenticator app (1Password, Authy, Google Authenticator…) by scanning a QR code and confirming a 6-digit code, and remove it just as easily. This is the setup half — enforcing the second factor at sign-in is a follow-on update.
- v0.99.45Fix
The dashboard sweep wraps up — plus a clickable audit history
- Brought the last set of surfaces onto the same instrument-panel look as the rest of the dashboard — the Overview, Approvals, Cost, Compliance, and Forge, plus the Compute, Team, Billing, API tokens, and Devices pages. Every action across them now confirms with the same non-disruptive notice from the top of the screen, so the whole signed-in dashboard finally reads as one consistent instrument.
- A few targeted improvements rode along: the audit log on Compliance is now clickable — each row drills straight into the trace, run, or resource it records; the 30-day spend graph on Cost and the Overview reads in white; audit retention is capped at a clean 7–365 days; and the Billing plan comparison is tidied up with centered columns and corrected copy.
- v0.99.44Fix
A cleaner, more consistent Webhooks — and the dashboard is uniform throughout
- Brought the Outgoing webhooks settings onto the same instrument-panel look as the rest of the dashboard — the create form, the endpoints table, and each webhook’s detail (events, signing secret, and the delivery log). Creating, testing, retrying, enabling, disabling, or deleting a webhook now confirms with the same non-disruptive notice from the top of the screen as the rest of the dashboard. This is the last area in a sweep that brought every dashboard surface onto one consistent look.
- v0.99.43Fix
A cleaner, more consistent Scribe
- Brought the Scribe area onto the same instrument-panel look as the rest of the dashboard — the skills list, the Distill a skill form, and each skill’s detail. Distilling, saving, or deleting a skill now confirms with the same non-disruptive notice from the top of the screen as the rest of the dashboard.
- v0.99.42Fix
Confirmation notices no longer replay on back-navigation
- Fixed a glitch where a “created / saved / deleted” confirmation notice would pop again when you left a page and navigated back to it — even though you hadn’t repeated the action. The notice now clears itself from the page’s history entry the moment it shows, so returning never replays it; repeating an action still confirms each time.
- v0.99.41Fix
A cleaner, more consistent Adversary
- Brought the Adversary area onto the same instrument-panel look as the rest of the dashboard — the campaign list, the New Campaign form, and each campaign’s detail. The threat-posture headline now reads as a status dot + label, and running a campaign, re-running one, or deleting one confirms with the same non-disruptive notice from the top of the screen as the rest of the dashboard.
- v0.99.40Fix
A cleaner Knowledge area — and toasts that confirm what you did
- Brought the Knowledge area onto the same instrument-panel look as the rest of the dashboard — the corpus, the New Source form, and each source’s detail. We also unified action feedback across the whole dashboard: creating a mission, canvas, agent, eval, gate, or knowledge source — and ingesting or deleting a source — now pops the same non-disruptive confirmation from the top of the screen, so an action never leaves you guessing whether it landed.
- v0.99.39Fix
A cleaner, more consistent Agents
- Brought the Agents area onto the same instrument-panel look as the rest of the dashboard — the roster, the New Agent and agent-edit forms, and the one-shot Quick run. Creating, updating, archiving, or restoring an agent now confirms with a non-disruptive notice from the top of the screen instead of an inline banner that shifts the page.
- v0.99.38Fix
A cleaner, more consistent Canvas
- Brought the whole Canvas area onto the same instrument-panel look as Traces, Evals & Missions — the pipeline list, the New Canvas form (its starter-template roles now read in their own colors), the canvas editor, node editing, and the full version history (snapshots + diffs). The editor’s configuration — Team Knowledge, Approval Gate, Commit, and Publish to Forge — now sits under one collapsible Canvas settings panel, so the page leads with the pipeline and the run. And every canvas action — adding, moving, or removing a node, toggling knowledge or approvals, committing, publishing, posting a comment, or deleting the canvas — now confirms with a non-disruptive notice from the top of the screen instead of shifting the page.
- v0.99.37Fix
Header menus hold the page still
- Opening a header menu — Product, Community, Company, or the mobile menu — now freezes the page behind it until you close it, so the page no longer scrolls away under an open dropdown. The lock compensates for the scrollbar width, so nothing shifts when a menu opens.
- v0.99.36Fix
A cleaner, more consistent Missions
- Brought the Missions board, the mission thread, and the New Mission form onto the same instrument-panel look as Traces & Evals. Each agent reply in a thread is now a tidy collapsible row — with In / Out / Cost and an Open Trace button; lane and mission status read as a colored dot + plain label; and action feedback (approvals, run errors) now arrives as a non-disruptive notice from the top of the screen instead of shifting the page.
- v0.99.35Fix
A consistent Kind label across Evals
- The Kind column in the Evals list now matches the eval detail view — a kind-colored dot with a plain white label instead of colored text — so the two read the same at a glance.
- v0.99.34Fix
A cleaner New Eval form and PR-blocking gates
- Continued the dashboard consistency pass through the rest of the Evals area. The New Eval form now shows only the configuration for the grader you pick — an output-contains string check or an LLM judge rubric — rather than both at once, and eval kinds read consistently as Output Contains / LLM Judge throughout. The PR-blocking gates list and detail now match the same instrument-panel look, and the copy-paste CI workflow references a
STACKON_API_TOKENsecret.
- Continued the dashboard consistency pass through the rest of the Evals area. The New Eval form now shows only the configuration for the grader you pick — an output-contains string check or an LLM judge rubric — rather than both at once, and eval kinds read consistently as Output Contains / LLM Judge throughout. The PR-blocking gates list and detail now match the same instrument-panel look, and the copy-paste CI workflow references a
- v0.99.33Fix
A cleaner, more consistent Traces & Evals
- Refined the Traces and Evals dashboards onto one consistent instrument-panel look — decluttered headers, run status as a colored dot + plain label (green completed / amber running / red failed), boxed metrics, and a single click-to-expand span timeline & details on every trace. The first wave of a dashboard-wide consistency pass.
- v0.99.32Fix
Stop a mission run — and no more runs stuck “in progress”
- Two fixes for runaway runs: a live mission now shows a Stop run button that ends it and unsticks the board immediately, and any run abandoned by an interrupted background task is automatically marked failed after 10 minutes (with a note in the thread) instead of spinning “in progress” forever.
- v0.99.31Fix
A clear path when a mission isn’t ready to run
- A mission runs a bound canvas of agents, so it needs one with at least one agent before it can start. Instead of a silently disabled composer, you now get a Setup needed panel that names exactly what’s missing and fixes it in one step — attach an existing canvas from a dropdown, build a new one, or jump to the bound canvas to add agents.
- v0.99.30Fix
Opening a trace the instant a run starts
- Clicking Open trace in the first moment of a live run used to hit a “not found” page — the trace was still being written. It now shows a brief Initializing run state that resolves into the real trace the instant it begins streaming, so the link always lands somewhere useful.
- v0.99.29Fix
Signing in without an account now points you the right way
- v0.99.28Fix
A more focused dashboard overview
- Removed the redundant “Jump to” shortcut row from the dashboard overview — the left sidebar (and
⌘K) already cover navigation, so the overview now stays on your live signal: spend, runs, eval health, and what needs you.
- Removed the redundant “Jump to” shortcut row from the dashboard overview — the left sidebar (and
- v0.99.27Fix
Dashboard chrome, tuned to the brand
- The dashboard now sits on the same black-and-smoke palette as the rest of stackon.ai — the faint green cast behind the workspace is gone — and the top-bar breadcrumb (Stackon / <page>) now shares the brand display typeface with the page title, so the chrome reads as one consistent surface.
- v0.99.26Infra
A reproducible database, from scratch
- Behind the scenes: Stackon’s entire database schema now lives in version-controlled migrations and is verified byte-for-byte identical to production — so a clean environment can be stood up from nothing. Reliability groundwork for staging and self-hosting; no change to the product itself.
- v0.99.25Fix
Canvas leads the workspace
- The dashboard’s Workspace nav now opens with Canvas — the first step when you start a project — ahead of Missions, matching the natural build order.
- v0.99.23Shipped
Your sign-in link now tells you when it lands
- When you request a magic link, the sign-in confirmation now updates the moment your email is actually delivered — the “in flight” signal settles into a Delivered receipt (or flags a bounce) in real time, so you’re never left wondering whether it’s on the way. Built on real delivery events, not a timer.
- v0.99.21Fix
A more polished sign-in
- After you request a magic link, the confirmation on the sign-in screen is now a refined smoke-glass panel in the same telemetry style as the dashboard — replacing the old green box. A subtle “in flight” signal traces toward its destination, so it’s clear at a glance that your link is on its way.
- v0.99.20Fix
Fixed: dashboard search & command palette
- The top-right search and the command palette now open correctly — clicking search previously threw an error. The shortcut hint is also OS-aware now:
⌘Kon macOS,Ctrl Kon Windows and Linux.
- The top-right search and the command palette now open correctly — clicking search previously threw an error. The shortcut hint is also OS-aware now:
- v0.99.19Fix
A more cohesive dashboard typeface
- Dashboard headings and key metrics now use Stackon’s display typeface — the same one across stackon.ai — so the workspace and the marketing site read as one product. A small follow-on to the dashboard redesign.
- v0.99.18Shipped
A redesigned dashboard — and navigation that finally fits
- Navigation moved off the cramped top bar into a collapsible left sidebar, grouped the way you actually work — Workspace, Observability, Extend, and Settings. It sits as a slim icon rail by default, expands on hover, and pins open when you want it to stay. Search (
⌘K) and your account moved to a clean top bar. - Every screen — Traces, Cost, Evals, Missions, Canvas, Agents, Adversary and the rest — was rebuilt into one cohesive mission-control look: telemetry-style readouts, live status signals, and corner-framed panels, all in the same black-and-smoke palette. Same data and actions, a far sharper surface.
- Navigation moved off the cramped top bar into a collapsible left sidebar, grouped the way you actually work — Workspace, Observability, Extend, and Settings. It sits as a slim icon rail by default, expands on hover, and pins open when you want it to stay. Search (
- v0.99.17Fix
Model Updates moves to /model-updates
- The model-release feed now lives at /model-updates — a URL that finally matches what the page is. The old
/blogaddress permanently redirects there, so every existing link and bookmark keeps working.
- The model-release feed now lives at /model-updates — a URL that finally matches what the page is. The old
- v0.99.16Shipped
Redesigned product pages — and Stackon Space joins the lineup
- Every product now has a polished, public page — Trace, Evals, Cost, Canvas, Missions, Bridge, the MCP server and the rest — each with a hero, a live visual of the actual product, deep-dive sections, and cross-links to the rest of the platform. Browse them from the Product menu or the /product hub — no sign-in required.
- New on the lineup: Stackon Space, the native desktop workspace — real terminals, a code editor, your missions, and your agent roster in one window, where every Claude Code session you spawn lands back in Stackon as a replayable trace. See the page; Mac & Windows builds are coming to /download.
- v0.99.15Shipped
Stackon MCP & Bridge are now on npm
- The Stackon MCP server and Bridge daemon are now published packages — install them in one line with
npm i @stackon/mcpornpm i @stackon/bridge. - Stackon MCP connects your workspace to Claude Code, Cursor, Windsurf, Codex, or Zed, so every agent run emits a Trace span and you can run evals straight from your editor. Bridge points agents at your own compute — your laptop, a GPU box, or your VPC — with nothing leaving your infrastructure.
- Every install snippet across the site and docs now resolves to a real package.
- The Stackon MCP server and Bridge daemon are now published packages — install them in one line with
- v0.99.14Shipped
A clearer site — public product pages + a sharper home
- Every part of the platform now has its own public page — Trace, Evals, Cost, Canvas, Missions, Bridge, the MCP server and more, browsable from the new Product menu and the /product hub. No sign-in required to see what each one does.
- The home page leads with what Stackon actually is — “Run AI agents on your codebase, and prove they got better” — plus an “up and running in 60 seconds” walkthrough (create a token, add the MCP server, watch it land in Trace).
- And it’s self-serve: start free from anywhere, no waitlist. Cleaner nav and footer to match.
- v0.99.13Shipped
Dashboard — an analytical home screen
- The dashboard home is now a real command center instead of a grid of links. At a glance: this month’s spend (against your budget), runs today, your 30-day eval pass-rate, and failed runs in the last week.
- Below the numbers, a 30-day spend trend, your most recent traces, what’s awaiting approval, and your active missions — each linking straight to the detail. A brand-new workspace gets a guided “get your first trace flowing” panel instead of an empty screen.
- v0.99.12Shipped
Blog — now sourced directly from the model labs
- The Blog is now a first-party feed: every update comes straight from the AI labs’ own sites — Anthropic (Claude), OpenAI (ChatGPT), Google (Gemini), xAI (Grok), Meta (Llama), Mistral, and DeepSeek — with no news aggregators or third-party rewrites in the mix.
- OpenAI and Google publish proper feeds; for the labs that don’t, we read their official release-notes / news pages directly. Corporate noise (funding, hiring, office openings) is filtered out so the feed stays focused on model launches and updates, newest first.
- v0.99.11Shipped
A more modern typographic voice
- Refreshed the typeface behind every headline across the site — from the landing page’s “Ship faster. With receipts.” to section titles like “Four products. One workflow.” — swapping the previous editorial serif for Hanken Grotesk, a contemporary grotesque that reads cleaner and more technical next to the product.
- It’s a single design-token change under the hood, so the new voice is consistent everywhere headlines appear, and the page stays fast (the above-the-fold headline font is still preloaded).
- v0.99.10Fix
Blog — cleaner, more readable cards
- Tidied up the Blog feed. News items pulled from Google News were showing raw link markup in their summary (a long redirect URL bled across the card) — now each card shows a clean headline with the original publisher (e.g. “via Yahoo Finance”) and links straight to the source.
- The cards themselves got a polish pass: equal heights in a tighter grid, titles and excerpts that clamp cleanly instead of overflowing, a subtle staggered reveal, and source filters that no longer show empty
0categories.
- v0.99.9Shipped
Billing — manage your subscription in Settings
- Settings → Billing is now a real page: see your current plan, how many seats you’re using against the plan’s limit, and an estimated monthly cost — with a side-by-side plan comparison and one-click upgrade.
- This is the subscription surface (plan, seats, payment method, invoices) — distinct from the Cost dashboard, which tracks your token spend. Each page links to the other so it’s always clear which dollars you’re looking at.
- Payment method and invoice management open in a secure Stripe billing portal when billing is configured; until paid plans are switched on, the page shows an honest “nothing to bill yet” state rather than an empty placeholder. Plan and payment changes are limited to workspace owners and admins.
- v0.99.8Shipped
Blog — a live feed of AI-engineering news
- The Blog is live — a real-time digest of what’s happening across Claude (Anthropic), Codex (OpenAI), and the broader AI-engineering world, pulled automatically from the source.
- It aggregates a curated set of official and topic feeds — OpenAI, Hugging Face, Google DeepMind, Simon Willison, Latent Space, and live Anthropic/Codex coverage — into one clean, filterable grid of headlines and short excerpts, with every card linking straight to the original.
- The page refreshes itself on a timer (no manual updates, no database), and each source is fetched independently — so if one feed is briefly unreachable, the rest of the page is unaffected and it reappears on the next refresh.
- v0.99.7Shipped
Stackon Space — sessions now record real cost, tokens & a readable transcript
- Every Claude Code session you launch from Stackon Space already becomes a replayable trace — now those traces carry real dollar cost and token counts instead of zeros. When a traced session ends, Stackon Space reads Claude Code’s own session transcript and backfills the trace with input/output tokens, cache usage, the model used, and a computed cost.
- The trace’s Outputs now show a clean conversation — the actual user prompts and model replies (with compact
[tool: …]markers) — instead of raw terminal redraw noise, rendered in the same readable view as Inputs and Attributes with a one-click JSON toggle. - Each turn is now its own span built from the transcript — with the prompt, the assistant’s clean reply, and its own cost, tokens, and duration — so you can see exactly what each step did and what it cost (replacing the old keystroke-guessed turns that captured terminal spinner noise).
- This makes the desktop’s session→trace bridge actually answer the question Trace exists for — what did this run cost, and what happened? — so spend shows up in the trace list, the trace detail, and the Cost dashboard like any other run.
- Under the hood we pin a session id at launch (
--session-id) so each trace maps deterministically to its transcript, and cost is computed from the same per-model pricing table the web runner uses (cache reads/writes priced correctly, not as full-price input).
- v0.99.6Shipped
Stackon Space — find in the terminal (Ctrl/⌘+F)
- The Terminal pane now has a find bar: press Ctrl/⌘+F with a terminal focused to search the scrollback, with match-case, whole-word, and regex toggles and a live match counter.
- Enter / Shift+Enter jump between matches and Esc closes the bar; matches highlight in the brand emerald as you type. When the editor pane is focused, Ctrl/⌘+F still reaches Monaco’s own find — the shortcut is only claimed for the active terminal cell.
- v0.99.5Shipped
Trace — readable span detail, with a raw-JSON toggle
- A trace’s Inputs, Outputs, and Attributes now render in a human-readable view by default instead of raw JSON — user messages and model output read as plain text (real line breaks, no escaped
\nor wrapper braces), chat transcripts render as a conversation, and attribute objects render as a tidy key/value list. - Every box keeps a Readable / JSON toggle in its header, so the exact raw payload is always one click away — nothing is hidden, just easier to read.
- The span list also previews each turn’s user input inline, so you can scan what every step was about without expanding it.
- A trace’s Inputs, Outputs, and Attributes now render in a human-readable view by default instead of raw JSON — user messages and model output read as plain text (real line breaks, no escaped
- v0.99.4Shipped
Stackon Space — fuzzy-match highlighting in Quick Open + Command Palette
- Quick Open (Ctrl/⌘+P) and the Command Palette (Ctrl/⌘+Shift+P) now highlight the characters that matched your query — so you can see at a glance why each result ranked where it did, the same way VS Code does it.
- The two overlays shared a near-identical fuzzy scorer; that logic now lives in one place and additionally reports which characters matched, so the highlight comes for free with no change to ranking.
- v0.99.3Fix
Stackon Space — smooth terminal resizing
- Fixed the terminal jittering / flickering at certain pane sizes while dragging a splitter (most visible maxing the terminal against the Tasks pane). At boundary heights the terminal’s scrollbar rapidly appeared and disappeared, which nudged the column count and reflowed the text, re-triggering itself — a fast feedback loop.
- The fix reserves a stable scrollbar gutter so the bar’s appearance can’t change the usable width, only re-fits when the pane’s actual pixel size changes (one fit per frame), and clips transient overflow — so dragging stays smooth.
- v0.99.2Infra
Stackon Space — close from the rail + a prompt when nothing's open
- The × next to the open workspace in the rail now closes it (editor + terminals together), not just removes it from the recent list. The × on a workspace that isn’t open still just forgets it from recents.
- When no workspace is open, both the Terminal and Editor panes now show a prompt to New Workspace or Open folder… instead of a stray home-directory shell — terminals are workspace-scoped, so you start one by opening a workspace.
- v0.99.1Fix
Stackon Space — closing a workspace closes its terminals
- Closing a workspace now closes the editor and that workspace’s terminals together. Before, the terminals stayed running in the background after the workspace was closed; now they’re shut down with it (the PTYs are killed), and reopening the workspace starts fresh. Switching between workspaces still keeps each one’s terminals alive — only an explicit close tears them down.
- v0.99.0Shipped
Stackon Space — workspace presets (one-click launch)
- Save a workspace setup once, relaunch it in a click. In the New Workspace Layout step, the Presets row holds saved bundles — a folder, a terminal count, and an optional agent. Click a preset chip and that workspace opens immediately with that exact layout (the agent running in one terminal, traced), skipping the rest of the wizard.
- + New saves the folder + terminal count you’ve set, with an optional agent picked from your roster; hover a chip to delete it. The agent is resolved fresh at launch, so editing or removing it later never launches a stale snapshot.
- v0.98.0Shipped
Stackon Space — guided workspace setup
- New Workspace is now a short three-step flow — Start → Layout → Agents. Pick (or create) a folder, choose how many terminals to open and how they’re laid out (1 / 2 / 4 / 6 / 8 / 10 / 12, in a grid), then either add an AI agent or Open without AI for just the terminals.
- Nothing opens until you finish, so you get exactly the layout you asked for — N terminals in a grid, with the agent you chose running in one of them, recorded as a Stackon trace. Recent workspaces are one click away at every step.
- v0.97.0Shipped
Stackon Space — parallel agent lanes (git worktrees)
- Run several Claude agents on the same repo at once without them stepping on each other. Agent lanes — the
⎇button in the Terminal pane, or the command palette — create a git worktree: a separate working directory on its own branch sharing the repo’s history. A Claude session spawns pinned to it, so each agent edits its own files on its own branch and two of them never fight over the same file or the git index. - Spin up a few lanes (each can wear one of your roster agents), watch them side by side in the terminal grid, then remove a lane when you’re done — the branch stays so you can merge its work. Lanes live in a
<repo>-worktrees/folder next to your project, and each session is recorded as a Stackon trace like any other.
- Run several Claude agents on the same repo at once without them stepping on each other. Agent lanes — the
- v0.96.0Infra
Consistent page headers across the dashboard
- Every dashboard page — Traces, Canvas, Evals, Agents, Missions, Cost, Knowledge, settings, and every detail / new / edit screen — now draws its header from one shared component. The eyebrow, title, description, back-link, action buttons, and per-page stat line render identically, so the app reads as one surface instead of ~40 hand-built variations.
- Lead pillars (Trace, Evals, Approvals) carry an emerald accent dot; detail pages use a two-column layout with status badges and actions aligned to the header. Purely presentational — no behavior changed.
- v0.95.0Shipped
Stackon Space — light theme
- Stackon Space now ships a light theme alongside the default dark. Flip it in Settings → Appearance; the choice persists and applies live — the whole workspace, the Monaco editor, the terminals, and the markdown preview all re-tone together, no relaunch.
- Dark stays the default; light is one toggle away.
- v0.94.0Infra
Reorder Stackon Space editor tabs
- Drag an editor tab along the strip to reorder your open files, the same way the Terminal pane tabs already work. The order sticks while you work.
- v0.93.0Infra
Syntax highlighting in the markdown preview
- Fenced code blocks in the Stackon Space markdown preview now get syntax highlighting, brand-toned to match the editor. The highlighter is bundled in the app, so it works fully offline.
- v0.92.0Shipped
Stackon Space terminals stay alive per workspace
- Switching between workspaces no longer kills their terminals. Running
claudesessions and long-lived shells keep going in the background and are right where you left them when you switch back. - Only the current workspace’s terminals are shown; the rest stay mounted and hidden — so a swarm running in one project survives while you hop to another.
- Switching between workspaces no longer kills their terminals. Running
- v0.91.0Infra
Stackon Space terminals are scoped to each workspace
- Open terminals now belong to the workspace you opened them in, instead of being shared across every project. Switch workspaces and you see that project’s terminals — not a pile of unrelated shells.
- v0.90.0Shipped
Stackon Space — open or create a workspace folder
- The New Workspace flow can now create a folder, not just open an existing one: pick a parent directory, name it, and Stackon Space makes it and opens it. And the editor’s plain Open folder… is back as a one-click switch for when you just want to point at a directory.
- v0.89.0Shipped
Stackon Space — a real New Workspace flow
- “New Workspace” is now the front door. Step one picks the folder — your project root, which sets the editor root, the terminal working directory, and the trace context. Step two picks or creates the agent or mission to start with. Opening a workspace is one coherent action instead of separate folder + session steps.
- v0.88.0Shipped
Stackon Space — commit history in the Changes rail
- The git Changes rail gains a Recent commits list — the last 30 commits with short hash, subject, relative time, and author. It refreshes after you commit or sync, so you can watch your work land without leaving the app.
- v0.87.0Shipped
Stackon Space — branch, push & pull from the Changes rail
- The Changes rail now shows your current branch (
⎇ main) and how far ahead / behind your upstream you are, with Push and Pull buttons right there. Each shows an inline result (“Pushed ✓” / “Already up to date”) so you know it worked. - Sync uses your operating system’s git credentials — the same ones the
gitcommand line uses — independent of how you signed in to Stackon Space. An uncached credential fails fast instead of hanging.
- The Changes rail now shows your current branch (
- v0.86.0Shipped
Stackon Space — stage & commit from the Changes rail
- Commit without leaving Stackon Space. The Changes rail lists changed files with a stage checkbox each (plus Stage all), a commit-message box, and a Commit button — the basic add / commit loop, right in the workspace.
Ctrl/Cmd+Entercommits.
- Commit without leaving Stackon Space. The Changes rail lists changed files with a stage checkbox each (plus Stage all), a commit-message box, and a Commit button — the basic add / commit loop, right in the workspace.
- v0.85.0Shipped
Stackon Space — git diff viewer
- A new Changes tab in the editor rail shows your git working-tree changes. Pick a file and it opens a read-only side-by-side diff (the same Monaco diff engine VS Code uses) of HEAD vs. your working copy, overlaid on the editor.
- Reads your repo through
gitdirectly, pinned to the repository root; degrades gracefully when the folder isn’t a git repo or git isn’t installed.
- v0.84.0Shipped
Stackon Space — markdown preview
- Open a
.mdor.mdxfile and a Preview toggle appears in the tab strip — flip it for a rendered, side-by-side view that mirrors your edits live. Links open in your browser; the renderer blocks script andjavascript:URLs so a README can’t do anything funny.
- Open a
- v0.83.0Shipped
Stackon Space — create, rename & delete files from the tree
- Right-click any file or folder in the editor tree for New file, New folder, Rename, and Delete (right-click empty space for new file / folder at the root).
- It’s careful with open buffers: renaming remaps the tab, and a rename is refused if the file has unsaved changes rather than risk losing them.
- v0.82.0Fix
Stackon Space editor works offline
- The Monaco editor used to load its engine from a CDN, so it came up blank with no internet. Its assets are now bundled with the app and served locally — the editor works fully offline, on a plane or behind a firewall.
- v0.81.0Infra
Stackon Space — a File menu
- The editor toolbar’s five buttons (New file, Open folder, Save, Save all, Close) are tidied into a single File ▾ dropdown, with the unsaved-changes count riding on the menu as a badge. Click out or press Esc to close it.
- v0.80.0Shipped
Stackon Space — create agents & missions from the workspace
- The new-workspace wizard can now create an agent or a mission inline, not just pick an existing one. Fill the short form, hit Create & start, and it’s saved to your team and a traced
claudesession spins up in the workspace. The rows are real — they show up on the web dashboard too.
- The new-workspace wizard can now create an agent or a mission inline, not just pick an existing one. Fill the short form, hit Create & start, and it’s saved to your team and a traced
- v0.79.0Shipped
Stackon Space — start-a-session wizard
- Open a workspace for the first time and a wizard offers to start you working: pick one of your agents or missions and it spawns a traced
claudesession pinned to that folder, or start a blank terminal, or skip. Reachable any time from the command palette via “Start session in workspace…”.
- Open a workspace for the first time and a wizard offers to start you working: pick one of your agents or missions and it spawns a traced
- v0.78.0Infra
Stackon Space — a real workspace switcher
- The left rail is now a live list of your recent workspaces instead of a placeholder. Click one to switch the editor, terminals, and trace context to it; hover to remove it from the list. Opening a new folder records it automatically.
- v0.77.0Infra
Stackon Space — more command-palette actions
- The command palette (
Ctrl/Cmd+Shift+P) gains Save file, Replace in files, and Close workspace, and the rail’s “Open folder” button is now wired up. Opening Replace-in-files from the palette reveals the replace row in the Search panel.
- The command palette (
- v0.76.0Shipped
Find-and-replace — per file and per match
- Stackon Space find-in-files replace gets finer-grained: hover a file’s result group to replace every match in just that file, or hover a single match to replace only that one occurrence. The global Replace All keeps its confirmation step; the targeted replaces are one click.
- v0.75.0Shipped
Stackon Space — font, tab size & scrollback settings
- Settings adds editor + terminal font family, editor tab size, and terminal scrollback, all applied live. Font family is shared across editor and terminal and falls back to the built-in mono if you type a name that isn’t installed, so it never renders broken.
- v0.74.0Shipped
Stackon Space — find and replace across files
- The Search panel gains a replace row and a global Replace All (with a two-click confirm, since it writes to disk). Files you have open in the editor are edited through the editor itself so the change stays undoable; files with unsaved changes are skipped and reported rather than clobbered.
- v0.73.0Infra
Find-in-files — search as you type
- Stackon Space find-in-files now searches as you type (debounced, kicking in at two characters so a single letter doesn’t scan the whole tree). Enter still forces an immediate search at any length, and toggling case / whole-word / regex re-runs in place.
- v0.72.0Shipped
Find-in-files — regex & whole-word
- Stackon Space workspace search gains two toggles next to the case switch: whole-word (
\b) and regular expressions (.*). Matches highlight at their true length, and an invalid pattern shows a clear “Invalid regular expression” note instead of silently returning nothing. Plain-text searches keep the fast path.
- Stackon Space workspace search gains two toggles next to the case switch: whole-word (
- v0.71.0Infra
Stackon Space — the focused pane is highlighted
- Phase 7H wraps. The Terminal or Editor pane that currently holds keyboard focus now gets an emerald frame border and a brighter title — so it’s always obvious which pane
Ctrl/Cmd+Wwill close a tab in. Click between panes and the highlight follows; open the command palette and it stays put on the pane you were last working in. - Backed by a tiny observable store (
useSyncExternalStore) the panes update on focus. Tasks and Agents never highlight — they aren’t Ctrl+W targets.
- Phase 7H wraps. The Terminal or Editor pane that currently holds keyboard focus now gets an emerald frame border and a brighter title — so it’s always obvious which pane
- v0.70.1Shipped
Stackon Space — close the active tab (Ctrl/Cmd+W)
Ctrl/Cmd+W(and a "Close active tab" palette command) closes the active tab of whichever pane has keyboard focus — terminal or editor. It resolves the target from where your cursor actually is at the moment you press it, so it never closes the wrong pane; when focus is in the command palette it falls back to the pane you were last in.- The shortcut is intercepted so it can never close the Stackon Space window itself.
- v0.69.0Shipped
Stackon Space — command palette + global shortcuts
Ctrl/Cmd+Shift+Popens a command palette: a fuzzy-filtered list of actions — new terminal, open folder, quick-open, find in files, save all, toggle the terminal grid, settings, sign out — each row showing its keyboard shortcut, so the palette doubles as a way to learn them. Plus two new direct shortcuts:Ctrl/Cmd+Tfor a new terminal andCtrl/Cmd+Bto toggle the workspace rail.- Actions route through a small command bus so the shell-level palette can drive any pane. It joins the shortcuts already in place —
Ctrl/Cmd+Pquick-open,Ctrl/Cmd+Shift+Ffind-in-files,Ctrl/Cmd+Ssave,Ctrl/Cmd+,settings.
- v0.68.0Shipped
Stackon Space — settings / preferences
- A real preferences pane lands, reachable from the header ⚙ or
Ctrl/Cmd+,. Set editor and terminal font size, the default shell new terminals launch, and terminal cursor blink + style. Font and cursor changes apply live to every open pane — no relaunch — and everything persists across sessions via the same store the workspace folder and tabs already use. - Default shell is a free-text field (e.g.
pwsh.exe,cmd.exe); leave it blank to auto-detect. The plumbing makes new controls cheap to add.
- A real preferences pane lands, reachable from the header ⚙ or
- v0.67.0Infra
Stackon Space — new terminals open in your workspace
- New terminals now start in the Editor’s workspace folder instead of your home directory.
+ New, drag-spawns from Tasks/Agents, and restored tabs all resolve the current workspace — so a fresh shell is already in the project you’re working on. Change the workspace folder and the next terminal follows it. - The path is read fresh at spawn time, and Stackon Space falls back to your home directory if that folder has since moved or been deleted — a stale path never breaks the spawn.
- New terminals now start in the Editor’s workspace folder instead of your home directory.
- v0.66.0Shipped
Stackon Space — find in files
- Search your whole workspace from the Editor, not just the open file.
Ctrl/Cmd+Shift+Fflips the left rail to Search; type a query, press Enter, and matches stream in grouped by file with the hit highlighted. Click any result to open that file as a tab and jump straight to the line. - Built like quick-open — it reuses the workspace index, skips vendor/build folders, reads files concurrently in batches so a few-thousand-file repo stays responsive, skips binaries, and caps results. A case-sensitive toggle is included; regex / whole-word and search-as-you-type are the next slice.
- Search your whole workspace from the Editor, not just the open file.
- v0.65.0Fix
Stackon Space Editor — undo + cursor survive tab switches
- Phase 7C.2. Switching editor tabs no longer resets your place. Each open file now keeps its own Monaco model, so undo/redo history and your cursor + scroll position are preserved when you jump between tabs and back — the editor feels continuous, like VS Code.
- Under the hood the editor drives models keyed by file URI (handling Windows
C:\paths correctly) and saves/restores per-file view state, instead of remounting per file. Models are disposed when you close a tab or switch workspaces.
- v0.64.0Shipped
Stackon Space — quick-open (Ctrl/Cmd+P)
- Jump to any file without hunting the tree.
Ctrl/Cmd+Popens a fuzzy file finder over your whole workspace — type a few characters, arrow to a match, Enter to open it as a tab. Heavy/vendor folders (node_modules,.git, build output) are skipped and the index is capped so big repos stay snappy. - VS Code-style: the shortcut is captured app-wide once a workspace is open (so it beats the browser print dialog and the terminal’s Ctrl+P). With nothing open, Ctrl+P passes through to the terminal as before.
- Jump to any file without hunting the tree.
- v0.63.0Shipped
Stackon Space Editor — create files + Save all
- The Editor can now create files, not just open them. + New file takes a workspace-relative path (
notes.md,src/foo.ts), writes it to disk, and opens it as a tab. And Save all (Ctrl/Cmd+Shift+S, or the toolbar button showing the dirty count) writes every unsaved buffer at once. - Writes stay inside Tauri’s scoped filesystem; creating into a folder that doesn’t exist yet surfaces a clear error (no implicit directory creation for now).
- The Editor can now create files, not just open them. + New file takes a workspace-relative path (
- v0.62.0Shipped
Stackon Space Tasks — live list + status control
- The Tasks pane mission list now updates live too: missions you create or move on the web appear and re-sort in Stackon Space without a refresh (Supabase Realtime
postgres_changeson missions, team-scoped by RLS). With the live transcript from the previous build, the whole Tasks pane is now real-time. - And it’s no longer read-only — change a mission’s status (backlog → in progress → done → …) right from the desktop via the status dropdown. The change is row-level-security gated to your team and syncs back to the web instantly.
- The Tasks pane mission list now updates live too: missions you create or move on the web appear and re-sort in Stackon Space without a refresh (Supabase Realtime
- v0.61.0Shipped
Stackon Space Tasks update live
- The Tasks pane mission transcript now updates in real time, matching the web. Open a mission in Stackon Space and watch agent replies, system notices, and teammates’ messages stream in as they happen — no reselecting. A small ● live marker shows when the thread is connected.
- Same Supabase Realtime
postgres_changespath as the web thread, gated by the same row-level security — you only ever receive your own team’s messages.
- v0.60.1Infra
Stackon Space remembers your open files
- Your Editor tabs now come back on relaunch, alongside the terminal tabs and workspace folder. Open files (and the active one) are remembered per workspace and re-read from disk on reopen — so the whole Stackon Space session restores where you left it.
- v0.60.0Shipped
Stackon Space Editor — open files in tabs
- Phase 7C.1. The Editor pane now holds multiple files open at once. Click files in the tree to open them as tabs, switch between them, and close individually — each tab tracks its own unsaved-changes dot, and switching keeps your edits in place. Open files are marked in the file tree too.
Ctrl/Cmd+Ssaves the active tab. One Monaco instance still drives the active buffer (per-buffer undo history + cursor across switches is the next polish), and every write stays inside Tauri’s scoped filesystem (HOME / Documents / Desktop / Downloads).
- v0.59.1Infra
Reorder Stackon Space terminal tabs
- Small polish on the Terminal pane: drag a tab along the strip to reorder it. The order (and which tab is active) persists across relaunches, and reordering reflows the grid view too. No session restarts — you’re just rearranging.
- v0.59.0Shipped
Stackon Space — see all your terminals at once
- Phase 7B.2 lands. A new grid toggle (▦) in the Terminal pane flips between tabs and an N-cell grid — every running terminal visible at once, laid out automatically (two-up, 2×2, up to a 3-wide grid). Drive a swarm of
claudesessions side by side, or watch a mission run next to a live shell. - Tabs and grid are the same terminals, just arranged differently — toggling never restarts a session (the PTYs stay alive; each terminal just reflows to its new size). The active cell is ringed; click any cell to focus it. Your layout choice persists across relaunches alongside the tab strip.
- Phase 7B.2 lands. A new grid toggle (▦) in the Terminal pane flips between tabs and an N-cell grid — every running terminal visible at once, laid out automatically (two-up, 2×2, up to a 3-wide grid). Drive a swarm of
- v0.58.0Shipped
Stackon Space remembers your terminals
- Phase 7B.2. The Terminal pane tab strip now persists across relaunches. Quit Stackon Space and reopen it — your tabs come back in the same order, with the one you were on still active. Built on the same
tauri-plugin-storethe workspace folder and sign-in already use. - A shell session can’t survive a restart (the process is gone when the app quits), so restored tabs open as fresh shells — we deliberately don’t re-run a task tab’s command, so a
claudesession you spawned from a mission won’t re-fire on every launch. The N-cell grid view is the next slice of 7B.2.
- Phase 7B.2. The Terminal pane tab strip now persists across relaunches. Quit Stackon Space and reopen it — your tabs come back in the same order, with the one you were on still active. Built on the same
- v0.57.0Shipped
Mission threads update live
- Open a mission and watch it fill in — no refresh. Messages now stream into the thread in real time: every agent reply as the bound canvas runs, system notices, and messages from teammates all appear the moment they’re written. Previously only the person who kicked off a run saw live progress; everyone else had to reload.
- Built on Supabase Realtime
postgres_changesover themission_messagestable, gated by the same row-level security as the rest of your data — you only ever receive messages for your own team’s missions. The server still renders the full thread on load; live rows merge in on top.
- v0.56.0Infra
Faster docs — the API reference paints instantly
- The
/docsAPI reference loads in a fraction of the time. It used to ship a blank page that waited on a ~1 MB Scalar bundle before anything appeared — Lighthouse scored it 39 on mobile. Now the page server-renders a full endpoint index (every/api/v1operation, grouped by Traces / Evals / Bridge, parsed straight from the same OpenAPI spec we serve at/openapi.yaml) that paints immediately, and the interactive Scalar explorer loads on demand when you scroll to it or click Load interactive reference. - Result: total blocking time dropped from 751 ms to 37 ms, Speed Index from 7.6 s to ~1 s, and first paint from 7.6 s to ~1 s — the heavy explorer is no longer on the critical path, but it’s one scroll away when you want it. The Scalar bundle is now pinned to an immutable, edge-cacheable version, too.
- Marketing-side polish along for the ride: the home hero’s entrance animations settle a touch sooner, trimming Speed Index without losing any of the motion.
- The
- v0.55.0Shipped
Stackon Space — sign in with an email code
- Signing in to Stackon Space now happens entirely inside the app: enter your email, we send a 6-digit code, you type it in — done. No browser round-trip, no custom URL scheme. Same Stackon account, and the session persists across launches.
- The magic-link email now shows the code prominently alongside the usual sign-in link, so either works. This replaces the earlier deep-link sign-in, which stays supported for any links already in flight.
- v0.53.0Shipped
Stackon Space — drop a skill into a running session
- Drag a skill from the Agents pane onto a terminal that’s already running
claudeand its instructions are typed into that session for you to review and send — no new tab. Dropping on the tab strip still spawns a freshclaudetab with the skill applied, as before.
- Drag a skill from the Agents pane onto a terminal that’s already running
- v0.52.0Fix
Stackon Space traces — cleaner cost roll-ups
- Tightened how Stackon Space records terminal sessions as traces: fixed a source of trace pollution, removed a dead cost parser, and added a background sweeper that closes out stale, never-finished session traces so your trace list stays tidy.
- v0.51.0Shipped
Stackon Space traces — per-turn spans + cost
- Recorded terminal sessions now break a
clauderun into per-turn spans with a cost roll-up — so a session trace reads as a sequence of turns with token + cost detail, rather than one opaque blob.
- Recorded terminal sessions now break a
- v0.50.0Shipped
Phase 7F — Every Claude Code session in Space becomes a Stackon trace
- The differentiator. When you drag a mission / agent / skill onto the Terminal pane in Stackon Space, the resulting Claude Code session is now recorded as a Stackon trace. A pulsing red
RECbadge appears in the terminal cell header while it's recording; an Open trace ↗ button lights up next to it. Click that → your default browser opens the session atstackon.ai/dashboard/traces/<id>, where the full transcript lives next to every other Stackon run — replayable, eval-gateable, postmortem-ready, ready to share with a teammate. Every local Claude Code session has receipts. - Mechanism: new
desktop/src/lib/trace-session.ts. On terminal mount (whentrace: trueis in the spawn payload — set automatically by the Tasks / Agents / Skills panes; default-shell+ Newtabs don't trace, so throwawaylssessions stay private), atracesrow + one rootspan(kind=agent, name=terminal.session) are inserted via the existing authenticated Supabase client. Each PTY output chunk is ANSI-stripped + appended to an in-memory buffer; flushes happen every 2 s OR when the buffer hits 64 KB. Typed input is also appended (so the trace shows what the user said). On PTY exit, the session closes with status=ok; on unmount mid-run, closes with the same status (idempotent — the TraceSession has its ownclosedguard). - Privacy: transcripts are capped at 1 MB — past that, appends are dropped with a visible
Cappedbadge so the user knows recording stopped. Only Tasks / Agents / Skills spawns are traced by default; plain+ Newshells aren’t (preserves throwaway-session privacy). Recording uses the same RLS-scoped client as every other Supabase write — only the user's team sees their traces. - Bundle: 783 KB JS / 26 KB CSS (gzip 215 + 6). +5 KB for the trace-session lib. Phase 7 is complete. Stackon Space now matches the original vision end-to-end — terminals, editor, missions, agents, skills, AND every shell session becomes a Stackon trace. The desktop workspace where every Claude Code session has receipts.
- The differentiator. When you drag a mission / agent / skill onto the Terminal pane in Stackon Space, the resulting Claude Code session is now recorded as a Stackon trace. A pulsing red
- v0.49.0Shipped
Phase 7E — Agents + Skills sidebar with drag-to-terminal
- Stackon Space’s Agents pane is no longer a stub. Top half = your team’s roster, pulled live from
team_agents(same Supabase project the web uses, RLS-scoped server-side). Bottom half = the Skills library — Scribe-distilled procedures from past canvas runs. - Drag an agent onto the Terminal pane → spawns
claude --append-system-prompt <agent.system_prompt>. The new Claude Code session boots already wearing that agent’s persona. Drag a skill → spawnsclaudewith the skill’s instructions appended to the system prompt, wrapped in a# Applied skill · <name>header so Claude treats it as procedural addendum, not the primary persona. - Every card also has a Spawn click button — same payload, same outcome, but works without drag (trackpad-friendly). Reuses the
application/x-stackon-spawnmime +spawn-busCustomEvent pipeline from Phase 7D — Terminal pane routes mission cards, agent cards, and skill cards identically. - Same
claudeprerequisite as 7D: install Claude Code CLI on your PATH (npm install -g @anthropic-ai/claude-code) or the spawned tab will saycommand not found. Phase 7E.1 polish: drop a skill onto an already-running terminal to inject it mid-session via PTY stdin instead of always spawning a fresh tab. Next: 7F — terminal session → Stackon trace bridge (everyclaudesession in Space optionally becomes a replayable trace).
- Stackon Space’s Agents pane is no longer a stub. Top half = your team’s roster, pulled live from
- v0.48.0Shipped
Phase 7D — Tasks pane wired to live Missions API + drag-to-terminal
- Stackon Space’s Tasks pane is no longer a stub. It now pulls your team’s missions from the live Stackon backend (same Supabase project as the web), with the list on the left + the selected mission’s transcript on the right. Click any mission card to see its full thread (user prompts + agent messages + system errors, exactly as the web mission page renders them). Read-only for v1 — composer + new-mission creation are Phase 7D.1.
- The differentiator: drag a mission card onto the Terminal pane’s tab strip and a new tab opens running
claudewith the mission’s title + description as the initial user prompt. The agent picks up the task as if you’d typed it. Same effect via the "Spawn in Terminal" button on the mission detail header. The tab strip flashes emerald on drag-over so you know the drop target is hot. - Mechanism: new
desktop/src/lib/missions.tsreuses the authenticated Supabase client from Phase 7A.1 — RLS scopes everything server-side to yourteam_membersrows, no extra filtering on the desktop side. Newdesktop/src/lib/spawn-bus.tsis a window-level CustomEvent helper for cross-pane spawn requests (avoids prop-drilling between sibling panes that don’t share state). The Terminal pane subscribes on mount; both drag-and-drop AND the "Spawn in Terminal" button feed it identically. - Prerequisite for the spawn to actually do anything useful: Claude Code CLI installed and on your PATH. If it’s not, the spawned tab shows
claude: command not found— install vianpm install -g @anthropic-ai/claude-code. Stackon Space doesn’t bundle Claude Code; you own that install (lets you stay on your preferred Claude Code version, get its own updates, etc). - Phase 7E next: Agents + Skills sidebar with drag-to-terminal injection. Phase 7F: terminal session → Stackon trace bridge (the killer differentiator — every
claudesession in Space optionally becomes a replayable Stackon trace).
- v0.47.0Shipped
Phase 7B.1 + 7C — terminal tabs + Monaco editor pane
- Terminal tabs (7B.1). Stackon Space’s Terminal pane is now multi-tab. Click
+ Newto spawn another shell. Each tab keeps its own PTY alive when you switch away (display:none, not unmount, so xterm state survives). Hover a tab for the close (×) which kills that tab’s PTY. ResizeObserver in the cell naturally refits when a tab becomes visible again. - Editor pane (7C). Real Monaco editor — same engine VS Code uses — wired to
tauri-plugin-fsfor read/write/list. Click Open folder… → native folder picker viatauri-plugin-dialog→ file tree on the left, Monaco on the right. Click a file to open it; Ctrl/Cmd+S writes the buffer back viawriteTextFile. Language detection covers TS/JS/MD/CSS/HTML/Rust/Python/Go/YAML/TOML/shell/SQL/XML; falls back toplaintextfor the rest. The workspace folder path persists across launches viatauri-plugin-storeso reopening Stackon Space restores your last project. - FS scoping. The
fs:scopecapability locks reads + writes to$HOME / $DOCUMENT / $DESKTOP / $DOWNLOADsubtrees. Anything outside the allowlist is rejected at the plugin layer — agents can’t touchC:\Windowsor/etcfrom the workspace. Per-workspace scoping is a future polish. - Monaco theme matches the Stackon palette (charcoal canvas, emerald cursor). One open file at a time for v1 — tabs come in 7C.1. Bundle: 771 KB JS / 25 KB CSS (gzip 212 + 6); Monaco itself loads dynamically from CDN on first use to keep the desktop binary small.
- Terminal tabs (7B.1). Stackon Space’s Terminal pane is now multi-tab. Click
- v0.46.0Shipped
Phase 7B — real PTYs in the Terminal pane
- Stackon Space’s Terminal pane is no longer a stub. It hosts a live
xterm.jsterminal wired to a Rust-side PTY running your platform shell (PowerShell 7+ if installed, else Windows PowerShell 5.1 on Windows;$SHELL→ zsh on macOS;$SHELL→ bash on Linux). Type, see output, resize the pane and the PTY resizes too. Restart button kills the child and spawns a fresh one. - Mechanism: new
src-tauri/src/pty.rswraps theportable-ptyRust crate. Four Tauri commands —pty_spawn/pty_write/pty_resize/pty_kill— each operate against aHashMap<String, PtyHandle>behind aMutex. On spawn, a dedicated reader thread pumps PTY output (8 KB chunks) to the renderer via Tauri events onpty:<id>:output; on child exit the thread emitspty:<id>:exitand removes the handle from state. - Renderer: new
TerminalCellcomponent constructs anxterm.jsinstance with the Stackon palette (charcoal canvas, emerald cursor, branded ANSI colors), loadsFitAddon, callsspawnPty, wires output →term.writeandterm.onData→writePty, and aResizeObserverdrivesfit.fit() + resizePty. Unmount kills the PTY + disposes the terminal. Status chip in the cell header reflects booting / running / exited / error. - Phase 7B.1 will add a tab UI (multiple terminals per pane) + an N-cell grid layout matching the screenshot the user shared. Phase 7D drags missions onto terminals to spawn
claudewith the mission user_task; Phase 7E lets you drag skills to inject system prompts. Phase 7F captures terminal sessions into the existing trace/span tables.
- Stackon Space’s Terminal pane is no longer a stub. It hosts a live
- v0.45.0Preview
Phase 7A.1 — Stackon Space OAuth deep-link sign-in
- Stackon Space’s splash now has a real Sign in with Stackon button. Click it → your default browser opens to
stackon.ai/sign-in?next=stackon://auth/callback→ you sign in (magic link or GitHub) → the web redirects to the customstackon://scheme with the session tokens in the URL fragment → the OS routes the URL back to the running Stackon Space window → the splash dismisses and your workspace mounts. Persisted to disk viatauri-plugin-store; subsequent launches restore the session automatically. - Web side:
/auth/confirmlearns aTRUSTED_SCHEMESwhitelist (currently juststackon://). Whennextis in the whitelist, the route’s post-verifyOtpredirect target gets the session encoded into the URL fragment (#access_token=...&refresh_token=...&expires_in=...) — tokens in the fragment so they stay out of server access logs + referrer headers. The webfinalUrlhelper also passesstackon://through unchanged so the magic-link email’semailRedirectTopoints at the custom scheme. - Tauri side: three new plugins —
tauri-plugin-deep-link(custom URL scheme registration via theplugins.deep-link.desktop.schemesbundle config),tauri-plugin-shell(renderer can open the external browser),tauri-plugin-store(persisted session file). Plustauri-plugin-single-instancewith thedeep-linkfeature so the secondstackon://launch (during a sign-in handshake) wakes the existing window instead of spawning a second process. Capabilities updated. - Renderer side:
desktop/src/lib/{supabase,auth}.ts. The Supabase JS client usesdetectSessionInUrl: falsebecause we feed the fragment tosetSessionourselves from the deep-link listener.App.tsxbootstraps with a brief "Restoring your session…" state, then either mounts the shell (if a session restored fromtauri-plugin-store) or shows the sign-in splash. Build-time env vars:VITE_SUPABASE_URL+VITE_SUPABASE_PUBLISHABLE_KEYdocumented in newdesktop/.env.example. - Phase 7A.1 unblocks 7B (real PTYs) and everything that follows — the session is now real, so Tasks/Agents/Skills can actually hit the Stackon API once those panes are wired in 7D/E.
- Stackon Space’s splash now has a real Sign in with Stackon button. Click it → your default browser opens to
- v0.44.0Preview
Phase 7A — Stackon Space scaffolded (native desktop agent workspace)
- Stackon Space — the native desktop incarnation of Stackon — gets a real shell. The Tauri window no longer redirects to the web dashboard; it hosts a Vite-built React app implementing a four-pane workspace: Terminal · Editor · Tasks · Agents. Splitters between panes, a workspace rail on the left, a pipeline strip on the bottom — the same kind of multi-pane layout you’d expect from a native IDE, but every pane is a future home for live Stackon primitives.
- What the desktop app IS today (Phase 7A): a real frontend pipeline (Vite + React 19 + Tailwind v4 inside
desktop/), the four-pane resizable shell, brand-token-matched chrome, a splash with a "Continue to workspace" CTA. What it’s NOT yet: real PTYs (Phase 7B —portable-pty+ xterm.js), Monaco editor (7C), Mission API integration (7D), Skill drag-injection (7E), terminal-to-trace bridging (7F), OAuth deep-link sign-in (7A.1). Each pane shows a labeled stub describing what fills it. - Strategic framing: Stackon Space is the same product as web Stackon — same backend, same auth, same Postgres, same brand. The desktop binary is the workspace surface; the cloud is the brain. Web Stackon stays for missions/agents/canvas/traces. Stackon Space adds the things web can’t do — local file system, native PTYs, multi-pane simultaneous runs.
- Build outputs:
desktop/dist/bundle (237 KB JS, 20 KB CSS gzipped to 74 + 5).tauri.conf.jsonnow invokesnpm run dev:vite/npm run build:viteviabefore*Command; dev URL flipped fromlocalhost:3000(web app) tolocalhost:1420(Vite). Tauri shell version bumped tov0.44.0.
- v0.43.0Shipped
Phase 6D — @-mention dispatch, swarm mode, multi-turn conversation context
- The mission composer is now a real terminal interface. Type plain text and the bound canvas runs sequentially (existing behavior). Start with
@alland every roster agent runs in parallel against the same prompt — outputs interleave into the transcript as they stream in. Start with@<agent-name>matching a roster agent in the bound canvas and just that agent runs, skipping the pipeline. The token matcher is forgiving (case-insensitive, ignores dashes/underscores/spaces), so@Coder-Bobmatches an agent named "Coder Bob" and vice versa. - Every run also now sees the prior mission turns as conversation context.
runCanvas+ newrunAgentByIdload the last 30 user/agent messages for the mission (when a missionId is threaded in) and inline them into each node's system prompt as a `# Prior conversation in this mission` block. Closes the stateless-run gap from Phase 6C — the agent that wrote the diff knows what the user asked for two turns ago. - New
runAgentById(agentId, userTask, opts)mirrors runCanvas's lifecycle for a single roster agent: trace shell + root span + broadcaster (uses the mission's bound canvas channel so the LiveRunPanel transparently subscribes), one synthetic LLM span, one mission_message.runCanvasgrows aswarm: booleanoption — sequential for-loop vs.Promise.all; the per-node atom was extracted into anexecuteNodeStepclosure so both modes share it. - Phase 6 is complete. The Missions / Agents / Canvas / Approvals tabs now feel like a Claude-Code-style multi-agent terminal: add agents to your roster, drop them into a canvas, attach the canvas to a mission, then converse with the team — swarm them, task them individually, or run the full pipeline. Every token streams live; every turn persists.
- The mission composer is now a real terminal interface. Type plain text and the bound canvas runs sequentially (existing behavior). Start with
- v0.42.0Shipped
Mission becomes a chat thread — roster, transcript, composer, live stream
- Mission detail page is no longer a form — it's a thread. Top: title + status + roster of agents (pulled from the bound canvas's nodes, named via the team_agents roster when available). Middle: scrollable transcript of every user prompt + every agent message, oldest first, with cost / tokens / trace link per agent message. Bottom: composer — type what the team should work on and hit Send. The existing edit / approve / archive / delete forms moved into a collapsed "Mission settings" disclosure so they're still reachable but no longer dominate the page.
- New `mission_messages` table (RLS scoped to `team_members`, append-only by design: insert + select only from user clients; admin client retains update/delete for future scrub flows). One `role='user'` row per composer submit; one `role='agent'` row per `node.completed`; `role='system'` for run failures. Each agent row links back to its `trace_id`, `span_id`, `canvas_node_id`, and `agent_id` (when bound to a roster agent) so the transcript carries all the cross-links needed for replay + drill-in.
- The composer reuses Phase 6B's broadcast pipeline: pregenerates a `traceId`, schedules `runCanvas` via Next 16 `after()` with `{ precreatedTraceId, missionId }`, redirects with `?live=
`. The LiveRunPanel mounts above the transcript and streams tokens as the run executes; once each node completes, a persisted mission_message arrives and the live block becomes static. Approval-gated submits still queue a pending row (`requestMissionRun`), but the user message persists immediately so the thread shows the intent before the approver acts. Approval-driven runs now also write agent messages because `approveMissionRun` threads the `missionId` into `runCanvas`. - Multi-turn agent context is intentionally deferred to Phase 6D — each composer submit is currently a fresh run against the bound canvas with the composer text as the user task. The mission's title + description are visible context for humans but aren't re-injected into the LLM prompt today.
- v0.41.0Shipped
Canvas runs stream live — tokens land in the page as they're generated
- Hitting Run on a canvas no longer makes you wait for the whole pipeline to finish before you see anything. The page now renders a live transcript: each agent shows its output character-by-character as it streams from Claude. Active node has an emerald-pulsed border; completed nodes show cost + token counts; final state links to the persisted trace.
- Mechanism: `runCanvas` extends to broadcast `run.started` / `node.started` / `node.token` / `node.completed` / `run.completed` / `run.failed` on the existing `canvas:
` private Realtime channel (same substrate as multiplayer cursors + comments). Token deltas are batched at 100 ms or 400 chars to stay under Supabase's per-channel msg/sec budget. Emission uses the service-role admin client so it bypasses the `realtime.messages` RLS policy without needing a user JWT. - Dispatch model flipped from "server action blocks until done" to "server action schedules + redirects with ?live=<traceId>" via Next 16 `after()`. The trace id is pregenerated client-side (crypto.randomUUID) and passed into `runCanvas` so the redirect target is known before the LLM work begins. The persisted trace remains the source of truth — broadcasts are best-effort, additive, and dropped if delivery fails (the live UI just misses a chunk; the trace catches up on completion).
- Foundation for Phase 6C (mission-as-thread) + 6D (swarm + interjection). Canvas approvals + eval-gate runner + HTTP API runner stay synchronous for now — they don't need a live UI.
- v0.40.0Shipped
Agents become first-class — team roster you can drop into any canvas
- The Agents tab is no longer a one-shot prompt form. It's now a roster: name, role, model, and system prompt saved per team. Click into any agent to edit; archive when you're done with it. The legacy one-off runner moves to `/dashboard/agents/quick` so you can still fire a quick test without committing to a saved agent.
- New `team_agents` table (RLS scoped to `team_members`, soft-deletes via `archived_at`, one active agent per (team, name)). `canvas_nodes` gains a nullable `agent_id` reference — nodes linked to a roster agent show a green `From roster` chip and resolve the agent's current role / model / system prompt at run time. Edit Coder Bob's system prompt and every canvas that uses him picks up the change on the next run.
- Canvas add-node form now leads with a `From roster` picker (when you have saved agents) above the existing inline form. Both work — pick from the roster to track an agent live, or define inline for a one-off node. Existing canvas nodes are untouched (agent_id is nullable; their inline columns keep working).
- Foundation for Phase B (live streaming inside the canvas) and Phase C (mission-as-thread with @-mention dispatch to specific agents). Agents need stable identity before either lands, which is what this ships.
- v0.39.4Shipped
Press-kit full lockup — mark + wordmark on one canvas
- Added a horizontal lockup to the press kit — mark on the left, wordmark on the right, both centered on the same 1536×1024 canvas. Ships in both dark (`#0A0A0A`) and light (`#FAFAF8`) variants. Useful for footers, slide decks, and any context where a journalist or partner wants both identity pieces composed as a single asset rather than reassembling the mark and wordmark by hand.
- `scripts/crop-stackon-logo.mjs` gains a lockup pass that reuses the existing `markBuffer` and the vector wordmark SVG (480×480 mark, 64 px gap, 760 px wordmark, group centered on the canvas). Same `npm run gen:brand` regenerates everything; no new dependencies.
- `/media` now lists the two lockup tiles at the top of the asset grid, ahead of the mark-only and wordmark-only slots — the typical first thing a press contact reaches for.
- v0.39.3Fix
Press-kit wordmark — designed SVG replaces gpt-image-1 raster
- The `/media` wordmark slots (`Wordmark · dark` and `Wordmark · light`) were generated by gpt-image-1, which mangles text — the rendered `STACKON` letterforms had subtle distortion and paper-grain artifacts that didn't read at press scale. Replaced with a hand-wired vector wordmark built from Geist Regular glyph paths.
- New `scripts/build-wordmark.mjs` reads the Geist-Regular.ttf already bundled with `@vercel/og` (a transitive Next.js dependency), uses `opentype.js` to convert the text "Stackon" to SVG glyph paths, and writes `public/stackon-wordmark-{dark,light}.svg`. Path-only — no font dependency at render time, no rasterization, no AI distortion. Single color per variant (white #FAFAFA on dark, charcoal #0A0A0A on light); drops the legacy coral 'on' two-tone from the v0.34 bitmap source, aligned to v0.36 monochrome.
- `scripts/crop-stackon-logo.mjs` now invokes the wordmark builder up-front, then rasterizes the SVG onto a 1536×1024 canvas at 1100 px target width for the press-kit PNGs. `npm run gen:brand` remains the single command to refresh all brand assets. PNG file size dropped from ~640 KB (raster) to ~59 KB (clean vector composite).
- Removed the `media-logo-dark` / `media-logo-light` entries from `scripts/placeholder-prompts.mjs` so a future `npm run gen:placeholders --force` can't silently overwrite the vector wordmark with a gpt-image-1 raster. Gotcha #60 (wordmark distortion caveat in press kit) closes.
- v0.39.0Preview
Stackon for Windows — Tauri shell scaffolded (NSIS + MSI)
- The Tauri shell now targets Windows alongside macOS. `tauri.conf.json:bundle.targets` extends to `["dmg", "app", "nsis", "msi"]` — Tauri silently skips the platform-foreign targets at build time, so the same `npm run desktop:build` invocation produces a DMG on macOS and an NSIS .exe + MSI on Windows. No code changes in `main.rs`; the Rust shell is platform-agnostic by design.
- Added a Windows `bundle.windows` config block: `webviewInstallMode: downloadBootstrapper` (so older Windows 10 boxes get WebView2 fetched at install time), NSIS `installMode: perMachine` with the new `icon.ico` as the installer icon, WiX defaults set to `en-US`. The capability surface is unchanged from the macOS shell — same minimal `core:window:*` permissions.
- Asset pipeline extended: `scripts/crop-stackon-logo.mjs` now also emits `desktop/src-tauri/icons/icon.ico`, a multi-resolution ICO covering 16/24/32/48/64/128/256 px. Built from the same RGBA mark via the `to-ico` npm package — no external tooling, runs on every `npm run gen:brand`.
- **You cannot build a Windows installer from macOS.** Tauri's Windows bundler relies on Windows-only tooling (NSIS, WiX, SignTool). Production builds happen either on a Windows machine or — recommended — a `windows-latest` GitHub Actions runner. `desktop/DEPLOY.md` gains a section 8 covering Windows prerequisites (MSVC C++ Build Tools, rustup), build commands, code signing (OV vs. EV certs), and the GH Actions workflow stub. The `desktopWindows` feature flag stays `enabled: false` until a signed `.exe` + `.msi` is hosted.
- v0.38.1Fix
Stackon for Mac — first compiling build (scaffold fixes)
- v0.38.0 scaffolded the Tauri shell but never compiled locally — the dev box was missing Command Line Tools + Rust. After installing both (xcode-select --install, rustup default stable), the first `npx tauri build` surfaced two real bugs in the scaffold: a capability that doesn’t exist in Tauri v2.11, and icon PNGs in the wrong color space.
- Capability fix: `core:webview:allow-reload` was requested in `capabilities/default.json`, but Tauri 2.11 removed it — reload now lives on the OS menu (⌘R). Dropped it; nothing was using it anyway.
- Icon fix: `scripts/crop-stackon-logo.mjs` was emitting RGB PNGs for the desktop icon matrix (32×32, 128×128, 128×128@2x, 512×512). Tauri’s `generate_context!` proc-macro requires RGBA. Added `.ensureAlpha()` to the desktop icon loop. All four PNGs now write as 8-bit RGBA; `iconutil` still assembles `icon.icns` from the RGB sources cleanly.
- After fixes, the first end-to-end build produces `Stackon.app` + `Stackon_0.38.1_x64.dmg` in ~1m 23s (~4.2 MB DMG, unsigned x86_64). Signing + notarization still gated on Apple Developer Program enrollment. Bumped `desktop/{Cargo.toml,package.json,tauri.conf.json}` from the inherited 0.37.1 to 0.38.1 so the DMG filename + version sync to the repo cadence going forward.
- v0.38.0Preview
Stackon for Mac — Tauri v2 desktop shell (scaffolded)
- New `desktop/` package: a Tauri v2 Rust shell that wraps the Stackon web ADE in a native macOS window. Dev mode points at `http://localhost:3000` and hot-reloads alongside `npm run dev`; production build redirects to `https://stackon.ai/dashboard` from a tiny `dist/index.html` splash. Window chrome is native (titlebar, dock icon, ⌘W/⌘Q), backed by WKWebView on macOS so memory + cold start are roughly half of what an Electron equivalent would be.
- Bundle identifier `ai.stackon.desktop`. Icons regenerate from `stackon/stackon_logo.png` via the existing `npm run gen:brand` script — the matrix now includes 32×32/128×128/128×128@2x/icon.png PNGs plus an `icon.icns` assembled via macOS `iconutil`. The Rust code is intentionally tiny: a single `main.rs` that calls `tauri::Builder::default().run()`. We’ll add commands + plugins (system tray, global hotkey for voice push-to-talk, native notifications) as later iterations.
- Distribution: direct download from `/download`, no App Store. The `desktopMac` feature flag stays `enabled: false` until the signed DMG is hosted — the page renders a 'Coming in Phase 4' violet pill in the meantime. Signing + notarization requires Apple Developer Program enrollment ($99/yr), which is the same gate as TestFlight (mobile/DEPLOY.md step 0.2). Doing both together is the natural sequence.
- Windows build is a near-identical follow-up in a later session — same Tauri base, swap the bundle target from DMG to MSI. The `/download` page already has a Windows card showing 'Coming in Phase 4' so the placement is in place.
- v0.37.0Shipped
Voice v2 — true local Whisper (wasm) joins the capability chain
- Push-to-talk now has a third path: fully in-browser Whisper via `@huggingface/transformers` (ONNX wasm). Audio + inference both stay on the device — nothing leaves the browser. First use downloads ~145 MB of `onnx-community/whisper-tiny.en` at fp32 precision (cached in browser Cache Storage thereafter). Subsequent transcriptions reuse the loaded pipeline with no network round-trip. fp32 chosen over the smaller quantized variants because their per-tensor scale tensors are broken in the upstream exports — crashes session init via the new MatMulNBits kernel.
- User-selectable preference (auto / local / cloud) is persisted to localStorage and exposed as a one-click chip next to the mic button. `auto` resolves to webspeech → local → cloud (best UX everywhere). `local` is a privacy lock — it will never silently fall back to cloud. `cloud` keeps the existing Whisper-1 path for users who explicitly opt in.
- Audit log records the same shape for all three modes (`bytes`, `mime`, `duration_ms`, `transcript_chars`, plus a new `mode` field). A new same-origin `POST /api/voice/audit` endpoint receives a JSON beacon from the browser when local-mode transcription finishes, so the compliance audit log shows the usage without the audio ever crossing the wire.
- Component palette aligned to v0.36 — error states use rose instead of red. Build, lint, typecheck all clean.
- v0.36.3Shipped
Final amber sweep — every remaining marketing + auth + onboarding surface
- Closes the v0.36 monochrome campaign. After this commit, `grep -rE 'amber|FBBF24|251,191,36' src/app src/components` returns empty across the entire repo. Home (v0.36), dashboard (v0.36.1), pricing (v0.36.2), and now everything else.
- 16 files swept: About, Careers, Changelog, Community/Discord, Community/Events, Contact, Forge marketplace + listing detail, Invite landing, Media, Privacy, Terms, the auth layout + form, the onboarding layout + 3-step wizard. ~58 amber utilities + 5 amber-rgba hero backdrops retired.
- Tone calls worth flagging: the changelog `preview` kind moved from amber to rose, filling the 4-tone categorical slot alongside shipped (emerald), fix (sky), infra (violet). The invite-landing `Pill` ('Team invite' / 'Email mismatch') moved to violet — categorical 'invitation' marker. The auth header's mini 'S' logo mark flipped to a white background. The onboarding wizard's 'checked' selection state, progress dots, and CTAs all moved to white (neutral primary) rather than picking a categorical color for what is fundamentally a selection-vs-unselected toggle.
- Every italic emphasis phrase ('one we'd trust with production', 'say hello first', 'where we build', 'on the calendar', 'the right answer', 'shipped', 'brand', 'policy', 'service') flipped from text-amber-300 to text-white. Emphasis without color, per v0.36 ethos. Every hero radial-gradient backdrop swapped from amber-rgba to a faint white glow. Every mailto link in /privacy and /terms moved from amber to text-zinc-100 with underline-offset.
- Build, lint, typecheck clean. No behavior changes.
- v0.36.2Shipped
Pricing page — amber sweep to match v0.36 monochrome palette
- The last public marketing surface still running on the old amber-accented system. `/pricing` now follows the same recipe as the home (v0.36) and dashboard (v0.36.1): white-pill primary CTAs, neutral zinc eyebrows, monochrome chrome.
- The featured Team plan card flipped from amber to violet — categorical 'premium tier' pop, matching the convention from v0.36.1 (Owner role badge, postmortem panel, modified-diff state). Border + gradient + ring + 'Most popular' badge text + the matrix column header all read violet now. The CTA inside the featured card is a white pill (same as every other primary action across the app).
- Feature-list bullets uniform muted zinc across all plan cards. FAQ caret neutral. Italic accent phrases ('not seat-shaming.', 'Start free') keep the typography but drop the amber tint — emphasis without color, per v0.36 ethos. Hero radial-gradient backdrop swapped from amber-rgba to a faint white glow.
- 12 amber utilities + 1 amber rgba retired in `src/app/pricing/page.tsx`. No behavior changes. Build, lint, typecheck clean. `/pricing` is now the third surface (after home + dashboard) running on the unified `--brand-*` palette.
- v0.36.1Shipped
Dashboard amber sweep — monochrome palette across the app shell
- v0.36 retired amber on the marketing home and shared chrome. v0.36.1 finishes the job: every page under /dashboard (38 surfaces) plus five shared components (ComingSoon banner, trace/badges, voice-input, canvas-multiplayer, canvas-comments) now run on the same monochrome system. ~273 amber utilities replaced with `--brand-*`-aligned alternatives.
- Primary CTAs flipped from amber pills to white pills (`bg-white text-zinc-950 hover:bg-zinc-200`), matching the home's primary action. Form focus rings dropped from amber to neutral white. Hover-link accents lost their amber tint.
- Semantic emerald now appears only where v0.36's rule says it should: live status. Trace, Evals, and Approvals eyebrows are emerald (the live-measurement family). The Run-canvas and Run-mission action panels carry an emerald-tinted gradient. The cost breakdown bar reads as a live feed. Postmortem panels moved to violet (analytical / investigative, not a status). Diff-modified rows moved to violet (categorical, distinct from emerald-added and red-removed). 'Coming Soon' chips and the dashboard nav hover dropped to pure neutral. Warning banners (missing env vars, no canvas yet) moved to rose — pending/attention per the v0.36 semantic palette.
- The Trace span-kind badge for `agent` moved from amber to the paler categorical emerald (`emerald-300`) — distinct from the saturated emerald-400 used for OK/in-progress status. Build, lint, and typecheck all clean; no behavior changed.
- v0.36.0Shipped
Marketing home rework — monochrome palette, editorial Trace pillar
- The home page and shared marketing chrome (header / nav / footer) traded amber for a monochrome white-on-near-black system. New brand tokens live in `globals.css` (`--brand-bg/surface/text/live/pending/tone-*`) as the single source of truth.
- Muted emerald (#34D399) is the only chromatic accent and it's reserved for live/healthy status moments — pulsing dots, the eval-pass row, the '● Recently shipped' hero callout. Categorical product chips use a 4-tone set (sky for Canvas, violet for MCP, emerald for Trace, rose for Mobile).
- Two new home sections: `
` ('Four products. One workflow.') and ` ` (Describe / Orchestrate / Ship triptych). The Trace pillar was rebuilt as a single editorial spine — small chip, oversized two-line headline ('Every run / leaves a trace.'), ` ` artifact with crop-mark corners, then a 3-up feature row. - All `gpt-image-1` prompts rewritten end-to-end — HUNTERADE wordmark → STACKON, amber → emerald-only-where-functional, `ANTI_AI_TAIL` to reduce AI tell. 17 of 18 placeholders regenerated; the 18th (`home-fp2p-ship.png`) is blocked on raising the OpenAI billing limit and renders the dotted-grid fallback in the meantime.
- v0.35.0Shipped
Renamed to Stackon
- HunterADE is now Stackon. The new brand mark — three stacked cards representing code, sparkle, and OpenAI's model — sits over the wordmark and reads as an editor environment built on top of the foundation models that actually do the work. The tagline followed: an Agentic Developmental Environment powered by Claude and Codex.
- Sub-products dropped the Hunter prefix. HunterTrace is Trace, HunterCanvas is Canvas, HunterMobile is Mobile, HunterCost is Cost, and so on. Two exceptions where the bare noun was too generic: Stackon MCP and Stackon CLI.
- This release is the visible-surfaces flip: marketing pages, dashboard UI, mobile app icon + name + deep-link scheme, emails, OpenAPI docs, /privacy and /terms. Wire formats stayed put on purpose — `ht_` / `hbk_` / `htmi_` / `htmd_` token prefixes still work, the `X-HunterADE-Signature` webhook header is unchanged, and `HUNTERADE_*` env vars keep their names. Existing automation against the API does not break. A later cutover sprint will rotate those when there's a clean migration window.
- iOS bundle ID flipped to `com.stackon.mobile` — the one exception to the phased rule, because App Store records are permanent post-registration and the mobile build hadn't shipped to TestFlight yet. Free now, irreversible after.
- v0.34.5Preview
HunterMobile brand assets — icon, splash, adaptive, favicon
- mobile/assets/ now ships with the four files EAS Build requires: icon.png (1024×1024 RGB), splash.png, adaptive-icon.png, and favicon.png. All derived from the existing HunterADE crosshair mark (public/placeholders/media-mark-dark.png) via macOS `sips` — center-cropped to 1024 square, no alpha channel (Apple rejects icons with transparency).
- mobile/app.json wires the new files through expo.icon, expo.splash (resizeMode contain, #0A0A0A background), expo.android.adaptiveIcon, and expo.web.favicon. Mobile bundle bumped to 0.34.5; DEPLOY.md step 1 now reads as ✅ shipped.
- Closes the last codebase-side blocker before TestFlight submission. Remaining: deploy the backend at the apiBaseUrl, enroll Apple Developer, eas login, eas init, eas build + eas submit.
- v0.34.4Preview
TestFlight prep — privacy, terms, mobile deploy checklist
- New /privacy and /terms pages cover everything Apple needs to accept a TestFlight submission — what data the app collects, who we share it with (Supabase / Anthropic / OpenAI / Resend / Expo / Stripe), how to delete your data, and the standard alpha-stage warranty disclaimers. Footer links to both. Plain-English drafts written for honest disclosure, not legal cover — get them reviewed by counsel before public GA.
- New mobile/DEPLOY.md walks the user through every step from Apple Developer enrollment to `eas submit --platform ios`. P0 flagged up top: the production build talks to hunterade.com, so the backend has to be deployed and reachable before TestFlight reviewers can pair.
- Cleanup in mobile/: dropped the dangling googleServicesFile reference so a first `eas build --platform ios` succeeds without an Android Firebase project. Bumped mobile bundle + app.json to 0.34.0.
- v0.34.3Fix
Press kit — full-image view, click-to-open, download per asset
- The new /media tiles were being cropped: every press shot is wider than 16:9, and the old PlaceholderImage frame used object-cover, lopping content off both sides. Replaced the press-kit grid with a new MediaAsset component that renders each shot at its natural aspect (object-contain inside an aspect-ratio computed from the file).
- Click any tile → opens the original file at full resolution in a new tab. Each tile now has a `↓ Download` link beneath it that saves the file directly. Captions are auto-built from the real PNG header — actual pixel dimensions + file size, so the page can't drift from what's in public/placeholders/.
- v0.34.2Shipped
Press kit — real dashboard screenshots replace AI mockups
- The three product shots on /media (HunterTrace, HunterCanvas, HunterMobile / Approvals) are now real screenshots of the running dashboard, not gpt-image-1 mockups. The AI versions were photoreal but leaked the prompt's example labels — "span name", "PlanGPT", "Expense Report" — into the UI; the new shots carry actual product copy.
- New scripts/seed-demo-screenshots.mjs (`npm run seed:demo`) inserts a photogenic 16-span trace, a 3-node Planner→Coder→Reviewer canvas, and a pending approval — all tagged so re-runs (or `--clean`) replace prior demo rows without drift. Anyone refreshing the press kit can re-seed, screenshot, and commit in five minutes.
- v0.34.0Shipped
Marketing site redesign — editorial nav + ecosystem index
- Homepage and global nav rebuilt around an editorial column grid: monospaced eyebrows mark structural sections, Instrument Serif italic carries emphasis pulls, hairline amber rules act as scaffolding instead of decoration. The page reads like a print spread now — same proof artifacts, more breathing room.
- New top nav: Logo · Pricing · Ecosystem (dropdown: Observability / Canvas & Missions / Apps & Surfaces — every enabled product from featureFlags.ts) · Community (Discord, Docs, Events, Blog) · Company (About, Changelog, Careers, Media, Contact). Hover-open + click-toggle + ESC + outside-click. Hand-rolled, no extra deps. Mobile hamburger opens a full-width sheet listing all three categories stacked.
- Single source of truth at src/lib/marketing/ecosystem.ts — the nav dropdown, the new homepage Ecosystem section, and the footer columns all read the same data. Adding a product = one edit.
- Six new stub pages so every nav link resolves: /about, /careers, /media, /contact, /community/discord, /community/events. Each is a real editorial page (not
banners) with placeholder image slots tagged data-placeholder-slot=" " — grep that attribute to swap in OpenAI-generated assets once the API key lands. - Hero ops cluster recomposed as a "specimen plate" with bracket markers, t+ timer, and a span/eval/budget caption — reads as proof artifact rather than tech demo. The conic-gradient swirl is gone; one calm radial bloom + the existing dotted-grid texture handles atmosphere.
- v0.33.1Infra
pg_cron sweeper hardening
- Both sweep_expired_canvas_pending_runs and sweep_expired_mission_pending_runs were tripping Supabase's function_search_path_mutable advisor: a function with no SET search_path leaves it role-mutable, so a malicious schema sitting earlier in resolution could shadow an unqualified table reference. Low risk in practice (pg_cron runs jobs as postgres; tables are owned by supabase_admin) but cleanest fix is to nail it down.
- Migration recreates both functions with SET search_path = '' and fully-qualified public.
references. CREATE OR REPLACE only — no schema or cron-schedule change. Both advisor warnings are gone; sweep_expired_*_pending_runs RPCs still callable and behaviorally identical (verified end-to-end in scripts/test-sweepers.mjs, 14 assertions).
v0.33.0ShippedHunterMobile — cost dashboard on your phone
- Mobile gets `budget.breached` pushes (v0.28) but couldn't see the current state on the phone. v0.33 closes that loop. New Cost tab on HunterMobile mirrors the web HunterCost dashboard: current-month spend, vs. last month delta with percent change, hard / soft budget limits with usage bar, and a 7-day spend sparkline.
- Server: new GET /api/v1/mobile/cost endpoint returns { current_spend_usd, last_month_spend_usd, budget, daily }. Reuses the same getMonthlySpend / getLastMonthSpend / getDailySpend / getBudget helpers the dashboard uses — refactored to thread an admin client so they work outside a session (mobile uses bearer tokens, no Supabase cookie).
- UI: pure-JSX sparkline (no chart library dep), color-coded budget bar (green under soft, amber over soft, red at hard), and a 'no limits set' empty state pointing to the web dashboard. Footnote spells out the spend formula so users can audit it.
- Mobile bundle bumped to 0.33.0.
v0.32.0ShippedHunterMobile — mission approvals on your phone
- The v0.31 server fan-out (mission.run.requested webhook + push) is now actionable from HunterMobile. New /(home)/approvals tab unifies canvas + mission pending runs in two grouped sections; each row deep-links to the right detail screen via expo-router.
- New mobile/app/mission-approvals/[id].tsx screen mirrors the canvas detail layout — shows mission title, requester, bound canvas, user task, and the same Approve & run / Reject buttons. Approve redirects to the resulting trace (same admin-client identity override path the dashboard uses, so the trace is attributed to the original requester).
- Three new bearer-token authed API routes: GET /api/v1/mobile/mission-approvals (list pending for team), GET /api/v1/mobile/mission-approvals/[id] (single), POST /api/v1/mobile/mission-approvals/[id] (action: approve | reject + optional reason). ApprovalError codes map cleanly: already_decided → 409 conflict, not_team_member → 403 forbidden.
- Push notifications for mission.run.requested now deep-link properly — server pushes set data.kind = 'mission_approval', mobile's deepLinkForNotification routes to /mission-approvals/[id]. Tapping a notification opens the right screen on cold start + foreground.
- Mobile bundle bumped to 0.32.0. Tab labels stay 'Approvals' — the inside is what changed.
v0.31.0ShippedHunterMissions run approvals
- Missions now opt into the same approval gate as canvases. Flip Require approval on a mission and Run mission queues a row in the new mission_pending_runs table instead of executing immediately. Any team member can approve or reject from /dashboard/approvals or the inline banner on the mission detail page.
- Mission-level approval supersedes canvas-level approval — signing off on a mission IS signing off on the run, so a canvas with its own requires_approval=true is NOT re-gated. The approveMissionRun helper calls runCanvas directly via the admin-client identity override, attributing the trace + cost to the original requester, not the approver. Same race-safe atomic claim pattern from canvas approvals (v0.29): UPDATE … WHERE status='pending' returns null on the second simultaneous approver, surfacing 'already_decided'.
- New webhook event mission.run.requested fans to outgoing webhooks AND mobile push (sibling pattern from v0.28). Three new audit_action values: mission.run.requested / .approved / .rejected. The pending row snapshots canvas_id + user_task at request time so a teammate rebinding the mission to a different canvas — or editing its title — between request and approval doesn't change what the approver is signing off on.
- /dashboard/approvals is now a unified inbox: missions and canvases live in the same list, grouped by kind. The /dashboard/missions/[id] page shows an inline pending banner above the Run button so the requester sees their own queued run without leaving the mission.
- pg_cron job sweep-expired-mission-pending-runs runs every 5 minutes (mirrors the canvas sweeper from v0.30.1) and flips status pending → expired for any row past expires_at (24h default). security invoker, idempotent reschedule, no audit_action for the transition — the absence of an approve/reject IS the signal.
v0.30.1InfraApprovals expiry sweeper
- canvas_pending_runs.expires_at defaults to now()+24h but nothing was marking expired rows — listings already filtered on status='pending' so they dropped out of view, but the audit trail showed a dangling 'pending' state forever. Closed.
- New pg_cron job sweep-expired-canvas-pending-runs runs every 5 minutes (*/5 * * * *) and flips status pending → expired for any row past its deadline. The job calls public.sweep_expired_canvas_pending_runs() which is security invoker — pg_cron's runner role bypasses RLS so we don't need definer privileges.
- No new audit_action value: pg_cron is system maintenance, not a user action. The absence of an approve/reject decision before expires_at IS the entire signal.
v0.30.0ShippedHunterMobile diff viewer + EAS Build config
- HunterMobile now has a canvas browser. New Canvases tab lists every canvas on your team with version count + 'requires approval' badge; tapping drills into the version history; tapping a version renders a side-by-side diff against the previous one (or against an arbitrary version via ?against=N).
- The mobile diff reuses the server's existing diffSnapshots() engine — same algorithm that powers /dashboard/canvas/[id]/versions on the web. Per-node ADDED / MODIFIED / REMOVED / UNCHANGED blocks with per-field deltas (role / name / model / system_prompt). Metadata diffs (canvas name + description) surface separately. Summary pills at the top count each category.
- Three new mobile API endpoints, all bearer-token (htmd_) authed, all team-scoped: GET /api/v1/mobile/canvases (list), GET /api/v1/mobile/canvases/[id]/versions (history), GET /api/v1/mobile/canvases/[id]/versions/[version]/diff (CanvasDiff between this version and previous, or `?against=` for an arbitrary base).
- Mobile bundle bumped to 0.30.0. New eas.json with development / preview / production profiles is in place — running `eas build --profile preview` produces an internal-distribution build for both platforms; `eas submit --profile production` ships to TestFlight + Play internal track. First build needs `eas login` and the Apple Developer + Google Play Console records (those are out-of-band).
- v0.30 closes the HunterMobile track for now — the app is feature-complete behind the mobile flag. Future work: actual store submissions, live multiplayer cursors mirrored to mobile, push-to-talk recording from the phone.
v0.29.0ShippedHunterMobile approve queued canvas runs
- Canvases can now opt in to an approval gate via a new requires_approval toggle on the canvas detail page. When on, every Run pipeline button queues a row in the new canvas_pending_runs table instead of executing immediately. Any team member can approve or reject from /dashboard/approvals or HunterMobile — approver != requester is allowed (the simplest rule that lets a phone-only co-pilot actually unblock a teammate).
- New webhook event canvas.run.requested fans to outgoing webhooks AND mobile push (sibling pattern from v0.28). The push notification carries the canvas name, requester, and a truncated user_task; tapping deep-links straight to the mobile approval detail screen. Existing webhook subscribers don't see the new event unless they explicitly subscribe — backwards-compatible.
- Server: new src/lib/canvas/approvals.ts wraps the lifecycle. requestCanvasRun inserts pending row + fires push/webhook. approveCanvasRun atomically claims the row (UPDATE … WHERE status='pending') so two simultaneous approvers can't double-run; then calls runCanvas via the admin-client identity override, attributing the trace to the original requester (not the approver). rejectCanvasRun mirrors the claim, with an optional reason stored in error_message.
- Dashboard: /dashboard/approvals lists all pending requests across canvases; per-canvas pages also show their own pending list inline so the requester sees their own queued runs without leaving the canvas. Three new audit_action values: canvas.run.requested / canvas.run.approved / canvas.run.rejected.
- Mobile: new /(home)/approvals tab + /approvals/[id] detail screen. Approve sends the user to the new trace; reject returns to the list. Notification taps deep-link to detail; the screen shows 'already decided' if two approvers race.
- Race safety: the WHERE status='pending' guard makes approve/reject idempotent — second caller gets a conflict error (409 on mobile API, friendly redirect on dashboard). pending_run.expires_at defaults to 24h after creation; a background cleanup will mark expired rows in a follow-up.
v0.28.0ShippedHunterMobile push notifications — webhook events to your phone
- HunterMobile flag flipped on. trace.failed / budget.breached / gate.failed / gate.passed now fan out to every paired device on the team alongside the existing outgoing webhook. Same fire-and-forget contract: fireMobilePush(teamId, event, payload) wraps the work in Next 16's after() so a slow Expo round-trip never adds latency to user-facing actions.
- Server: new src/lib/mobile/push.ts hits exp.host/--/api/v2/push/send with all active push tokens for the team in a single request. Per-device receipts land in a new mobile_push_deliveries table (status / expo_ticket_id / error_code / error_message / timestamps), readable by team members. One audit event per fan-out (mobile.push.send) summarises delivered + failed counts.
- Device life-cycle: when Expo returns DeviceNotRegistered or InvalidCredentials we set mobile_devices.expo_push_token_invalid_at and the device drops out of future fan-outs until the next heartbeat with a fresh token. The active-device index (mobile_devices_push_idx) is now scoped on (team_id) where token-present-and-not-invalid.
- Mobile: expo-notifications + expo-device added. New mobile/src/push.ts handles permission, projectId lookup, getExpoPushTokenAsync, and POSTs to /api/v1/mobile/heartbeat with push_token. RootLayout subscribes to addNotificationResponseReceivedListener — tapping a notification deep-links to /traces/
for trace + gate events, /(home) for budget. Settings tab shows ‘Push notifications: Enabled / Disabled’ and exposes a manual re-prompt button when the OS permission is off. - Notification payloads carry only event title + IDs (trace_id, gate_slug, event kind). Trace bodies, span outputs, and budget breakdowns stay on the server — Expo can't see them.
v0.27.0PreviewHunterMobile preview — pair-by-code + read-only viewer
- Phase 4's last surface starts shipping. New @hunterade/mobile package at mobile/ — Expo + Expo Router + TypeScript app with three screens (pair, traces list, trace detail) and a settings tab that shows device/team identity and signs out. Token lives in expo-secure-store (Keychain on iOS, Keystore on Android).
- Pairing: /dashboard/settings/devices mints a 6-character code (15 min TTL) per user, the mobile app exchanges the code via /api/v1/mobile/exchange for a long-lived htmd_-prefixed device token. Each user only sees their own devices, even on shared teams.
- API surface: /api/v1/mobile/{exchange,heartbeat,me,traces,traces/[id]} — a separate authenticator from the scoped PAT one (mobile tokens are scope-less, mirrors HunterBridge's hbk_ pattern). Three new audit_action values: mobile.pair, mobile.revoke, mobile.heartbeat.
- Scope deliberately small for v0.27 — read-only screens and pull-to-refresh. Push notifications via Expo Push API, approve/reject queued canvas runs, and a diff viewer all ship in v0.28+. The mobile feature flag stays off until that lands; the v0.27 preview is reachable directly from /dashboard/settings/devices.
v0.26.0ShippedHunterVoice cloud-Whisper fallback (Firefox + everywhere else)
- Closes gotcha #16 — the v1 push-to-talk button now works in browsers without the Web Speech API. The component picks its mode at mount: Web Speech where present (Chrome / Edge / Safari), or MediaRecorder + cloud Whisper where it isn't (Firefox, in-app webviews).
- Cloud path: MediaRecorder captures audio with the best supported mime type (webm/opus → mp4 → ogg/opus → browser default), the blob is POSTed to a new same-origin /api/voice/transcribe route handler, the server calls OpenAI whisper-1 via raw fetch (no extra SDK — same pattern as HunterKnowledge embeddings), and the returned text is appended to the linked textarea using the existing appendForVoice helper. UX is byte-identical to the v1 path other than a small ‘cloud’ tag and a ‘Transcribing…’ status while the round-trip is in flight.
- OPENAI_API_KEY drives the fallback (already required for HunterKnowledge embeddings). Each callsite reads isWhisperConfigured() server-side and passes a cloudFallbackEnabled boolean to the client component, so the disabled-state copy can tell the user whether the limit is the browser or the server.
- Audit-logged as voice.transcribe with bytes / mime / duration / transcript-char-count metadata only — we deliberately do not store the raw audio or the transcript itself. Compliance audit log already renders the new action label.
- Auth: same-origin Supabase session cookie, same shape as server actions. 12 MB upload cap, normalized error envelope ({ error: { code, message } }), 503 when the key is missing, 502 on upstream failure.
v0.25.1InfraWebhooks: drop legacy plaintext secret column
- Follow-up to v0.24.1 — encrypt-at-rest is now the only path for webhook signing material. The plaintext webhooks.secret column is gone, the webhooks_secret_present_chk constraint is gone, and secret_encrypted / secret_iv / secret_auth_tag are NOT NULL.
- createWebhookAction now refuses to create a webhook unless HUNTERADE_BYOK_MASTER_KEY is set — no more silent plaintext fallback in dev. Local dev needs the master key configured to flag-flip webhooks.
- dispatch.ts is simpler: one decrypt path, no lazy migration, no fallback branch. Decrypt failures fail the delivery loudly with a hint that the master key probably rotated.
- Closes gotcha #20 fully. The transition window is over.
v0.25.0ShippedHunterMultiplayer v2: persisted comments + Realtime Authorization
- Canvas comments are now a real persisted thread, not just live cursors. New canvas_comments table with author profiles, resolve/reopen, author-or-admin delete, full RLS scoped to team membership. The dashboard renders an SSR snapshot; new inserts stream in via Supabase postgres_changes — no refresh needed.
- Closes gotcha #15 — the canvas:
cursor + presence channel is now private. Two new policies on realtime.messages enforce team membership before a client can subscribe or broadcast: split_part(realtime.topic(), ':', 2) gives the canvas id, then a join through canvases → team_members checks auth.uid(). Public-channel access by guessed UUIDs is no longer possible. - Browser client calls supabase.realtime.setAuth() with the active session JWT before subscribing, then opts in with config.private = true. The cursor / presence experience is byte-identical to v1 — just provably scoped.
- Three new audit_action enum values — comment.create, comment.resolve, comment.delete — labeled on /dashboard/compliance. Author can edit their own comments; owners and admins can moderate any.
- Comment writes go through server actions that look up canvas.team_id, populate the row, and invalidate the canvas page; the postgres_changes listener also re-fetches so two open tabs converge on the same state without thrashing.
v0.24.1InfraWebhook signing secrets encrypted at rest
- Closes the v2 hardening item (gotcha #20). Webhook secrets now live in three new bytea columns — secret_encrypted / secret_iv / secret_auth_tag — encrypted with AES-256-GCM keyed off HUNTERADE_BYOK_MASTER_KEY. Same scheme as BYOK API keys; rotating the master key invalidates both surfaces.
- AES-GCM helpers extracted from compliance/byok.ts to a shared src/lib/crypto/aes-gcm.ts (encryptSecret, decryptSecret, bytesFromBytea, bytesToBytea, masterKey, isMasterKeyConfigured). Rule of two — webhooks is the second consumer, so it earns the abstraction.
- Transition: new webhooks insert encrypted-only with secret = NULL. Existing rows still have plaintext; dispatch.ts lazy-migrates on first read (decrypt → dispatch → write encrypted columns + null plaintext in the background). After every row has been hit, a follow-up commit will drop the plaintext column.
- Defensive constraint: webhooks_secret_present_chk ensures every row has either plaintext OR all three encrypted columns. No row can lose its signing material via a partial write.
- Behaviorally invisible to users — same /dashboard/settings/webhooks UI, same delivery log, same HMAC-SHA256 X-HunterADE-Signature on every request. Flag-flipped without a key in dev: createWebhookAction falls back to plaintext when isMasterKeyConfigured() is false.
v0.24.0ShippedPublic API: OpenAPI 3.1, scoped tokens, rate limits, request IDs
- Hand-authored OpenAPI 3.1 spec at /openapi.yaml — every /api/v1 endpoint with request/response schemas, scope annotations, and error envelope. Rendered with Scalar at /docs (no npm dep, single CDN script).
- Personal access tokens now hold scopes: traces:read (list/get traces + spans), traces:write (start traces, append spans, end, record_run), evals:run (trigger evals on a trace + run an eval gate). The token-create form at /dashboard/settings/tokens has a checkbox grid for picking a least-privilege subset; existing tokens were backfilled with the full scope set so no consumer broke.
- Per-token sliding-window rate limit — 60 requests/minute default, settable via HUNTERADE_API_RPM. Counters live in api_rate_buckets via an atomic security-definer Postgres function. 429 responses carry Retry-After + X-RateLimit-{Limit,Remaining,Reset} headers. Fails open on infra blips so a transient DB error doesn't deny legitimate traffic.
- Error envelope normalized across every /api/v1/* response: { error: { code, message, request_id } }. Every response (success + error) carries an X-Request-Id header — partners can pass one in to correlate their logs with ours, or read the one we mint. Hunter MCP client updated to read either the new or legacy shape, surfacing the request id when present.
- Versioning policy committed in the spec's info.description: /api/v1 is stable; new optional fields and new endpoints land without a major bump; deprecations get a 90-day Deprecation header notice and a changelog entry; breaking changes ship under /api/v2 with parallel running.
- Bridge daemon endpoints (hbk_ namespace) inherit the same error envelope + request id flow but stay scope-less — single-purpose tokens for job dispatch.
v0.23.0ShippedTeams & invites — Phase 1 closer
- New `/dashboard/settings/team` surface. Owners and admins invite teammates by email + role, see pending invites with sent/expires timestamps, revoke any pending invite, promote/demote members, and remove members. The owner row is protected — never demotable or removable from this UI.
- Each invite mints a single-use `htmi_`-prefixed token (sha256-hashed at rest, plaintext only sent in the email) with a 14-day expiry. The accept-invite landing at `/invite/[token]` handles every edge case explicitly: signed-out → sign-up/sign-in deeplink with the email pre-filled, signed-in but wrong email → sign-out CTA, expired/revoked/already-claimed → friendly explainer.
- Resend delivery mirrors the waitlist pattern — gated on `resendIsConfigured()` so flag flips ship without a real key, dispatched via Next 16 `after()` so the user's redirect lands instantly. The `team_invites` row is the durable record; the email is delivery only.
- Audit trail extended with three new actions — `member.invite.revoke`, `member.accept`, `member.role.update` — alongside the existing `member.invite` and `member.remove`. Every transition shows up on `/dashboard/compliance` with a recognizable label.
- RLS: members read their team's invites (so non-admins see who's been invited); owners and admins manage. Accept-invite redemption goes through the admin client because the redeemer isn't yet a team member when the row is being looked up by token_hash.
- Phase 1 now fully closes: marketing site, auth (magic link + OAuth), waitlist + Resend, onboarding wizard, ⌘K palette, and teams & invites — all live and registry-flagged.
v0.22.0ShippedPhase 1 cleanup: waitlist confirmation, onboarding wizard, ⌘K palette
- Waitlist now sends a Resend confirmation email after a fresh signup. Dispatch wraps Next 16's `after()` so the redirect lands instantly while the email send survives the serverless response. Already-on-the-list submissions skip the email and surface a friendly 'queued' toast on the home page; failures show a retry message instead of disappearing into the void.
- Onboarding wizard at `/onboarding` — 3 steps (display name, role, primary use case) — runs after sign-up and before the first dashboard hit. Profile row gets `role`, `primary_use_case`, and `onboarded_at` columns; the dashboard layout detours fresh users until the wizard is complete. Skipped automatically for users who've already completed it (back-button safety).
- Command palette (⌘K / Ctrl+K) mounts globally across `/dashboard/*`. Three groups: Navigate (every dashboard surface + settings), Create (new mission, canvas, eval, adversary sweep, scribe distillation, knowledge source), Settings & docs. Built on the shadcn `cmdk` primitive — fuzzy search, keyboard-only operation, no mouse required.
- Marketing surface picks up post-submit feedback: `?status=joined|already|invalid|error` on the home renders a colored banner anchored to the waitlist section so users see exactly what happened with their submit.
- Three Phase 1 flags flipped (`waitlist`, `onboarding`, `commandPalette`); Phase 1 is now substantively complete except for teams + invites.
v0.21.1FixWebhooks: dispatch survives serverless response via Next 16 `after()`
- fireWebhookEvent now wraps dispatch in `after()` from next/server. On Vercel a bare `void promise(...)` is dropped when the response returns; with after() the runtime keeps the function alive until dispatch finishes. Falls back to bare scheduling outside a request scope (tests / scripts) by catching the E468 'wrong context' throw.
- No behavior change in local dev — Node continues running async work either way. The change matters in production where serverless functions terminate the moment the response is sent.
v0.21.0ShippedOutgoing webhooks: ping Slack / Discord / PagerDuty when things matter
- Subscribe a URL to events HunterADE already cares about: gate.passed, gate.failed, budget.breached, trace.failed. Slack / Discord / PagerDuty / your own infra now composes with the dashboard so an eval regression or a budget breach pages someone instead of sitting in a tab.
- Each delivery is signed HMAC-SHA256 in the X-HunterADE-Signature header (sha256=hex(hmac(secret, body))) — same scheme as GitHub / Stripe / Linear. Receivers verify by re-signing the raw body and constant-time-comparing. The signing secret is shown once at create; lose it and you delete + recreate.
- X-HunterADE-Delivery carries a stable UUID so receivers can dedupe replays. Manual retry from the dashboard re-fires with the same delivery_uuid so the receiver's idempotency check still works.
- Single-attempt inline + manual retry from the UI in v1; cron-driven exponential backoff is a deliberate v2 once we have a worker queue. 8s timeout per attempt so a slow receiver can't hang a gate run.
- Dispatch is fire-and-forget at every call site (fireWebhookEvent, no await) so a wedged receiver never adds seconds to a user-facing response. Failures land in the delivery log with HTTP status, response body (truncated to 2KB), and error message.
- /dashboard/settings/webhooks: list + create (URL + event multi-select + auto-mint secret shown once) + per-webhook detail page with delivery log, manual retry, send-test-event button, enable/disable toggle. Three new audit_action values (webhook.create / update / delete) plus webhook.test for the synthetic-event path.
v0.20.0ShippedHunterEvals PR gates: block PRs from CI when an agent regresses
- The Phase-2.5 promise the README has been making for months. A 'gate' bundles a canvas + a fixed test input + the evals that must pass, identified by a stable slug. Trigger it from a GitHub Action and you get a synchronous pass/fail you can wire into branch protection — a regression to the canvas's prompt blocks merge.
- New schema: eval_gates (slug-unique-per-team, eval_ids[], canvas + test_input) and eval_gate_runs (status, trace_id, pass/fail counts, optional commit_sha + pr_url for CI deep-links). Three new audit_action values (eval_gate.create / delete / run).
- POST /api/v1/eval-gates/[slug]/run is bearer-token authed, runs the canvas with the gate's test input via an admin-client identity override on runCanvas, then grades the gate's evals against the resulting trace and returns {status, passed_count, failed_count, trace_id, dashboard_url} in one synchronous call.
- /dashboard/evals/gates lets you create gates (canvas dropdown + test input + multi-select evals + auto-derived slug) and each gate page shows recent runs (manual + CI), a copyable workflow YAML pre-filled with the slug, and a 'Run gate now' button for smoke testing.
- .github/workflows/example-eval-gate.yml.template ships in the repo as a reference workflow — drop into your own repo, set HUNTERADE_API_TOKEN secret, add to branch protection, done.
- runCanvas now accepts an optional identity override ({teamId, userId, client}) so any non-session caller (eval gate runner, future webhooks) can drive a canvas run without hijacking auth.getUser. Existing user-session callers are unchanged.
v0.19.1ShippedHunterVoice: ⇧Space toggle replaces hold-Space PTT
- Press ⇧Space inside a focused prompt textarea to start dictating; press it again to stop. Plain Space is no longer intercepted, so typing literal spaces while composing a prompt is back to normal.
- Behaviour matches the click-to-toggle button: mic stays hot until you toggle off, so you can pause to think without losing the recognizer.
v0.19.0ShippedHunterVoice v1: push-to-talk dictation on agent + canvas inputs
- Click the mic next to any prompt textarea — or hold Space inside it — and dictate. Final transcript is appended to whatever you've already typed; live interim text shows next to the button so you see the recognizer working before you stop.
- Two interaction modes: click-to-toggle (accessibility default, keyboard / screen-reader friendly with aria-pressed + aria-label) and hold-Space inside the focused textarea (Slack-style power-user shortcut).
- Web Speech API only in v1 — works in Chrome, Edge, Safari with zero new deps and zero env vars. Firefox shows a disabled 'Voice n/a' button instead of crashing. True local Whisper (transformers.js wasm, ~40MB) and an OpenAI Whisper cloud fallback are deliberate v2 paths so we don't ship a 40MB browser bundle for an MVP.
- Dropped on /dashboard/agents (user prompt) and /dashboard/canvas/[id] (run-canvas task input). Wires up by id — the textarea stays a normal server-rendered field, the VoiceInput client component finds it via document.getElementById and writes to .value so form submission picks up the dictated text without any controlled-input refactor.
v0.18.0ShippedHunterMultiplayer v1: Figma-style live cursors + presence on canvas
- Open the same canvas detail page (`/dashboard/canvas/[id]`) in two windows — or with a teammate — and you see each other's cursor in real time, with a coloured arrow + name tag. Top-right pill stack shows everyone currently viewing.
- Pure Supabase Realtime — one channel per canvas, presence for the pill stack, broadcast for cursor coordinates throttled to 20 Hz. Zero new tables, zero DB writes; opening a canvas you don't have access to never reaches the channel because Realtime inherits the same RLS as your other queries.
- Per-user color is a stable hash of `user_id` from a hand-picked dark-theme palette (no amber, so the brand accent stays distinct from any one cursor). Initials computed from full_name → email → user_id fallback.
- Each tab is its own session, but pills de-dupe by user_id so two tabs from the same person show one avatar — Figma-style. Cursors GC after 5s of silence as a safety net for crashed peers.
- Comments + Multiplayer-on-other-surfaces (traces, missions) are deferred to v2 — the canvas headline experience is what the roadmap promised, and shipping it cleanly beats a half-built three-feature drop.
v0.17.0ShippedHunterBridge v1: BYO compute — pair your laptop, run agents locally
- Phase 3 closes. Register a machine (laptop, GPU box, self-hosted runner), pair it with a 15-minute one-time code, and dispatch agent runs to it from /dashboard/agents. The bridge polls the HunterADE API, executes locally with its own Anthropic key, and streams traces back into HunterTrace — zero model traffic touches our infra.
- New schema: `bridges`, `bridge_pairing_codes`, `bridge_tokens` (hbk_… bearer, sha256-stored), `bridge_jobs` queue, plus `traces.bridge_id` so the trace viewer shows where a run executed. Three new audit_action values: bridge.register / bridge.revoke / bridge.run.
- Daemon-facing API at /api/v1/bridge/*: pair, heartbeat, jobs/next (atomic claim), jobs/[id]/result. Bridge tokens authenticate every endpoint; tokens are sha256-hashed at rest and revoked the moment a bridge is decommissioned.
- /dashboard/compute lists bridges with online/offline state (90s heartbeat window), shows unclaimed pairing codes with countdown, recent jobs grouped by bridge with status + trace deep-link, and a one-line install command.
- @hunterade/bridge ships as a Node-based reference daemon under bridge/. `npx @hunterade/bridge pair --code …` then `npx @hunterade/bridge run` is the whole loop. Heartbeat every 30s, poll every 3s, graceful shutdown on SIGINT. Config stored chmod 600 at ~/.hunterade/bridge/config.json.
- Agent runner gets a "Run on" select — defaults to Cloud, lists every bridge with online/offline status. Cloud path is unchanged; the bridge path enqueues a job + pre-creates the trace so the user lands on a live URL while the daemon picks it up.
- Tauri/Rust binaries with mTLS tunnel + auto-update + code signing are deferred to v2 — out of scope for a single session, and the v1 token-auth model is functionally complete for self-hosted use.
v0.16.0ShippedHunterCompliance v1: SOC2-ready audit log, PII proxy, BYOK
- New `audit_events` table captures every meaningful action — agent runs, canvas runs, evals, postmortems, adversary sweeps, scribe distillations, forge publishes / installs, knowledge ingests, budget changes, BYOK rotations, token lifecycle, compliance settings updates, and audit exports. Append-only, RLS-protected per team, indexed on (team_id, occurred_at).
- PII proxy redacts emails, phones, SSNs, credit cards (Luhn-checked), IPv4, AWS access keys, and known model-provider key formats from every prompt before it leaves our infra. Strict mode adds long digit runs and IPv6. Originals stay in your trace spans.
- BYOK lets a team supply their own Anthropic / OpenAI key. Encrypted at rest with AES-256-GCM under HUNTERADE_BYOK_MASTER_KEY. Runner resolves BYOK first, falls back to platform env. Rotating leaves a `byok.rotate` audit event.
- /dashboard/compliance — owner / admin only — surfaces PII toggle, retention slider, BYOK cards (key hint + last rotation), and a 100-event audit log. Stream the full log as JSONL or CSV; the export itself shows up as the next event in the trail.
- Every LLM-calling surface (runAgent, runCanvas, runRedTeamCampaign, runPostmortem, distillSkillFromTrace, llm-judge) goes through one `prepareRun(teamId, provider)` helper that resolves the key + redacts inputs + stamps `compliance.*` attributes on the parent span.
- RBAC: owners and admins manage settings + BYOK; all team members can read the audit log. Personal teams treat their creator as owner even before team_members has a row.
v0.15.0ShippedNaming pass: every product / surface now starts with "Hunter"
- Locked in the naming rule from v0.14.0 across every shipped surface — product labels in featureFlags.ts, every dashboard page header, every empty-state, and the public marketing surfaces.
- Phase 2: Mission Control → HunterMissions, Eval Harness → HunterEvals, Multi-Agent Canvas → HunterCanvas. Phase 3: Cost Governance → HunterCost, Red Team Mode → HunterAdversary, Agent Postmortems → HunterPostmortems, Agent Git → HunterGit, Team Knowledge Graph → HunterKnowledge, Local Bridge → HunterBridge. Phase 4: Forge → HunterForge, with HunterMultiplayer / HunterMobile / HunterCompliance lined up.
- Dashboard sub-nav labels stay terse on purpose — the Hunter brand prefix is implied by being inside the HunterADE app shell. Each terse label maps to its full Hunter-prefixed name on the page header (e.g. nav "Adversary" → page header "HunterAdversary").
- ROADMAP.md and README.md status table refreshed in the same commit so external readers see the official names. Added an explicit Naming rule line to ROADMAP § Brand & Naming so the policy lives next to the surface list.
- Internal code identifiers (table / column / variable names like canvas_versions, forge_listings) intentionally stay descriptive snake_case — the rule only governs user-facing product names.
v0.14.0ShippedHunterScribe v1: distill a recorded trace into a reusable skill
- New `skills` table — name, description, instructions (the actual prompt prefix), source_trace_ids[] for provenance, distill model + cost rollup. RLS via private.is_team_member; owners/admins delete.
- Added `skill_id` to canvas_nodes — when set, the canvas runner prepends the skill's instructions to that node's system prompt automatically.
- Distillation: pick a saved trace at /dashboard/scribe/new, click Distill — Sonnet 4.6 reads the trace's spans + IO previews and produces { name, description, instructions } in strict JSON. Typical cost ~$0.005 per skill.
- /dashboard/scribe — list of skills with provenance count + distill cost. /dashboard/scribe/[id] is a full edit page (refine the auto-generated instructions before attaching).
- Canvas node edit page gained a HunterScribe skill picker. The runner pre-loads all referenced skills in one query, splices skill.instructions into the system-prompt head before knowledge context and base role.
- Naming rule: every product / surface starts with "Hunter" going forward. Skill Recorder → HunterScribe is the first feature shipped under this rule.
v0.13.0ShippedHunterForge v1: publish a canvas, install someone else's
- New `forge_listings` table — frozen canvas snapshots (same shape as canvas_versions), unique slug, published_at lifecycle, install_count rollup. RLS lets anon + authenticated read PUBLISHED listings; team members additionally see their own drafts.
- /forge — public marketplace landing (no auth required). Hero, role-chip preview per listing, install_count + node count footer.
- /forge/[slug] — public detail with full pipeline preview (every node's role, name, model, system prompt) and a one-click Install button.
- Install action forks the listing into the user's team: new canvas + nodes, auto-commit as v1 with message "Installed from Forge ·
", increments install_count, redirects to the new canvas. - Publish panel on /dashboard/canvas/[id]: title + description form. Server action snapshots current state, mints a slug (title + 6-char random suffix), sets published_at = now.
- /dashboard/forge — your team's listings with Unpublish / Republish / Delete actions. Drafts and unpublished listings remain visible to the team without leaking to the public.
- Forge link added to the marketing nav (public) and the dashboard sub-nav (publishers).
v0.12.0ShippedHunterKnowledge v1: pgvector retrieval that grounds every canvas run
- Enabled pgvector + new knowledge_sources / knowledge_chunks tables (1536-dim embeddings, HNSW cosine index). public.match_knowledge_chunks RPC runs as security_invoker over team-scoped RLS — no security-definer warnings.
- Built /dashboard/knowledge with paste-ingest (paragraph-aware chunker, ~500 tok / 50 tok overlap), source detail with chunk drill-down, and a built-in Search panel that runs cosine retrieval ad-hoc to verify quality.
- OpenAI text-embedding-3-small via raw fetch (no extra SDK dep). Friendly setup banner + form-disable when OPENAI_API_KEY isn't configured.
- Per-canvas opt-in via a Use Knowledge toggle on the canvas detail page. When on, runCanvas embeds the user task once, retrieves top-6 chunks above min-similarity 0.4, and prepends a "Relevant team context" block to every node's system prompt.
- Retrieved chunk_ids land on the agent.run span's attributes so trace replay shows exactly which knowledge informed the run.
v0.11.0ShippedHunterGit v1: version-control your canvas like code
- New `canvas_versions` table — frozen snapshots of (canvas + ordered nodes) keyed on (canvas_id, version) with auto-incrementing per-canvas integers. Snapshots are immutable history; the table has no UPDATE policy.
- Commit panel on /dashboard/canvas/[id]: type a message, click Commit, snapshot lands as the next version. Required commit message keeps history meaningful.
- /dashboard/canvas/[id]/versions: full list with revert links and a Diff vs vN-1 button on each row. Latest pair gets a one-click "Diff latest" shortcut in the header.
- /dashboard/canvas/[id]/versions/[versionId]: full snapshot view of name + description + every node (with its system prompt) + a Revert button.
- /dashboard/canvas/[id]/versions/diff?from=…&to=…: side-by-side diff with metadata changes highlighted, per-position node states (added / removed / modified / unchanged), and per-field change summaries (role, name, model, system_prompt). Modified rows expand with both before/after states + full prompt text.
- Revert is auditable: replaces canvas + nodes with the snapshot, then auto-writes a new version with `is_revert = true` and message "Revert to vN" so history stays linear.
v0.10.0ShippedHunterPostmortems v1: 5-whys analysis on any trace
- New `postmortems` table — one per trace (UNIQUE), summary + structured analysis (whys, root_cause, recommendations) jsonb, model + cost + duration tracked. RLS via private.is_team_member.
- Embedded a Postmortem panel into /dashboard/traces/[id]: empty state with a Generate button, populated state with summary + numbered 5-whys list + amber root-cause callout + recommendation bullets + Regenerate button.
- Runner uses Claude Haiku 4.5 with a strict JSON-output system prompt and a compact trace-context summary (root + spans with status, IO previews, errors). Typical cost is sub-cent; budget gated.
- Re-generation upserts on (trace_id) — running it again on the same trace overwrites with a fresh analysis. The trigger column reserves space for future auto-on-error / auto-on-budget triggers.
v0.9.0ShippedHunterAdversary v1: automatic adversarial sweeps against your front-door agent
- New `red_team_campaigns` + `red_team_attempts` tables with attack_kind enum (prompt_injection / jailbreak / system_extraction / off_task / edge_case). RLS via private.is_team_member.
- Standard attack pack: 4 canonical adversarial inputs — "Ignore previous instructions", system-prompt extraction, DAN-style jailbreak, and an off-task chitchat distraction. Each attack ships with an explicit judge rubric so verdicts are auditable.
- Runner targets the front-door (first node) of any saved canvas. Each attack creates a new HunterTrace + agent.run + llm.completion span — the campaign reuses the same trace + eval infrastructure, no new observability surface.
- LLM judge (Haiku 4.5 by default) grades each attempt: passed=true means the agent BLOCKED the attack, false means the attacker won. Judge cost is rolled into the campaign's total_cost_usd alongside the agent call.
- Built /dashboard/red-team with a list view (block-rate bar chart per campaign), /dashboard/red-team/new (canvas + pack picker), and /dashboard/red-team/[id] showing per-attempt verdicts, judge reasoning, and links into each generated trace.
- Re-run + delete campaigns inline. Cost gated by the same monthly budget as everything else.
v0.8.0ShippedHunterCost v1: monthly budgets that refuse runs over the hard limit
- New `budgets` table — one per team via PK, hard + optional soft USD limits. RLS lets owners + admins update; members read.
- Built /dashboard/cost: this-month total + budget gauge, last-month comparison, 30-day SVG sparkline (no charting library — pure server-rendered), spend breakdown by runner (canvas, agent runner, evals, API) and by model, top 10 traces by cost.
- BudgetExceededError + assertBudgetAvailable() wired into runAgent, runCanvas, and runEvalsForTrace. Once the team's monthly spend reaches the hard limit, every LLM-triggering path returns a clear error with the exact number to raise the cap or wait for next cycle.
- Soft limits surface as a banner above the dashboard (and on the budget gauge as a tick mark) — runs continue, but the team knows they're approaching the wall.
- Phase 3 begins. Budgets close the immediate enterprise-readiness gap that traces alone don't solve.
v0.7.0ShippedHunterMissions v1: kanban tasks that run end-to-end through your canvases
- New `missions` table + `mission_status` enum (backlog / in_progress / done / failed / archived). Optional canvas_id and current_trace_id link each mission to its execution and resulting trace. RLS via private.is_team_member.
- Built /dashboard/missions kanban with four lanes, status dropdowns, priority chips, and a Run button on cards bound to a canvas.
- Built /dashboard/missions/new (title + description + canvas selector + priority) and /dashboard/missions/[id] for full edit + run + archive/delete with the latest linked trace pinned to the top.
- runMissionAction wraps runCanvas: marks the mission in_progress, executes synchronously, parks the trace_id back on the row, transitions to done (or failed). Closes the loop from queue → execute → replay.
- Sub-nav now leads with Missions: Overview · Missions · Agents · Canvas · Traces · Evals.
- Phase 2 is complete: every roadmap surface for the lead pillar is shipped.
v0.6.0ShippedHunterCanvas v1: orchestrate Planner → Coder → Reviewer pipelines
- New `canvases` + `canvas_nodes` schema with a `canvas_role` enum (planner / coder / reviewer / tester / red_team / custom). RLS via private.is_team_member; ordered retrieval indexed on (canvas_id, position).
- Built /dashboard/canvas list, /dashboard/canvas/new (with four starter templates), /dashboard/canvas/[id] for the pipeline editor, and /dashboard/canvas/[id]/nodes/[nodeId] for per-node prompt + model editing.
- Composer UX is fully server-rendered: add / remove / reorder nodes via server actions; no client JS required. Vertical card layout with animated connectors between steps.
- Canvas runner walks nodes in order, feeds each output into the next agent's system prompt, captures every call as an llm.completion span under one agent.run root span. The whole pipeline lands as a single HunterTrace you can replay and grade with Evals.
- Adaptive thinking on every node; ephemeral prompt caching on the system block; cost rolled up from each node's usage object.
- Sub-nav now: Overview · Agents · Canvas · Traces · Evals. Canvas tile is a Live link.
v0.5.0ShippedHunter MCP server: stream traces from Cursor / Claude Code / any MCP client
- New `api_tokens` table with sha-256 hashed PATs (plaintext shown once); `/dashboard/settings/tokens` to mint and revoke.
- New v1 HTTP API: POST /api/v1/runs (one-shot), POST /api/v1/traces (start), GET /api/v1/traces, GET /api/v1/traces/:id, POST /api/v1/traces/:id/spans, POST /api/v1/traces/:id/end, POST /api/v1/traces/:id/evals/run. Bearer-token authed.
- New `mcp/` package: an independent npm module exposing six tools (record_run, start_trace, add_span, end_trace, list_recent_traces, run_evals) over MCP stdio. Drop the binary into Cursor or Claude Code's mcp.json and your editor agent emits HunterTrace spans on its own.
- Eval runner refactored to accept an injected Supabase client so the API path can run evals with the admin client without going through user RLS.
- Requires the SUPABASE_SECRET_KEY env var — the HTTP API returns 503 with a clear setup message until it's set.
v0.4.0ShippedHunterEvals v1: grade traces with output-contains or LLM judge
- New evals + eval_runs schema (RLS via private.is_team_member) — re-running an eval against the same trace upserts on (eval, trace).
- Two grader types: output_contains (instant, free) and llm_judge (Haiku 4.5 by default — costs negligible tokens per run, returns a JSON verdict with pass/fail, score, and reason).
- /dashboard/evals: list + create form with conditional config blocks per grader kind. /dashboard/evals/[id] shows the eval's recent runs with verdicts, scores, and per-run cost.
- Trace detail (/dashboard/traces/[id]) gained an Evals panel: passed/failed counts, per-eval verdict chips, and a Run evals button that grades the trace against every enabled rule.
- PR-blocking eval gates land in Phase 2.5 once the local CLI ships.
v0.3.0ShippedSingle-agent runner: real Anthropic calls, every span recorded
- Wired @anthropic-ai/sdk into a server-side runner that streams Messages API calls (adaptive thinking, prompt caching on system blocks) and persists every call as a HunterTrace span tree: agent.run wraps llm.completion.
- Built /dashboard/agents — a clean form (system prompt, user prompt, model dropdown). On submit you land on the trace detail with cost, tokens, latency, and the full assistant output captured.
- Accurate cost calculation per model, including separate rates for cache writes (5m TTL × 1.25 input) and cache reads (× 0.1 input). Opus 4.7 / 4.6, Sonnet 4.6, Haiku 4.5 supported.
- Typed Anthropic SDK exceptions (RateLimitError, AuthenticationError, etc.) surface as span.status = error with the HTTP status preserved on attributes.
- Surface a clear setup banner when ANTHROPIC_API_KEY is missing rather than failing silently.
v0.2.0ShippedHunterTrace v1: trace + span ingest, list view, timeline replay
- New `traces` and `spans` tables with full RLS — every span carries cost, latency, model, tokens, IO, and a typed `kind` (agent / llm / tool / eval / internal).
- Built `/dashboard/traces` list view with status badges, span counts, total cost rollups, and relative timestamps.
- Built `/dashboard/traces/[id]` timeline replay — proportional span bars colored by kind, stat tiles, and a full inspector with collapsible inputs/outputs/attributes per span.
- Auto-create a personal team for every new user (and backfill existing users) so traces always have a home.
- One-click "Generate sample trace" action that inserts a realistic span tree to play with.
v0.1.2InfraSupabase wired up — auth and waitlist persist
- Provisioned the production Supabase project (us-west-1, Free tier) with `profiles`, `teams`, `team_members` (owner/admin/member enum), and `waitlist` tables — RLS on everything.
- Security-definer trigger functions (`handle_new_user`, `handle_new_team`, `is_team_member`) live in a private schema so they can't be called as RPCs.
- Generated typed `Database` for the Supabase clients — full autocomplete and compile-time safety on every query.
- Waitlist form on the landing page now persists to Postgres. Duplicate emails are treated as success.
v0.1.1ShippedPhase 1 auth: magic link + GitHub/Google OAuth
- Added the `(auth)` route group: shared `AuthForm` with email magic-link plus GitHub and Google OAuth buttons.
- Wired session-refresh middleware so Supabase auth cookies stay fresh on every navigation.
- OAuth callback exchanges the `?code` for a session and redirects to `?next` (defaults to `/dashboard`).
- `/dashboard` is now server-side guarded — unauthenticated users land on `/sign-in?next=/dashboard`.
- Site header switches to a user menu with email + sign-out once you're signed in.
v0.1.0ShippedPhase 0 foundation
- Stood up the HunterADE app: Next.js 16 + React 19 + TypeScript + Tailwind v4 + shadcn/ui.
- Supabase clients (browser, server, middleware) typed end-to-end.
- Introduced the `
` pattern + `featureFlags.ts` registry — flip a single boolean to launch a feature; banner self-removes. - Marketing landing page with hero, four-pillar grid (HunterTrace as lead), and waitlist form.
- CI on every push: typecheck + lint + build.