-
v1.6.13 Stable
released this
2026-09-18 03:22:49 +00:00 | 188 commits to main since this releaseThe pipelines now stop and ask at the two points where being wrong is cheap to fix, and stop paying for reviews the diff does not need.
Intake actually asks. The
default8-node template declaredagenthub stage intakefor its intake node — a stage report with no work attached — so "intake" was a label a run walked past without ever asking a question. It now declares/superpowers:brainstorming(and detects it; that rule moves offplan), and bothship-featureandship-feature-lanemake the brainstorm mandatory, asked withAskUserQuestionand waited on, never answered on the user's behalf.The plan is approved before it is code. After it is written and adversarially challenged, it goes to the user: approve / revise / change approach. Implementation does not start without that approval, and work that turns out to need a different approach comes back for a fresh one.
Review is scoped, native, and a loop. Reviewers are picked from
git diff --name-only: Claude Code's owncode-reviewalways; a domain reviewer only for a layer the diff actually touched, and only once the change is big enough to have seams. Review ends on a clean pass over the current diff, not on one pass having happened.The gate asks the user, and a NO-GO goes back by size. Nothing is claimed done — and in the lane pipeline nothing is published, publishing being outward-facing — until the user accepts. A defect returns to implement; a wrong approach returns to plan. Nothing carries a NO-GO forward with a note about it.
A real stall, fixed.
ship-featurehad no waiting rule, and a session sitting at the gate invented one withScheduleWakeup— a/loop-only primitive that paces nothing here and is refused outright whenautomode cannot reach its safety classifier. The rule the lane skill already had now exists in both.Cost, measured in what each agent is for. The suite run leaves its agent (nothing is judged there, so nothing is delegated), and
backend-reviewerdrops from opus to sonnet like its frontend twin — both read a scoped diff against a fixed checklist, and the senior gate above them is still opus.Also:
KEEP_RETIRED_ROOTSdrops to 1, so a plugin-cache install keeps the running build plus one rollback copy instead of two (~130 MB each). And a sweep of the docs skill:doc-maptold agents not to recreate the removed translations and then, three lines later, to mirror every README change into them; the mapping still carried+VN+CNand the punctuation left behind; Procedure jumped 2 → 6; Verify requiredscripts/doc-coverage.sh, which does not exist in this repo.Downloads
-
v1.6.12 Stable
released this
2026-09-18 02:45:50 +00:00 | 190 commits to main since this releaseRemoving a lane now deletes only the dashboard's record of it.
A lane's worktree is the user's, not the dashboard's.
removeused to tear down what the lane pointed at:git worktree remove --force, a branch delete, and a drop of the lane's own database. One mis-click on a row cost a whole branch's unpushed code, for a row that was the only thing AgentHub actually owned. It now stops the run and the stack, clears AgentHub's own runtime bookkeeping underLANES_ROOT/.state/lane<slot>/, and deletes the row. The working tree, its branch, git's worktree records and the database stay exactly where they are — deleting them is yours to do by hand, when you mean to.Fixes #28 — "Lane action failed: lane is not listed as a worktree in …". Removal used to route through
assertDestroyable, whose third check demands the lane's directory appear ingit worktree list; a managed lane git no longer listed answeredENOTWORKTREEand could never be dropped from the dashboard at all. Removal no longer asks git anything, so no preflight blocker stops it, and the unpushed-commits force-gate applies toresetalone — nothingremovedoes can discard a commit.The UI follows: one label for both lane kinds ("Delete lane record"), copy that says what survives, and no Force checkbox on removal.
removeWorktree/removeLaneDataremain as guarded primitives; no route calls them any more.Downloads
-
v1.6.11 Stable
released this
2026-09-17 16:20:19 +00:00 | 192 commits to main since this releaseFixes the quota check for the account you are actually logged into, and stops making you ask one row at a time.
The live account is read from the CLI. An OAuth refresh token is single use, so every refresh Claude Code performs on its own account retires the copy stored in that account's saved profile — which made the profile you would try first the one guaranteed to fail, with a raw
invalid_grant. The usage call now matches a profile against the live credentials and uses what the CLI is holding. That token is never refreshed and.credentials.jsonis never written: rotating it would log you out of your own terminal.Clearer answers for the two remaining failures. An expired live token says to use Claude Code once so the CLI refreshes it; a genuinely spent refresh token says to activate the account and save the profile again, instead of echoing Anthropic's 400.
Opening the Profiles modal now loads every account's quota at once. Comparing accounts is the only reason the panel exists. Credentials are still not rewritten on a whim: the live account costs a plain read, and any other profile is refreshed only once its token has actually expired, which leaves it valid for hours of further opens. Each row resolves on its own, so one superseded account still lets the rest report.
Downloads
-
v1.6.10 Stable
released this
2026-09-17 15:22:15 +00:00 | 194 commits to main since this releasePer-profile Claude quota in the Profiles modal, plus three fixes where a write reached disk but did not look like it had.
Check quota per auth profile (#19) — each saved profile now reports how much of its account's quota is spent, which is the only number that decides which one is worth switching to. It is a button, never a poll: a non-active profile's token is normally expired, so answering refreshes it, and a refresh rotates the credentials written back to disk. The token is sent to Anthropic and nowhere else; what leaves the server is two percentages and two reset times.
A settings patch that changes nothing now writes nothing (#20) — opening the config panel used to take a timestamped backup even when the patch was a no-op, quietly growing a backup directory inside every lane. A lane's git exclude also picks up
.claude/.cc-config-backups/.A lane's router pick stops reverting (#21) — the apply route was the only mutating lane route that never broadcast its lane, so the client's cached row kept the old profile: the picker looked right until you switched lanes and back. Also guarded against an apply that resolves after you have moved on painting its result onto the lane now on screen.
Add-lane closes itself (#27) — worktree mode left the dialog up after a clean setup with a dead confirm button. It now closes when nothing failed, and keeps the summary with a real Close when something did.
Downloads
-
released this
2026-09-17 09:17:53 +00:00 | 196 commits to main since this releaseA pipeline run is what you declared, and reload types two commands, not one
A backwards DETECTION no longer opens a new pipeline run.
runsis the denominator every rate on the Workflows page's pass-rate panel is read against, and until now any backwards move started one. Stage detection bounces by design — a single feature readsimplement → tests → implementas the session edits, runs the suite and edits again — so one feature was recorded as five or six runs, and a lane in constant use reported a handful of passes scattered across dozens of phantom ones. A backwards move now opens a run only when it is declared (agenthub stage, or a codex lane's ingest-driven declaration); a backwards detection continues the run in flight. Reaching the pipeline's last node still closes the run for either, since work afterdoneis new work however it was observed. Replayed over this repo's own lane, the rule takes a 26-run history down to the 5 features that actually shipped through it.Nothing else about the panel moved: a pass is still a declaration, detections still render as the grey "reached, not declared" bar, and the
GET /api/lanes/pipeline-statspayload is unchanged. If your lane's rates read low, that is the honest answer — a session that works without callingagenthub stageleaves detections, not passes./reload-pluginsand/reload-skillsreach a pane as two commands again. They were typed back to back, and Claude Code opens its slash-command menu the moment/is typed, so the Enter that follows lands on that menu instead of submitting. The second command was appended to the line still sitting in the composer and the pane submitted the single string/reload-plugins/reload-skills— which Claude Code runs as/reload-pluginswith an argument, so skills were never reloaded and a stray prompt turn was left in the scrollback. Reproduced and fixed against a live pane: the two sends are now a second apart (SETTLE_MSinserver/lib/cc-reload.js), which makesreloadOpenSessionsasync rather than block the event loop for it, and the detached Update all worker got the same pause.POST /api/cc-config/reloadtherefore takes about a second longer to answer.Downloads
-
released this
2026-09-17 08:11:04 +00:00 | 198 commits to main since this releaseDrag your lanes into order, name them, and read the diff
The lane strip is yours to arrange. Drag a tile onto another to move it there, or press Alt+←/→ with a tile focused — the keyboard path, since HTML5 drag-and-drop has no touch gesture and does not auto-scroll an overflowing strip. The order is a per-viewer preference, not a lane fact: it persists to
localStorage(agenthub.workspace.laneOrder) exactly like the split-view layout beside it and writes nothing server-side, soGET /api/lanesandagenthub laneskeep answering in id order. A lane the stored order has never seen lands at the end rather than wherever a stale index would put it; a stored id whose lane is gone is skipped.A lane can be renamed in place. Click its name in the detail header (a pencil appears on hover) — Enter saves, Escape and clicking away cancel, and an empty name clears the title, which puts the lane's
cwdback in its place. Renaming is display-only: a managed lane's branch name was slugified from its title once, at creation."Lane 23 ·" is gone. The word cost a third of the tile's top row and said nothing; the bare
#23stays, because that number is how the CLI addresses a lane (agenthub stage --lane 23).The uncommitted-files tooltip is now a real panel.
GET /api/lanes/:id/gitreturnsfilesas{path, status, added, deleted}records instead of raw porcelain lines, with per-file line deltas from one extragit diff --numstat HEAD(staged and unstaged together). Hover — or focus, or tap — theN modified · N untrackedtext on a lane card and you get one row per file: the status letter colour-coded, the directory truncated before the filename ever is, and each row's+N −Maligned under a total. It is portalled to the document body, so the Workspace's own scroll box cannot clip it, and it stays open while the pointer travels into it.added/deletedarenullwhere git has no delta to report — an untracked file (its content is deliberately not read off disk; a lane mid-build can have a 100 MB artifact), a binary file, a rename, or a repo with no commit to diff against.Bad input to
PATCH /api/lanes/:idis a 400, not a 500. Renaming made a lane column reachable from a text field for the first time, so the guard is column-wide rather than a special case: any non-scalar patch value (linksexcepted — it is stored as JSON) is rejected withEBADFIELD, and theSQLITE_CONSTRAINTfamily maps to 400 as well. Atitleis trimmed and capped at 200 characters, andnullclears it rather than violating the NOT NULL.Upgrade note
GET /api/lanes/:id/git'sfileschanged shape — it was an array of rawgit status --porcelainstrings and is now an array of records. Anything parsing those strings needs updating; nothing in AgentHub itself did outside the lane card.Downloads
-
released this
2026-09-17 06:27:13 +00:00 | 200 commits to main since this releaseThe files behind a lane's counts, and a header-free Workspace
Lane git facts now name the files, not just count them.
GET /api/lanes/:id/gitreturnsfiles— the rawgit status --porcelainlines thedirty/untrackedcounts were already parsed from — and the lane card hovers them as a tooltip on itsN modified · N untrackedtext. The list is capped at 20 (a lane mid-npm installwould otherwise ship thousands of paths through a polled endpoint) and the tooltip appends… +Nwhen the cap bit; the counts themselves are never capped. No new endpoint and no extra subprocess: those lines were being counted and thrown away.Workspace loses its page header. The title and the four counters (
lanes,running,needs you,dead) said a second time what the lane strip already shows lane by lane — its own liveness dot, its own ⚠ marker — so they only cost a row of height on a screen whose point is the terminal.GET /api/lanesstill returnscountsfor other callers.Add lane is now the lane strip's first tile instead of a header button — dashed border, no liveness dot — because creating a lane is the same kind of act as picking one, and it reads as the empty slot at the head of the row.
The Tools menu (agents install / mcp sync / sync-base check) moves onto the lane-detail header row, beside the pipeline picker and the Model select. All three of its actions run against one lane's
cwd, so it belongs next to the lane it acts on — and not in Settings, where it would need a lane picker just to say which.docs/LANES.mdwas updated to match (the/gitresponse shape and its cap, and the Workspace anatomy section).Downloads
-
released this
2026-09-17 04:40:09 +00:00 | 203 commits to main since this releaseA leaner run panel and lane detail
Lane card drops the progress bar and its percent — the pipeline map right below it already draws the same number as named, coloured nodes, so the bar was a worse second telling of it.
Split view toggle (Workspace) swaps the "1 pane" / "2 pane" / "4 pane" text buttons for the conventional square / two-column / 2×2-grid icons most apps use for this layout. The words are still there for assistive tech and hover, as
aria-label/title.Run setup merges the fresh-vs-resume source picker onto the same row as Working directory / Model / Permission mode / Thinking effort, instead of a row above them: settings on the left, New session / Resume existing session on the right. The session picker for an active resume still gets its own row, since it only shows up in that one state.
"Run Claude" header goes from a two-row title + wrapped blurb to a single row (smaller icon and title), with the blurb trimmed to one short sentence and hidden below
sm, where it would wrap again anyway.docs/LANES.mdwas updated to match (split-view description, the lane-card field list, andagenthub stage's progress-bar wording).Downloads
-
released this
2026-09-17 03:03:27 +00:00 | 205 commits to main since this releaseA compact lane detail panel
The Workspace lane panel spent four rows saying what fits in two.
Strip tile — the stage badges move onto the id row; the progress bar and percent are gone. The detail panel's pipeline map right below shows the same progress with the stage names attached, so the tile was spending two rows to repeat it worse.
Lane detail — the pipeline picker, stage badges, feature picker, router select and the remove button merge into the single header row instead of a second row under it. The pipeline's name is no longer interpolated into
laneHeadereither: the picker beside it already says it. The git block collapses from four lines to one (branch · head · subject · N modified) and drops the cwd, which the header above it already spells out.AI Router is now labelled Model —
LaneRouterRowmoves out ofLaneCardinto that header row (it is now exported). A finished apply reports as a✓/⚠marker with the message in a tooltip, rather than a wrapped sentence that pushed every row below it down for the life of the selection. A failed apply still reverts the select, same as before.Dropped: the tracker / dev QC / CI wait badge row
Two of those three toggles have no consumer at all — the ticketer and the dev-QC agent are not built — so the badges could never be anything but decoration, and the row cost card height to say nothing. Gone with them:
useLaneIntegrations, theapi.lanes.integrationclient wrapper, and theintegrations.*strings.agenthub lanes integrationandGET /api/lanes/:id/integrations/:nameare untouched — they are now the only readouts, andci_wait's real consumer (agenthub lanes ci status) is unaffected.docs/LANES.mdwas updated to match.Downloads
-
released this
2026-09-16 04:29:34 +00:00 | 207 commits to main since this releaseTest an AI Router before you save it
POST /api/ai-routers/testsends one Anthropic-style message, capped at a single output token, to<baseUrl>/v1/messageswith a 15s timeout — the same wire shape aclaudelane's env keys use, so a router that answers the test is a router the lane can actually talk to.A reachable router is
HTTP 200whatever it replies: the result{ok, status, message}carries the router's own words rather than a verdict of ours, andstatusisnullwhen nothing answered at all. A 401 from the endpoint is a successful test that reports an auth failure, not a failed request.Network errors report
error.cause, because node'sfetchcollapses every transport failure — DNS, refused connection, TLS — into the same useless"fetch failed"string.Security: a stored key only ever goes to the endpoint it was stored against
Sending a blank
apiKeyfalls back to the saved profile's key only whilebaseUrlis unchanged; change the URL and the request is refused withEBADKEY. Without that rule the route would be a way to make the server POST a saved API key to any URL a browser names.Re-point a live lane's AI Router from its card
The lane card's AI Router select switches a running lane through
POST /api/lanes/:id/router/apply— never a lanePATCH, because the database column and the lane's on-disk config have to move together or the row claims a router the lane has never heard of.- A failed apply reverts the select, so the control never shows a router the lane isn't on.
- The select is hidden when
nativeis the only profile — nothing to switch between.
docs/API.mdanddocs/LANES.mdwere updated to match.Model pricing: Claude Opus 5 priced, Sonnet 5 corrected, retired models dropped
This release also carries a pricing fix that landed on
mainbetween 1.6.3 and 1.6.4.- Claude Opus 5 had no pricing row at all, so every token it burned was costed at $0 — the pattern list stopped at the 4.x Opus family and nothing matched
claude-opus-5. It is now priced at 5/25 per MTok, fast mode 10/50, the same shape as Opus 4.8. - Sonnet 5's launch discount expired 2026-08-31 and the discounted rate became the published standard, so the row's 3/15 standard rate started overcharging the day after. 2/10 is now the standard rate and no model ships an introductory rate today.
- Fable / Mythos 5.1 fell through to the
claude-fable-5%row, which caches at $1/MTok against 5.1's $0.25. They get their own rows — and that overlap is only resolvable if the lookup prefers the more specific pattern, somatchPricingnow orders by pattern length descending instead of taking whichever row happened to be inserted first. - Claude 3.x, Opus 4/4.1 and Sonnet 4 are retired from the defaults. Because the startup top-up only ever adds missing rows, they are also pruned once from existing databases, guarded by
PRAGMA user_versionso a model you deliberately re-add in Settings survives later restarts.
Only rates are deleted — recorded token usage is never touched, and Reset Defaults still restores the full current set.
docs/DATABASE.mdwas updated to match.Downloads