Skip to content

v0.40.0 — Linear browser sign-in, Jira sprints, init recovery, the gate proven

Choose a tag to compare

@keparlak keparlak released this 06 Sep 12:07
· 10 commits to main since this release
9f8f20f

A browser sign-in for Linear that works on a bare install, Jira sprints, a baron init that
recovers from a wrong credential, and the gated-transition contract proven against a real classic
workflow.

0.39.0 was tagged but never published to npm. Everything it would have carried is in this release.

Linear: sign in from the browser, no key to paste

baron init --provider linear now offers to sign you in through the browser instead of asking for
a personal API key — through Baron's own public Linear application, so there is nothing to
register. It is the OAuth authorization-code flow with PKCE: no client secret exists anywhere, and
the token exchange is bound to the process that started the sign-in. The access token Linear issues
lasts a day; the refresh token, its expiry and the application id are stored beside it in
.baron/credentials, and the transport renews the token before it expires (or once, when Linear
refuses it) and writes the rotated pair back — from the MCP server and from baron run alike — so
a sign-in outlasts the day. BARON_LINEAR_CLIENT_ID selects another application; set it to empty
to keep pasting a key, which is narrower than any OAuth scope.

Two things the live run taught, both fixed before shipping: Linear matches the redirect URI
against the application's registered list exactly, port included, so Baron listens on a fixed
port (41765, BARON_LINEAR_CALLBACK_PORT moves it, and a port in use names the way out); and the
page the browser lands on after approving now says who signed in and what to do next, instead of
one bare line of text.

Jira stays on the API token: Atlassian's OAuth requires a client secret and offers no PKCE, so a
shipped CLI cannot hold it honestly.

Jira sprints

Sprints on Jira belong to a Scrum board, not to the project, and live on the Jira Software API
rather than the platform one — which is why the adapter shipped with sprints: false. It now
resolves the project's first Scrum board (or the one JIRA_BOARD names, by id or name), lists that
board's sprints as iterations with the active one as @current, moves an issue into a sprint
through the agile API, and filters a query by sprint. The sprint an issue is in is read from Jira's
sprint field, whose id varies per site and is discovered once from the field catalogue. A project
with no Scrum board simply has no sprints.

baron init recovers from a credential the provider refuses

When the provider cannot be read with the credentials just gathered, init says which provider
failed and why, and offers to re-enter that provider's credentials on the spot (current non-secret
values shown so a typo is visible; an empty answer keeps what is there; secrets never echoed),
saves them, and tries again. A --force run, a declined offer, or a second failure stops with
INTROSPECTION_FAILED naming .baron/credentials and the keys to fix. Jira names the site on a
network failure instead of a bare "fetch failed".

Also: init no longer announces "Provisioned N workflow labels" on a provider whose labels exist
by being used. IssuesPort.ensureLabels now resolves to whether anything was provisioned, and the
conformance suite pins the honest answer.

The gate, proven on the classic workflow

A company-managed Jira project on the classic jira workflow gave what the team-managed default
could not: a transition carrying a screen and a status that refuses hops. Through the MCP server,
Resolve without fields was refused with TRANSITION_FIELDS_REQUIRED naming resolution and its
accepted values with nothing written; the retry with fields landed; and a move from Closed was
refused with TRANSITION_NOT_PERMITTED naming Reopened as the one hop allowed. Nine checks, nine
passes, no code change needed.

What was run before publishing

The whole path as a user would — a publish-equivalent tree from a throwaway copy, a fresh
project, a private throwaway repository, init and doctor, every task-* recipe, the MCP
server over JSON-RPC, a headless Claude Code session with the plugin skills, and the Docker image.
The Linear sign-in was then run live against a real workspace: approval, renewal before expiry,
renewal on refusal, a steady-state run that rotated nothing, and a bare install with no
environment at all.