Changelog

Unreleased

not yet deployed

Merged and awaiting deployment.

  • A forward deploy of an existing release now gets the pre-migration snapshot

    Measure the step, not the label

    fixed deploy operators

    deploy.sh --version was treated as a rollback, so shipping an already-cut release forward applied its migrations with no pre-migration snapshot and no honest rollback. The snapshot now keys on the migrations the deploy actually applies.

    #3690 · 2026-10-20

  • A browser's slot and identity stay held until its end is confirmed

    Nothing is free until it is seen gone

    fixed node operators developers

    If a client disconnected while a session was ending, the node could count that browser's slot as free before the browser was confirmed gone, and a retried end could let the identity go too early. Both now wait for a confirmed end.

    #3704 · 2026-10-17

  • Control ends abandoned sessions and sees which ends are unconfirmed

    Say what you see

    fixed control operators

    A session the node has abandoned for inactivity is now ended by control instead of staying live while its lease renews. Its identity stays held until the node confirms its browser is gone.

    #3707 · 2026-10-20

v2026.10.17.3

2026-10-17
  • An ended session never starts or launches a browser again

    Ended stays ended

    fixed node developers operators

    When a session ends or is abandoned, the node records that durably. A later launch answers E_BROWSER_UNAVAILABLE with reason session_ended, and a delayed or retried start of it is refused, also after a node restart.

    added node operators

    The node's GET /health now answers 503 with reason barrier_unreadable when its record of ended sessions cannot be read; the node then refuses every start and launch but keeps ending sessions.

    #3684 · 2026-10-17

v2026.10.17.2

2026-10-17
  • The node's session cap now counts browsers, not sessions

    Count what holds the room

    changed node developers operators

    The node's cap now counts browsers, from launch until their end is confirmed, crashes included. A session with no browser, such as a parked or abandoned one, takes no place, and a refusal says limit runningBrowsers.

    #3687 · 2026-10-17

  • A warm resume refused for capacity keeps its sign-in for the retry

    A refused door keeps your key

    fixed node developers

    When a warm-resume session's first browser launch was refused, for example because the node was at its browser cap, the saved sign-in was already used up, so the retry opened a cold session. The node now keeps it until a launch succeeds.

    #3700 · 2026-10-17

v2026.10.17.1

2026-10-17
  • A session's identity is freed only once its browser is seen to be gone

    Watch it go before you let it go

    fixed node developers operators

    Ending a session now checks that every process of its browser is gone before the session counts as ended. Until then it stays draining and keeps its identity, so no other session can take it while the browser may still run.

    #3679 · 2026-10-09

  • Control's health check also reports whether the node is healthy

    Up means the part that does the work is up

    added control operators

    The health endpoint's body now carries a node field: ok, or a short reason such as unreachable or timeout. Before, it checked only the database, so a down node still read as healthy.

    #3686 · 2026-10-09

  • The MCP lease-release tool runs its workflow instead of failing with 400

    An empty request asks for nothing

    fixed mcp developers

    identity_release_lease answered 400 (missing field declaredEvidence) on every call. The gateway sends an empty JSON object, and the route read any body as the declared override; an empty object now runs the ordinary release workflow.

    #3694 · 2026-10-17

  • A full node now says so: session starts answer a retriable 503, not a 502

    Full is not broken

    fixed control developers operators

    When the node is at its live-session cap, a session start now answers 503 E_NODE_CAPACITY (retriable, NOT_STARTED) with a Retry-After header, instead of 502 E_UPSTREAM.

    #3695 · 2026-10-17

v2026.10.08.2

2026-10-09
  • wait now tells visible from mounted, and absent from not-found-yet

    A wait that answers the question asked

    fixed node developers

    The typed wait's selector states now mean what they say: visible needs a rendered element, hidden and detached are satisfied by an absent one, and a selector that matches several elements is no longer stuck as not satisfied.

    #3665 · 2026-10-08

  • A session keeps its network log tier and viewport across a node restart

    What you declared stays declared

    fixed node developers operators

    A session started with its network log off now stays off after a node restart. It used to come back at the metadata tier and start recording method, host, path and status. A higher tier is kept too, and so is the requested viewport.

    #3666 · 2026-10-08

  • The abandoned-session refusal reads as one sentence

    Close the gap

    fixed node developers

    The message on a session_abandoned refusal carried a run of 18 spaces in the middle of its sentence; it now reads as one line.

    #3674 · 2026-10-08

v2026.10.08.1

2026-10-08
  • Frontend deploys show why a build failed instead of discarding it

    A quiet build still speaks when it fails

    fixed deploy operators

    The console, docs and website deploys stay quiet while a build succeeds, but when it fails they now print the last 40 lines of the build and the path to its full log, so the deploy log names the cause.

    #3639 · 2026-10-01

  • The changelog files each change under the release that actually shipped it

    Shipped means contained

    fixed docs operators developers

    The changelog now lists each change under the first release that actually contains it. It grouped by day, so a change merged after a day's last release read as shipped in that day's first one.

    fixed console operators

    The What's new banner no longer says the changelog is older than the running build when the server runs a recent release. The banner matches the running version to the changelog's releases, and same-day releases were missing.

    Before
    After
    A console whose server reports v2026.10.01.5. Before: a banner claiming the changelog is older than the running build, because that release had no section. After: no banner, because it has one. Captured from a local build.

    #3643 · 2026-10-01

  • The hosted node gets 12 GiB of memory, up from 8

    Room for the tabs the sessions open

    fixed deploy operators

    On 2026-10-08 seven cloak sessions with ChatGPT tabs outgrew the node's 8 GiB memory cap: the node thrashed, renderers were OOM-killed, and perceive timed out. The hosted node's cap is now 12 GiB.

    #3656 · 2026-10-08

  • Dialogs keep a margin from the screen edge on a narrow screen

    A frame needs its margin

    fixed console operators

    On a phone-width screen, a dialog such as Create API key filled the screen edge to edge. It now keeps a margin on every side.

    Before
    After
    The Create API key dialog at a 400px wide viewport. Before: the panel touches both edges. After: a margin on every side. Captured from a local build.

    #3657 · 2026-10-08

  • An off-box probe now raises an issue when production goes down

    Watch from outside the house

    added deploy operators

    A scheduled probe checks the production health endpoint from outside every 15 minutes and opens a prod-down issue when it stays unreachable, closing it on recovery. A 28-hour outage in October went unnoticed because no alert path existed.

    #3658 · 2026-10-08

  • Confirmations use the shared nightglass toast and can be dismissed

    Said once, then out of the way

    changed console operators

    The small confirmations that appear after an action, such as Session ended with the session's id, now use the nightglass toast. Each has a close button and is drawn above any open dialog.

    Before
    After
    The Session ended confirmation after ending a session. Before: the console's own toast. After: the nightglass toast, with a close button. Captured from a local build.

    #3659 · 2026-10-08

  • An abandoned session now says it was abandoned

    Name the timer, not the tunnel

    changed node developers operators

    A session the node abandoned after its inactivity timeout (30 min by default) now answers later calls with E_BROWSER_UNAVAILABLE and reason session_abandoned, not proxy_not_registered, which pointed at the proxy instead of the timer.

    #3660 · 2026-10-08

  • A screen reader hears each sign-up attestation in full

    What you read is what you agree to

    fixed console operators

    On the create-organization page, each checkbox is now announced with exactly the text beside it. The business attestation used to be announced without its last sentence, about being authorized to bind the organization.

    The create-organization page, where the three attestation checkboxes are now named by their full visible text. Captured from a local build.
    The create-organization page, where the three attestation checkboxes are now named by their full visible text. Captured from a local build.

    #3661 · 2026-10-08

  • A role locator finds native buttons, links and inputs, not only explicit roles

    A button is a button without saying so

    fixed node developers

    A quoted, exact role locator for a button named X now finds a native button, link or input with that accessible name. Before, it saw only elements with an explicit role attribute, so on most pages it timed out as not found.

    #3664 · 2026-10-08

v2026.10.01.6

2026-10-01
  • A session that refuses to launch its browser says so on every call

    Ask twice, hear the same answer

    fixed node developers operators

    When a session refuses to launch its browser, every page call on it now returns that same refusal with its reason. Before, only the first call did, and later calls returned E_TAB_NF, which reads as navigate first and can never work.

    #3635 · 2026-10-01

v2026.10.01.5

2026-10-01
  • An ended session no longer leaves its identity stuck as in use

    Once ending, never attached again

    fixed control operators

    A background cleanup could mark an identity as in use again just after its session ended, so every new session on it was refused until someone force-released it. A lease that is ending now always finishes ending.

    #3625 · 2026-10-01

  • Sessions keep working across a node restart, inside their original limits

    The envelope travels with the session

    security node operators developers

    A session the node rebuilds after a restart, such as a deploy, now gets its exact egress policy back and relaunches its browser through its own proxy. Before, it was refused with envelope_not_restored and had to be replaced.

    security deploy operators

    New node setting NIGHTJAR_REQUIRE_SESSION_EGRESS, on in the hosted deploy: every browser launch must go through a session proxy, or it is refused with proxy_not_registered. The node logs whether it is enabled or disabled at boot.

    #3630 · 2026-10-01

  • A session that refuses to relaunch its browser now says why

    One code, two causes, and now a reason to tell them apart

    fixed control developers operators

    When a session can no longer launch its browser, for example after a node restart, the API error now carries a reason such as envelope_not_restored. Before, it looked the same as a node with no browser installed.

    #3632 · 2026-10-01

v2026.10.01.4

2026-10-01
  • The console never shows an identity as free when it cannot read the lease

    Not knowing is not the same as free

    fixed console operators

    When the control plane does not report an identity's lease, the console now says Lease unknown and blocks deleting it, instead of showing it as Available.

    The identities list, where the Lease column lives. On a current control plane it looks exactly as before; Lease unknown appears only when the control plane does not report the lease.
    The identities list, where the Lease column lives. On a current control plane it looks exactly as before; Lease unknown appears only when the control plane does not report the lease.

    #3609 · 2026-10-01

  • The identity response says available or in use, like the assumable list

    One word for held, on every surface

    added control developers

    The identity list and single-identity responses on /v1 now return leaseState, available or in_use, the same value the assumable list already returns for the same identity.

    #3612 · 2026-10-01

  • Every identity lease release now leaves an audit record

    No release goes unrecorded

    fixed control operators

    An org suspend, and the cleanup that finishes an end the node confirmed later, now record the identity lease they release, with no actor and a via field naming the path.

    #3619 · 2026-10-01

  • Sessions refuse to relaunch outside their limits after a node restart

    Refuse rather than run outside the bounds

    security node operators developers

    After a node restart, such as a deploy, a live session's browser relaunched without its egress proxy and limits, and cloak relaunched as Chrome. Such a session now refuses its next command with a typed error; start a new one.

    changed control developers

    launchedBrowserKind now describes the running browser: a relaunch updates it with a new launchConfirmedAt, and after a node restart it is absent until the relaunch is confirmed. Absent means not yet confirmed, never a match.

    #3620 · 2026-10-01

v2026.10.01.3

2026-10-01
  • One identity, one browser, even under concurrent starts and unconfirmed ends

    One identity, one browser at a time

    fixed control developers operators

    Two session starts on the same identity can no longer both succeed. The second is refused with 409 E_CONFLICT, and its reason says why the identity is held.

    added control developers

    Identity responses gain leaseHold: live, in_flight, ending or unresolved, and null when the identity is free. A refused session start names the same value in reason. leaseState stays available or in_use.

    changed control developers operators

    Force-release now ends the session and frees the identity only once the node confirms the browser is gone. Otherwise the lease stays, and released: false says why.

    changed control developers operators

    Ending, deleting or suspending a session that holds an identity completes it only once the node confirms. Until then the session is draining: it cannot be driven, and the identity stays held.

    added control operators

    A reconciliation worker, on by default, finishes interrupted starts and unconfirmed ends once the node confirms. Its boot line says whether it is running.

    added control developers

    A new 503 E_BIND_BUSY, retriable and with Retry-After, is returned when every identity-start slot is in use.

    changed mcp developers

    identity_list_assumable shows leaseHold, and identity_release_lease runs the termination workflow and reports a reason when it keeps the lease.

    fixed console operators

    An identity held by a start in progress, or by one that was interrupted, now reads In use instead of Available.

    Before
    After
    The identities list: ops-runner is held by an interrupted start with no session yet. It used to read Available; it now reads In use.

    #3597 · 2026-10-01

  • Governance docs stop saying recording and cloak mirror local reach

    Two switches that still start off

    docs control operators developers

    The allowSessionRecording and cloakEnabled descriptions in the governance contract said they were off by default, mirroring allowAgentSelfReach. New orgs now get allowAgentSelfReach on, so the two descriptions name each other instead.

    #3600 · 2026-10-01

v2026.10.01.2

2026-10-01
  • Agent keys in new orgs can ask for local reach by default

    Asking is open; reaching still needs a human

    changed control operators developers

    In an org created from now on, an agent-bound key minted without scopes carries reach:self, so its agent can ask for local reach without an admin first enabling allow_agent_self_reach. Existing orgs keep their stored setting.

    #3590 · 2026-10-01

  • A crashed session no longer holds its identity forever

    Ask the node who is still alive

    fixed control developers operators

    Since v2026.10.01.1 a session whose browser had crashed could keep its identity held: the reaper waited for a confirmation the node never gave. It now treats a session missing from the node's live list as ended, and frees the identity.

    #3591 · 2026-10-01

v2026.10.01.1

2026-10-01
  • The act receipt no longer promises a join key it does not deliver

    Declared is not delivered

    docs sdk developers

    ActReceipt.commandSpanId is now described as absent when unset, never null, and as not yet delivered on act receipts, so no client builds a correlation chain on a key that is always missing today.

    docs mcp developers

    The act tool's receipt schema carries the same correction: commandSpanId is absent rather than null, and is not yet populated on act receipts.

    #3508 · 2026-09-29

  • An identity's lease holder is reported the way a bind sees it

    One predicate, read and write alike

    fixed control developers operators

    The identity read now reports leaseHeldBy whenever a live session holds the lease, including after its renewal horizon has passed. It used to read null there while session_start still refused the identity.

    added control developers

    Identity reads carry leaseExpiresAt, the held lease's renewal horizon, so a holder can renew before it passes. It is null exactly when leaseHeldBy is, and a past value does not mean the identity is free.

    #3515 · 2026-09-29

  • Identity page stops claiming a snapshot is captured when a session ends

    Only a capture you ask for becomes a snapshot

    fixed console operators

    The identity page said a login snapshot is minted when a session ends; nothing does that. It now says snapshots come only from an explicit capture, and marks the version warm-resume actually uses.

    Before
    After
    The auth-state versions section, before and after: the corrected explanation, and the active chip on the version warm-resume uses.

    #3520 · 2026-09-29

  • See who approved or denied each access request, and when

    Every decision keeps its decider

    added control developers operators

    GET /v1/access-requests takes a status filter, and every approved or denied request now names who decided it (actionedBy) and when (actionedAt).

    added sdk developers

    accessRequests.history() pages through approved and denied access requests with their deciders; accessRequests.list() still returns the pending queue exactly as before.

    added console operators

    The Identities screen shows Recent decisions under the access-request queue, so an approval no longer vanishes from the console once it is made.

    #3525 · 2026-09-29

  • Clipboard capture resolves perceived controls; errors stop naming other tabs

    Copy the control you perceived

    fixed node developers

    clipboard_capture now resolves a perceive address for its copy control, the same way act does, generation suffix and all. It used to fail every time with not found in perception snapshot, whatever the page.

    security node operators developers

    A not-found error for a uid or a tab no longer lists the tab ids and UID counts of other sessions on the same node. It names only the tab it was asked about.

    #3526 · 2026-09-29

  • Session terminalReason says what it reports today

    Over is not the same as clean

    docs control developers

    The terminalReason description now says that every terminal session currently reads ended, crashed, evicted and challenge-walled ones included, since nothing records a reason yet. Read ended as “the session is over”, not “it ended cleanly”.

    #3531 · 2026-09-29

  • The adopt route names the takeover scope and when it applies

    Say which door needs the second key

    docs control developers

    POST /v1/sessions/:sessionId/adopt now names sessions:takeover: replacing another principal’s live controller token, or a live input grab someone else holds, needs org-admin membership or that scope, and otherwise answers 403.

    #3533 · 2026-09-29

  • The command palette puts your cursor in the search box again

    Type the moment it opens

    fixed console operators

    Opening the command palette with Control-K or Command-K focused its Close button instead of the search box, so typing went nowhere. The search box has focus again.

    The command palette just after Control-K or Command-K: what you type lands in its search box.
    The command palette just after Control-K or Command-K: what you type lands in its search box.

    #3534 · 2026-09-29

  • The crashed-session reaper no longer ends a session that started mid-check

    Choose who to check before you look

    fixed control operators

    The crashed-session reaper now picks its candidate sessions before it asks the node which sessions are alive, so a session that starts during that check can no longer be ended as crashed.

    #3536 · 2026-09-29

  • Reapers free an identity lease only when the node confirms the browser ended

    No release without a receipt

    fixed control operators

    The session reapers now end a session and free its identity lease only when the node confirms the browser is gone. An unreachable node leaves the session live and the lease held until a later tick can confirm.

    #3537 · 2026-09-29

  • The role selector says how it matches a name

    First match wins, and now it says so

    docs control developers

    The act selector description now says how a role locator's name matches: a case-insensitive substring, and the first match in accessibility-tree order wins with no ambiguity error. A name like Copy also hits an earlier Copy message button.

    docs mcp developers

    The act tool's selector description in the MCP schema carries the same matching rule, and points to the perceive address when two controls share a name.

    #3540 · 2026-09-29

  • A quoted locator name matches exactly, and refuses when it is ambiguous

    Say exactly which one, or hear that there are two

    added node developers

    A quoted name or text in a role, text, label or placeholder locator now matches exactly and case-sensitively. If an exact locator matches more than one element, nothing is done and E_LOCATOR_AMBIGUOUS names each candidate's uid.

    added mcp developers

    The act, wait, extract and clipboard capture tools accept the quoted exact form in their selectors, with the same refusal when it matches more than one element.

    #3542 · 2026-09-29

  • Issuing, revoking and expiring a reach grant now leave an audit record

    Who could reach what, and until when

    added control operators

    A reach grant's issue, its owner's revoke and its expiry each write a value-free entity event: the target policy, the owner and the actor, never a claim code. Before, the only record was the grant row itself, deleted 90 days after it ended.

    #3543 · 2026-09-29

  • An ended reach grant's network stays guarded until it is actually cut

    No reach without a live grant behind it

    security control operators developers

    A reach grant's backing network is now torn down whichever path ends the grant, and stays guarded until it is cut. Before, after a re-ensure or before the reaper's next tick, another org member could bind it and reach the owner's target.

    #3545 · 2026-09-29

  • Governance settings that nothing enforces now say so

    A switch wired to nothing says so

    fixed console operators

    Settings no longer presents Data region as a residency choice: it says nothing in the platform acts on it yet. The Crypto-delete line says the flag is not read, and that purging a deleted org destroys its key either way.

    Before
    After
    The Data region field on Settings, Data governance: it now says the setting is not enforced.
    docs control developers operators

    The governance fields dataRegion, operatorAccess and cryptoDelete are documented as stored but not enforced, on both the settings and the patch shapes. Their behaviour is unchanged.

    #3547 · 2026-09-29

  • An act addressed by name says how many elements matched, and which one it used

    It chose one of three, and said so

    added node developers

    An act addressed by a role, text, label or placeholder locator now reports receipt.matchCount, how many elements that locator matched. Over 1, an A_LOCATOR_MATCHED_SEVERAL advisory on the delta names the element used and the others.

    added mcp developers

    The act and credential fill tools publish receipt.matchCount in their output schemas, and the selector description says where the count and the advisory appear.

    #3550 · 2026-09-29

  • Session list filters are declared, and an unknown status is now a 400

    Two names, one status, no quiet typos

    fixed control developers

    Filtering the session list by the completed status now returns every session the API reports as completed, including older ones stored under the legacy value ended, which the filter used to miss.

    changed control developers

    Both session list endpoints now declare their query filters. A status other than live, completed, failed, queued or draining is a 400 instead of an empty list, so a mistyped status no longer looks like no sessions.

    #3552 · 2026-09-29

  • The API reference stops advertising the retired mailbox credential kind

    A retired kind says never, not yet

    docs control developers

    CredentialKind no longer describes mailbox as a working email-code fetch. It says the kind was retired on 2026-07-14, is refused at create, and stays in the enum only so older credentials still read.

    fixed control developers

    Filling a stored mailbox credential is still refused, but the error now says the kind was retired and will never fill, instead of suggesting a resolver ships later. Other kinds keep their not yet fillable error.

    #3554 · 2026-09-29

  • Nine error and approval messages lose a run of stray spaces mid-sentence

    One space between words, not twenty

    fixed control developers operators

    The sign-in approval page, the reach refusal receipt and the declared-hosts error no longer show 13 to 45 spaces in the middle of a sentence. The ruled words of the receipt are unchanged.

    fixed cli developers

    The daemon's could-not-determine-a-control-URL error reads as one sentence again.

    #3555 · 2026-09-29

  • Docs write every Bitspark project name as its repository is named

    A name reads the way it is typed

    docs docs developers operators

    The docs, READMEs and agent guides now write nightjar, nightfall and the other Bitspark projects exactly as their repositories are named, following the Bitspark naming rule. Quotations and verbatim records keep their original spelling.

    internal docs developers

    A new advisory CI job runs the vendored Bitspark naming check on every pull request, after a control that proves it flags a planted misspelling by name.

    #3557 · 2026-09-29

  • The console, docs site and packages write the product name as nightjar

    The name on the screen is the name you type

    changed console operators

    Console copy, page titles and the logo's accessible name now write the product as nightjar, following the Bitspark naming rule. HTTP header names such as X-Nightjar-Org are identifiers and are unchanged.

    Before
    After
    The What we store page: its body text and the topbar version label now read nightjar. Headings render in capitals, so they look the same.
    docs docs developers operators

    The docs site's pages, navigation and llms.txt write nightjar. One error line keeps the capital, because it quotes the tunnel's output verbatim and that output is unchanged.

    docs sdk developers

    The npm package descriptions and source comments of the SDK, the API types, the design system and the UI components write nightjar. No exported name or behaviour changes.

    #3558 · 2026-09-29

  • CLI help, CLI errors and MCP tool descriptions write the name as nightjar

    The help text spells the name you type

    changed cli developers operators

    The nightjar CLI's command help, error messages and remediation hints now write the product as nightjar, for example: Cannot reach nightjar server. Error codes and exit behaviour are unchanged.

    docs mcp developers

    Five MCP tool descriptions now write nightjar: the egress argument of session_start and spawn_and_start_session, and console_log, network_log and local_reach_ensure. No tool name, argument or behaviour changes.

    #3559 · 2026-09-29

  • The design-phase architecture docs are labelled historical

    A frozen page says when it froze

    docs docs developers

    The ten numbered design-phase documents under docs/architecture now open with a banner saying they are a narrative frozen on 2026-06-13, and point to the current domain model and the ADR index instead.

    #3562 · 2026-09-29

  • An act receipt names the command span its traffic carries

    The receipt and the traffic finally share a name

    fixed node developers

    receipt.commandSpanId is now present on act receipts and equals the _commandSpanId of the requests the act's verb started, so an act can be joined to its traffic in network_log. It was declared but absent on every act.

    fixed mcp developers

    The act and credential fill tools return receipt.commandSpanId, and its description no longer says it is not yet delivered.

    #3563 · 2026-09-29

  • Runtime messages, the API title and the MCP instructions write nightjar

    The error names the product the way you type it

    changed cli developers operators

    CLI output and errors that the CLI builds itself, such as the doctor report, surface probes and tunnel start-up errors, now write nightjar. Exit codes and error codes are unchanged.

    changed control developers

    The OpenAPI document is now titled nightjar API, and error messages the node and control plane return, such as tunnel refusals and session id validation, write nightjar. Error codes are unchanged.

    changed mcp developers

    The instructions the MCP server sends to a connecting client now open with nightjar hosted browser. No tool, argument or behaviour changes.

    #3567 · 2026-09-29

  • The seeded CLI OAuth client is named nightjar CLI

    A name on record, spelled as the repository

    changed control operators

    Migration 0076 respells the seeded nightjar-cli OAuth client's display name from Nightjar CLI to nightjar CLI, so the operator's list-oauth-clients output matches the Bitspark naming rule.

    #3570 · 2026-09-29

  • OAuth approval pages name the client that is actually asking

    Only a vouched-for name heads the page

    security control operators developers

    The consent, OOB copy and device approval pages used to say Claude Code for every OAuth client. They now name the client itself: a first-party client by its name, and a self-registered client as an UNVERIFIED application with its client id.

    #3574 · 2026-09-29

  • Client registration refuses every invisible character in a name

    What a name hides, registration refuses

    security control developers

    A dynamically registered OAuth client name is now refused if it contains any Unicode Default_Ignorable_Code_Point, such as variation selectors, tag characters or Hangul fillers, besides control, bidi and zero-width characters.

    #3578 · 2026-09-29

  • The published API contract writes nightjar as its repository name

    The contract spells its own name

    docs docs developers

    Descriptions in the published /v1 OpenAPI document now write the project name as nightjar, matching its repository. Only prose changed: no schema, field, header or operation id moved, and X-Nightjar headers keep their names.

    #3579 · 2026-09-29

  • List the sessions one identity holds, in one call

    Ask for one identity, not the whole org

    added control developers operators

    GET /v1/sessions and GET /v1/sessions/page accept an identity filter, the identity's id. Combined with live, it lists the live sessions an identity's teardown must end, instead of listing every session in the org and filtering client-side.

    added sdk developers

    SessionFilter gains identity, sent by sessions.list and sessions.listPage; the mock client filters on it the same way.

    #3582 · 2026-09-30

v2026.09.17.1

2026-09-17
  • The CLI's exit codes were documented nowhere

    One means the floor gave way

    docs cli operators developers

    A script author asking what nightjar returns on failure had nowhere to look: CLI_REFERENCE.md is generated and has no exit-code section, so the contract lived only in main.rs. Now stated in command-architecture.md.

    #3438 · 2026-09-04

  • AGENTS.md drops 26 percent, and a silent clobber hazard goes with it

    Nothing of ours inside a managed region

    fixed docs developers

    2,654 lines sat inside markers declaring them installer-managed, but 97 percent existed only here. An install would have destroyed about 1,900 lines of nightjar rules. That content moved out; AGENTS.md drops 169k to 126k tokens.

    #3452 · 2026-09-04

  • AGENTS.md gets 58 sub-headings: 593 lines per heading becomes 99

    An unbroken slab, given section lines

    changed docs developers

    The Git workflow section was 6,976 lines with ZERO sub-headings, so the file's own advice, enumerate the headings, could not work on the file. 58 headings added at real topic boundaries. Provably zero content change.

    #3455 · 2026-09-04

  • Five MCP tool descriptions were being truncated at 2048 characters, silently

    The tail never left the building

    internal mcp developers

    A tool description over 2048 chars is cut by the client and the tail reaches no agent, with no error anywhere. Five of 39 exceed it. A guard now freezes those five as debt and blocks any new one.

    #3456 · 2026-09-04

  • The external-state register now probes itself on a schedule

    A cron is the only trigger it has

    added docs developers operators

    Eleven register rows are now probed every six hours and written to a generated file. The register's subject changes without a commit, so no merge gate could ever have seen it drift.

    added docs developers

    Every probe carries a control whose expected answer is the opposite of the real probe's, and a failed control marks that row VOID rather than letting it read as a value.

    #3460 · 2026-09-04

  • The deploy now says when the production edge is frozen

    The rate limiter cannot deploy itself

    internal deploy operators

    Every Caddyfile apply has refused since 2026-06-29 because the remote Caddy lacks the rate-limit module, and no surface reported it. deploy.sh now runs a read-only edge check after a deploy, and verify-edge.sh runs alone.

    #3461 · 2026-09-04

  • Rust doc comments now build in CI, and 52 broken references surfaced

    A reference that resolves, and one that does not

    internal docs developers

    About 2 MB of Rust doc-comment prose shipped without cargo doc ever running in CI, so no cross-reference in it had been checked. The first build found 97 unresolved intra-doc links. An advisory job now builds the docs and classifies them.

    #3462 · 2026-09-04

  • Every ADR now shows what references it, generated rather than remembered

    Every edge now points both ways

    added docs developers

    ADRs carry a generated Referenced by block, drift-gated in CI. ADR-018 said it supersedes ADR-002 and ADR-006; neither of them carried a single reference back, in the direction a reader travels.

    docs docs developers

    Three networking relations are now declared rather than implied, so they render as labelled backlinks: ADR-018 supersedes, ADR-021 extends, ADR-035 reframes.

    #3463 · 2026-09-04

  • daemon up stops guessing the control URL from a port number

    The deployment says where it is

    added cli operators developers

    The CLI derived the daemon control-channel URL by adding one to the API port. That cannot work against a hosted deployment, so it asks the server instead, at a new public endpoint.

    #3464 · 2026-09-04

  • The ADR backlink gate was running on files it never opened

    The frame was smaller than the picture

    fixed docs developers

    The CI filter already fired on ui, core and deploy markdown, so the gate ran and reported zero drift about files its graph did not read. It now scans the same roots as its sibling link checker.

    fixed docs developers

    A generated backlink stated its relation in the referrer's voice, so a superseded ADR was labelled as the one doing the superseding. The label now inverts for the target.

    #3465 · 2026-09-04

  • The credentials guide now says a login hop needs the auth host declared

    The second gate was never on the map

    docs docs operators developers

    The guide described the cloak gate only at session start (the url must be a declared advisor origin). It now says the same gate narrows every request, so a login hop to an identity-provider host fails unless that host is declared too.

    #3468 · 2026-09-05

  • The credentials guide: what a lease keeps, and a capture never auto-promotes

    The clock on the tab is not the clock on the lease

    docs docs operators developers

    An identity lease keeps the session and the lease, not the tab: the node closes an idle session's browser 30 minutes after its last session verb; lease renewals do not count. A captured auth-state version is never promoted automatically.

    #3475 · 2026-09-06

  • Choose a browser when starting a session

    A browser choice at the start

    added console operators developers

    Choose Chrome or Cloak in the New session dialog. Cloak shows organization availability and requires a valid start URL; Chrome remains usable if availability cannot be checked.

    Before
    After
    The New session dialog now includes a Browser selector above Start URL, with Cloak availability and URL guidance.

    #3478 · 2026-09-06

  • Unify session control and make authority visible

    One operator, one controller

    changed control operators developers

    Human org admins can take over sessions and identity leases using their membership authority. API keys keep their own scopes, modes, and identity grants.

    fixed sdk developers

    A successfully adopted controller is carried on subsequent calls for that session, including navigation and remote input. Tokens stay in client memory and are cleared on release.

    changed console operators

    Take control establishes one lease for navigation and remote input. Key creation shows execution mode and offers explicit workflow presets.

    Before
    After
    The key creation dialog now explains execution mode and offers explicit start-and-drive and remote SDK presets.

    #3479 · 2026-09-06

  • Say which identity open mode is actually enforced

    A stored setting is not a shipped behaviour

    docs docs developers

    The credentials guide (both twins) now says only exclusive is enforced at session-open: fork and readonly are stored and echoed read-side but not wired, and openModes echoes the stored default rather than reporting a capability.

    #3483 · 2026-09-12

  • MCP identity discovery now says where provisioning and the spec live

    The drive plane points at the provisioning plane

    docs mcp developers

    identity_list_assumable and the server instructions now say provisioning (create identity, store credential, grant) is REST-only, name the routes and scope, point at the OpenAPI spec, and flag that openModes is an echo, not a capability.

    docs sdk developers

    The IdentityCreate defaultOpenMode description in the v1 OpenAPI spec now says only exclusive is enforced at session-open; fork and readonly are stored and echoed but not yet wired.

    #3484 · 2026-09-12

  • Open modes other than exclusive are not planned, and the record says so

    One session per identity; multiplex on your side

    docs docs developers

    The credentials guide twins, ADR-011, ADR-009 and open-questions Q24 now record the 2026-09-12 decision: only exclusive is enforced, fork and readonly are not planned, and consumers multiplex their actors onto one session per identity.

    #3485 · 2026-09-12

  • The spec and MCP prose now say fork and readonly are not planned

    Stored, inert, and honestly labelled

    docs sdk developers

    The OpenMode, Identity.defaultOpenMode, IdentityCreate.defaultOpenMode and AssumableIdentity.openModes descriptions in the v1 spec now say only exclusive is enforced by decision, and that fork and readonly are stored, inert and not planned.

    docs mcp developers

    identity_list_assumable now says only exclusive is enforced by design (one live session per identity; multiplex your actors onto it) instead of today, so no reader plans around a mode that is not coming.

    #3486 · 2026-09-12

  • The identity form stops promising open modes that are not coming

    Exclusive, by design

    changed console operators

    The New identity form's open-mode hint now says fork and read-only are not planned and exclusive is the only mode, by design, instead of not enforced yet: one live session per identity, actors multiplexed onto it by the consumer.

    Before
    After
    The Default open mode field in the New identity form: the hint no longer says fork and read-only aren't enforced yet; it says they are not planned, and exclusive is the only mode by design.

    #3487 · 2026-09-12

v2026.09.04.1

2026-09-04
  • warmResume now names the v1-only producer half it depends on

    Consume, never mint

    docs mcp developers

    The MCP surface lets a caller consume an auth-state version and mint none: capture is v1-only by design and promote was deferred. The description now says so, rather than pointing an MCP caller at a tool absent from their surface.

    #3399 · 2026-08-31

  • A deep link into the console now survives signing in

    Back where you were going

    fixed console operators

    Following a console link while signed out, such as one that opens the new key form, now brings you back to that page after you sign in, instead of to the start page.

    The API keys page with the new key form open and its name filled in: where a signed-out visitor following a new key link now lands after signing in. Captured from a local build.
    The API keys page with the new key form open and its name filled in: where a signed-out visitor following a new key link now lands after signing in. Captured from a local build.

    #3411 · 2026-09-02

  • Three documents promised a redaction floor that was removed 27 days earlier

    A guarantee outlived its code

    docs docs developers

    The result contract and the getting-started guide told integrators every model-exit read is secret-shape-floored. That floor was removed 2026-08-07; floor_secret_shapes is now the identity function. Both now say so.

    #3417 · 2026-09-03

  • Repair stale doc references and guard the ADR index against silent decay

    An index that cannot lose a row

    fixed docs developers operators

    The ADR index listed 31 of 56 ADRs and was diverging. All 56 now have a row, and a new guard fails when an ADR has none or a row names a missing file. Five dangling wiki-links, six dead path claims and one broken anchor are also fixed.

    #3418 · 2026-09-03

  • The glossary had the two authority planes backwards

    Two planes, never crossing

    fixed docs developers operators

    The published glossary described both authority planes as credential mechanisms, and claimed captured network logs are filtered for secret values. Neither was true.

    #3419 · 2026-09-03

  • The docs now say what we publish, and the register says it correctly

    Probe it, or do not state it

    fixed docs developers operators

    The external-state register was falsified 57 minutes after its own last edit and stayed wrong for 16 days across six rows. It said two npm packages were broken and burned when both were fixed and healthy.

    fixed docs developers

    check-doc-links reported zero broken links over 173 files while the repo's only broken link sat in the 34 files its roots could not reach. Widened to 204 files; it then caught the link, which is also fixed.

    fixed docs developers operators

    Two ratified ADRs carried self-expiry clauses that fired on the npm publication and were never pulled. ADR-024 still said the packages were not published while they sat at 0.1.5 and 0.1.3.

    added docs developers

    The root README now names the four doors a consumer can attach to, the ADR index lists all 56 ADRs instead of 31, and the architecture index reaches the ten sibling directories it never mentioned.

    fixed docs developers

    The published getting-started page told consumers ADR-035 was awaiting ratification, two months after it was ratified. The unpublished in-repo twin had it right.

    #3423 · 2026-09-03

  • Networking docs point forward, and intranetMode stops saying it does nothing

    A stale doc gains a forward pointer

    fixed docs operators developers

    The published intranetMode description said toggling it does not yet change session behavior. It has governed all private tunnel reach since v2026.06.28.1, so the contract told org admins the opposite of the truth for nine weeks.

    docs docs developers

    Networking docs now carry forward pointers. ADR-002 and ADR-006 named none of the three later ADRs that changed them, and the architecture index mentioned ADR-018, ADR-021 and ADR-035 zero times.

    docs docs developers

    The published guides said local reach has no CLI and was awaiting ratification. The tunnel command ships and the ADR was ratified on 2026-07-01; only the signed installer is unbuilt.

    #3425 · 2026-09-03

  • The sign-in routes now pass through the rate limiter they were always meant to

    Two doors, one gate

    security control operators

    The GitHub sign-in entry points were classified as rate-limited and never actually were: they sat one layer outside the limiter. They are inside it now, so repeated sign-in attempts from one address get a 429 like every other public route.

    #3434 · 2026-09-03

  • The env-var reference named 35 of the 72 variables the runtime reads

    Half the dials were unlabelled

    docs docs operators developers

    core/docs/configuration.md calls itself the canonical reference for the environment variables the node, daemon and CLI read. It named 35; the runtime reads 72. The 37 missing ones are now documented with defaults read out of the code.

    #3437 · 2026-09-03

v2026.08.31.1

2026-08-31
  • State that daemon:files reads file content and writes to local disk

    Consent needs the whole truth

    security control operators developers

    The daemon:files scope described itself as 'List and stat files' while also reading file content and writing files to the caller's local disk. Granters saw a read-only description for our broadest local-disk capability.

    #3362 · 2026-08-28

  • Stop enumerating act verbs in prose: the spec points at the enum

    Read the enum, not a sentence

    docs control developers

    The published ActVerb description listed eleven verbs while the enum carried thirteen, so a client reading the spec could not discover fill or select. It now points at the enum instead of restating it.

    #3370 · 2026-08-29

  • Correct the contract: inline clipboard capture is refused, not available

    Say what the surface does

    fixed control developers

    The OpenAPI contract described inline clipboard capture as a usable return mode and its result field as sometimes populated. Both are refused with a 400, so the descriptions now say so.

    #3372 · 2026-08-29

  • Agents can prepare a config change for a human to approve

    Compute the change, keep the click

    added control developers

    A new request kind lets an agent compute a config change, render its diff and file it for ratification. Preparing grants nothing: the record is inert until someone with the authority acts on it.

    #3380 · 2026-08-29

  • The controller token comes back on a different header than it arrives on

    Correct, precise, and pointing away from the fix

    fixed control developers

    Adopt mints the controller token onto a RESPONSE header; renew and release expect it back on a DIFFERENT REQUEST header. Renew never named it and neither declared it. All three endpoints now declare their required headers.

    #3383 · 2026-08-30

  • An unknown config change class is now refused when it is filed

    Refuse at the door, not at the desk

    changed control developers

    POST /v1/config-change-requests now accepts only declared change classes. Filing an unrecognised target returns 400 and names the classes that are allowed, instead of queueing a request that no one could ever apply.

    #3386 · 2026-08-30

  • App authors get a security guide for what is enforced and what is not yet

    A real floor, and an open gate

    docs docs developers

    A new guide tells app authors what App Surface protects today and what is only decided. The headline: there is no consent gate or scope check on import, so reachability to the node is the authorization.

    #3387 · 2026-08-30

  • A refusal that was correct now also names the lease you can actually renew

    Name the road you are not on

    fixed control developers

    Renewing the identity lease on a controller-owned session answered 'session is not identity-bearing' and stopped. True, and it reads as 'no renewal exists'. It now names the CONTROLLER lease and its renew verb.

    #3388 · 2026-08-30

  • The SSRF denial now names declared hosts, except where that would be a bypass

    Name the door, not the wall

    fixed node operators developers

    Direct egress blocked by the SSRF guard said only 'private address'. True, and it left the caller nothing to act on. It now names intranet_mode and the declared-hosts allowlist for the classes where that is the sanctioned path.

    #3390 · 2026-08-30

  • The reachability refusal now names the right remedy of two, not a guess

    Two gates, two doors

    fixed node operators developers

    One error variant covered two different gates with two different remedies, so a refusal could not name a correct next step for either. It now carries which gate refused and names that gate's remedy.

    #3392 · 2026-08-30

v2026.08.28.1

2026-08-28
  • Console dialogs converge on the nightglass modal size scale

    One scale of night for every window

    changed console operators developers

    Console dialogs now use the adopted design system's three-step size scale and its dialog chrome: a header band with an explicit close button; widths converge on sm/md/lg.

    Before
    After
    The Create API key dialog: free-form 56rem tightens to the adopted lg width (48rem), and dialogs gain the upstream chrome - a header band with a close button.

    #3349 · 2026-08-27

v2026.08.25.1

2026-08-25
  • The public marketing site finally has a deploy pipeline

    Merged is not deployed

    added deploy operators

    A website merge used to trigger the console deploy, ship nothing of the site and report green. A dedicated workflow now runs the sanctioned script and asserts the live stamp, and the console filter no longer matches the website.

    #3301 · 2026-08-23

  • Agents can read their own scopes with the new whoami tool

    Know what you hold

    added mcp developers operators

    The MCP surface now exposes whoami, which returns the calling credential's own orgId, agentId, keyId and scopes.

    #3311 · 2026-08-25

  • The generated MCP reference now carries the ADR-022 D9 cross-surface matrix

    A number that cannot hide its own caveat

    added docs developers

    The generated tool-surface reference now reports capability coverage across http, mcp, cli and sdk, with the tools it cannot represent counted beside it.

    #3314 · 2026-08-25

  • The cross-surface matrix now cites the ruling that governs a surface's scope

    A number a reader can interpret

    fixed docs developers

    Where a surface declares a scope ruling, the matrix now cites it beside the coverage figure, so a non-exposed state is not misread as debt.

    #3316 · 2026-08-25

  • D9's two unbuilt artifacts are now recorded as deferred, not left as open gaps

    A decision reads differently from a gap

    added docs developers

    The generated reference now records D9's per-capability sheets and effects/safety view as deliberately deferred, each with the condition that would revisit it.

    #3319 · 2026-08-25

v2026.08.23.2

2026-08-23
  • Correct the crypto-delete scope shown in console settings

    Say which keys, and mean it

    fixed console operators

    The governance panel described crypto-delete as destroying per-session keys. It destroys per-org and per-credential keys.

    Before
    After
    The crypto-delete row now names the org and credential scopes instead of a session scope.

    #3291 · 2026-08-23

  • Name the control-plane authority for artifact collection, not the node's

    Name the scope the caller can actually hold

    fixed mcp developers

    The tool surface named profile-maintenance and runtime-admin as the authority for artifact collection. Those are node-side arms with no control-plane analogue, so an agent looking up the scope it needs found names that do not exist there.

    #3294 · 2026-08-23

  • Access-request keys no longer mint with raw drive

    One default, every door

    security control operators developers

    A key minted by approving an access request took the database default and granted raw drive. It now binds the same delegation_required default as every other mint path.

    #3296 · 2026-08-23

v2026.08.22.2

2026-08-22
  • Agent keys minted from the self reach template can be rotated again

    The exception that stopped at the door

    fixed control operators

    An org that opted into agent self reach could mint a reach:self key but never rotate it, because rotation demanded a scope the template exists precisely not to require.

    #3249 · 2026-08-22

  • New API keys default to requiring delegation, not raw session driving

    A default withholds, never grants

    security control operators developers

    A key minted without an explicit mode now gets delegation_required instead of direct, so it cannot drive a session by its own raw presentation. Existing keys are untouched and keep the mode they were minted with.

    #3273 · 2026-08-22

v2026.08.22.1

2026-08-22
  • A malformed declared host is now refused instead of silently dropped

    A rule you declared should never become no rule

    fixed control operators

    Declaring a reachable host that cannot be parsed used to be accepted and then discarded. If it was the only entry the allowlist became empty, and an empty allowlist is permissive, so the one rule you declared quietly became no rule at all.

    #3227 · 2026-08-21

  • Show denied advisor origins where the declared set is edited

    The evidence belongs beside the editor

    added control operators developers

    A new org-scoped endpoint reports which advisor origins your sessions were refused, so the person editing the declared set can see what is missing.

    #3235 · 2026-08-21

  • A scheme-less advisor origin is now refused instead of silently coerced

    A scheme is not optional

    changed control operators developers

    Declaring an advisor origin without a scheme now returns 400 instead of being stored as http://HOST — a form that could never match an https advisor session, because the comparison is exact on scheme and port.

    #3245 · 2026-08-21

  • A 403 scope denial now names which key was refused

    A refusal that says who asked

    added control operators

    Server-side traces for a refused request now carry the acting key id, so a 403 can be joined to the caller rather than only to the scope and the request.

    #3246 · 2026-08-21

  • Correct the website README: a merge here deploys nothing at all

    A green run can mean nothing happened

    fixed docs developers

    Both app READMEs claimed a console deploy happens automatically. No deploy secret exists, so that workflow gates every real step behind an arming check and goes green having done nothing. Neither app has a live auto-deploy.

    #3248 · 2026-08-21

  • The scratchpad identity check can return a peer's handle on a resumed session

    A path cannot tell you whose it is

    docs docs developers operators

    AGENTS.md said a session-UUID scratchpad path carries your own handle. On a resumed session it need not track the running session at all, so the first 8 characters can name a live registered peer instead of you.

    #3252 · 2026-08-22

  • Show recently-denied advisor origins beside the field that declares them

    The evidence sits beside the control

    added console operators

    The governance tab now lists advisor origins that were recently denied, directly under the field that declares them.

    #3256 · 2026-08-22

  • Say why there is no verb to release your own artifacts

    A missing verb, explained

    docs mcp developers

    The download-to-artifact tool now explains why an agent cannot reclaim its own artifacts, instead of only stating that it cannot.

    #3258 · 2026-08-22

  • Cloak session start now honours a wildcard advisor origin declaration

    One rule, one implementation

    fixed control operators developers

    A wildcard advisor origin was honoured when the browser fetched a page but refused when the session started, so half the declaration worked and nothing said which half.

    #3261 · 2026-08-22

  • Correct the last false launch-state claim in the docs and website plan

    Measure the claim before you plan around it

    changed docs developers

    The planning draft said concepts had no public glossary. One is deployed and defines all five concepts the clause named, so the claim is struck in place.

    #3262 · 2026-08-22

v2026.08.21.6

2026-08-22
  • Advisor origins accept a wildcard, so a CDN change no longer breaks cloak

    One entry, every subdomain

    fixed node operators

    A declared advisor origin can now use a leading wildcard label and will match any subdomain. Previously only an exact host matched, so a provider that generates hostnames could break a cloak session with no config change on your side.

    #3205 · 2026-08-21

  • A drained session now closes with its own code, distinct from a plain end

    A redeploy is not a refusal

    added node developers

    The session-ended journal event now carries a typed cause beside its human reason, and a session drained by a redeploy closes the events socket with 1012 instead of 4410.

    #3213 · 2026-08-21

  • Add nightjar mcp install to wire a repo to a saved login

    The repo names the login, never the key

    added cli developers operators

    nightjar mcp install points a repo's .mcp.json at a saved login, and replaces an older entry that carried an Authorization header in the same write.

    #3215 · 2026-08-21

  • Tell docs authors that merging does not deploy the docs site

    Merged is not deployed

    docs docs developers

    The docs app now carries a README saying a merge to main does not reach the live docs site, and how to verify a change actually shipped.

    #3231 · 2026-08-21

  • Warn that a website merge deploys the console and ships nothing

    Green, and the wrong app

    docs docs developers

    The public website app now carries a README saying a merge there triggers the console deploy, goes green, and ships none of the site.

    #3240 · 2026-08-21

v2026.08.21.5

2026-08-21
  • Move rationale out of the API spec and into the concept pages

    Contract at the call site, reasons on the page

    docs docs developers

    Thirty-two OpenAPI descriptions shed their rationale paragraphs, which now live verbatim on two concept pages. Each field keeps a one-line pointer.

    #3150 · 2026-08-21

  • Declare a changelog position or the contract job now fails

    A position declared beats a position inferred

    changed docs developers

    The changelog contract job now fails a PR that declares no position at all — neither an entry nor the changelog:none label.

    #3151 · 2026-08-21

  • act upload now says what SUCCESS does and does not mean

    Set is not attached

    docs mcp developers

    act upload issues CDP SetFileInputFiles, so it cannot observe whether the page accepted the file - but the description never said so, and consumers read SUCCESS as attachment. It now states the limit and names the discriminating field.

    #3153 · 2026-08-21

  • act upload's receipt names what it SET on the input, not what the page attached

    Set, not attached

    docs mcp developers

    The uploadedRefs receipt said the refs were ATTACHED. They are the refs the verb resolved and set on the file input, before the page is handed anything - so a page-side upload failure is invisible to the caller.

    #3156 · 2026-08-21

  • Make the how-it-works page's Where to go next section actually link

    A named destination should be a door

    fixed docs developers operators

    The concept page's closing section named three destinations in bold prose with no links. All three are now links, and each target route was verified to exist.

    #3158 · 2026-08-21

  • Group the harvested spec rationale by the kind of mistake it prevents

    Sort by the shape of the error, not the shape of the thing

    changed docs developers operators

    The rationale moved out of the spec is now grouped by what it protects you from, and sits before each page's closing section rather than after it.

    #3160 · 2026-08-21

  • Approving an access request for reach:self no longer 403s the operator

    A gate no human could pass, on the surface built for exactly this

    fixed control operators developers

    An agent could file an access request for reach:self and no human could ever approve it. The approve gate checked the scope against the approver's own ceiling, and reach:self appears in no human role, so the click always failed.

    #3165 · 2026-08-21

  • A blank org header no longer dead-ends a multi-org operator

    One definition of no org selected, not two that agree by luck

    fixed control operators

    On the OAuth sign-in leg, a present-but-empty X-Nightjar-Org header made a multi-org operator see an error telling them to set that same header, instead of the org picker.

    #3167 · 2026-08-21

  • Pin the scan budget clock seam, and record the bound itself as untested

    An untested bound, honestly named

    internal control developers

    The provenance scan's time budget now reads a runtime clock at its three enforcement sites, with a test pinning that production behaviour is unchanged. The bound itself remains untested, and the reason is recorded in the source.

    #3186 · 2026-08-21

  • Pin the egress-cap env shape production actually passes, not the unset one

    The flag decides, not the default

    internal node developers

    The default-off test used remove_var, pinning the unset case. Deployment passes an empty string, which nothing pinned. Adds that arm, and fixes a lock that let the two tests race.

    #3189 · 2026-08-21

  • Declaring an advisor origin also bounds the hosts its page fetches

    One origin, many hosts

    docs control operators developers

    The declaredAdvisorOrigins description now states that the set bounds subresources, not just navigation, and that host matching is exact with no wildcards.

    #3193 · 2026-08-21

  • Every concept page now links back to the API reference

    A pointer that only goes one way is half a link

    added docs developers operators

    The spec's doc comments point at the concept pages, but no concept page pointed back. All four now link to the API reference, in prose that already named it.

    #3195 · 2026-08-21

  • CI now fails when a writable governance setting has no console control

    A setting nobody can reach is a setting nobody can fix

    internal control developers operators

    A governance field that can be changed by API but has no control in the console now reds CI, unless it is exempted with a written reason.

    #3197 · 2026-08-21

  • Declared advisor origins can now be edited in the console

    The last field with no control

    added console operators

    Data governance gains an editor for declared advisor origins, the field that previously had no console control at all.

    #3204 · 2026-08-21

v2026.08.21.4

2026-08-21
  • A direct-path SSRF denial now leaves a per-session audit record

    Both routes write it down

    security node operators

    An SSRF denial on the direct egress route bumped its counters but emitted no EgressAuditEvent, so the same security event the tunnel-floor deny journals was invisible per-session on that route. It now emits one.

    #3143 · 2026-08-21

v2026.08.21.3

2026-08-21
  • A session ended by a redeploy now says so, instead of later looking abandoned

    Say why the session ended

    fixed node developers operators

    A session closed by a node redeploy recorded nothing at the time, and was later reported as abandoned - which says the client went stale when the host had actually restarted.

    #3119 · 2026-08-21

  • Two explanation pages: what Nightjar refuses, and what things are not

    Explain the no, not only the yes

    added docs developers operators

    The docs site gains two explanation pages: the deliberate refusals and the reasoning behind them, and the category corrections where a name suggests one thing and the system means another.

    #3124 · 2026-08-21

  • Browser sessions can no longer reach link-local addresses on the direct route

    Every route through the same gate

    security node operators developers

    Sessions using split or platform egress were launched without a proxy, so their direct traffic reached the cloud metadata address unscreened. They now run through the same chokepoint every other route uses.

    #3125 · 2026-08-21

  • Published API descriptions no longer open with an internal issue number

    The first words belong to the reader

    fixed sdk developers

    Nineteen schema descriptions in the published spec began with an internal issue number. The number moved into a source-only comment; the description now opens with what it describes.

    #3126 · 2026-08-21

  • Serialize the CLI test that reached a process-global through production dispatch

    A lock excludes only those who take it

    internal cli developers

    A test reached the process-global diagnostics context through a production dispatch without taking the test lock, racing the tests that did.

    #3129 · 2026-08-21

  • Add the two boundary pages to the docs sidebar

    A page nobody can find is a page nobody reads

    changed docs developers operators

    The How Nightjar works section now lists What Nightjar refuses and What these things are not, between How it works and the Glossary.

    #3130 · 2026-08-21

  • The SDK drift record is regenerated and CI now fails when it goes stale

    The record that shows drift had drifted

    internal sdk developers

    SDK-versus-spec coverage is now a machine-checked number instead of a snapshot someone remembered to re-run.

    #3133 · 2026-08-21

v2026.08.21.2

2026-08-21
  • A redeploy now finishes draining browser sessions instead of being killed

    Finish the drain before the door closes

    fixed deploy operators

    The node's shutdown drain gave up after 8 seconds even though the container allows 60, so a redeploy killed sessions it had time to close cleanly.

    #3097 · 2026-08-21

  • Cite code by symbol, not by line number, in the credential guides

    A citation that survives the code moving

    fixed docs developers

    Code citations in the credential guides now name a module and symbol instead of a file and line, so they stay true when the file changes.

    #3103 · 2026-08-21

  • Every code citation in the credential security guide now resolves

    Pointers that all land somewhere real

    fixed docs developers

    The credential security guide no longer cites code by file and line. All 35 pointers are now module and symbol names, checked against the source tree on every CI run.

    #3104 · 2026-08-21

  • Explain how Nightjar works, with figures, under its own nav label

    The label finally cashes its cheque

    added docs developers operators

    The 'How Nightjar works' section now contains an explanation, not just a glossary.

    #3118 · 2026-08-21

  • Choose your organization when signing in with more than one

    The sign-in page finally asks which organization you mean

    added control operators

    Signing in to an application while your account belongs to several organizations now shows a page asking which one to use, instead of an error naming a header a browser cannot set.

    #3120 · 2026-08-21

v2026.08.21.1

2026-08-21
  • Correct why the Run targetId field is always null

    A reason can expire before the fact does

    fixed control developers

    The API reference said targets do not exist yet. They do - a run simply cannot be bound to one.

    #3063 · 2026-08-20

  • Say why three API fields are always empty

    An empty field can still say why

    docs control developers

    Three fields the API returns are never populated. The reference now says so, and says why.

    #3067 · 2026-08-20

  • Clearer sign-in message when your account belongs to several organizations

    Two organizations, one sign-in, no way to choose

    fixed control operators

    The multi-organization sign-in page no longer tells you to run an approval from the CLI. That step does not exist on this flow, so the message now says plainly what happened and what will actually work.

    #3069 · 2026-08-20

  • Two more ways a clean-looking issue turns out to have nothing to build

    Reading the artifact is the check

    docs docs developers

    The dedup guidance listed two ways an issue can pass every structural check and still not be takeable. Four screens in one day found four reasons, and two of them were new.

    #3072 · 2026-08-20

  • Give the node time to finish draining browser sessions on redeploy

    Let it finish before you pull the plug

    fixed deploy operators

    The node now gets 60 seconds to drain its browser sessions on redeploy, instead of the 10-second default that killed the drain part-way through.

    #3075 · 2026-08-20

  • A seat records when its own failure mode fires hardest

    Urgency is when a guess travels furthest

    internal docs developers

    The SW6 seat keeps a list of times it measured something correctly and published it wrongly. Two more were added, along with the condition under which it happens.

    #3076 · 2026-08-20

  • api-types now ships spec provenance, so drift checks can answer for it

    A fingerprint must cover every source

    added sdk developers

    api-types is generated from the OpenAPI document and the WS event schemas but shipped no record of which revisions it came from. It now stamps both, so the release check can say a bump is due instead of reporting NOT APPLICABLE.

    #3077 · 2026-08-20

  • The documentation is reachable from the marketing site

    A door nobody can find is a wall

    added docs operators developers

    The marketing site carried no link to the documentation at all. It now closes with one, so the explanation layer is reachable from the front door.

    changed docs operators developers

    The docs sidebar group Concepts is now How Nightjar works, at the same rank, so it reads as an argument rather than a cabinet of terms.

    #3081 · 2026-08-20

  • Console screens can point at the explanation for what is on them

    Answer the question where the question is asked

    added console operators developers

    Reach grants and Identities now carry a contextual link into the docs, naming the question the screen raises rather than sending you to a docs front page to search.

    Before
    After
    The PageHeader showcase. After adds a third example carrying a contextual docs link, and documents the two new props. Captured from a pristine build and this branch, both asserted to have the component's styles applied.

    #3083 · 2026-08-20

  • A docs guide can no longer claim a tool count the manifest disagrees with

    A count must come from the thing it counts

    added docs developers operators

    The credentials guide said the MCP surface was a closed set of exactly 9 tools. It is 38. Both numbers now render from one validated selection, and CI refuses a tool table that has drifted from it.

    #3089 · 2026-08-20

v2026.08.20.12

2026-08-20
  • Document the four Run fields that are always null

    Say what the empty fields mean

    docs control developers

    The API reference now says which Run fields are always null today, why, and what would change that.

    #3060 · 2026-08-20

v2026.08.20.11

2026-08-20
  • Pin the NULL-profile filter in the reclaim report so removing it turns CI red

    A comment is not a signal

    internal control developers

    The reclaim report reads a nullable column into a non-Option String and is safe only because its query filters the NULLs out. That filter now has a regression test instead of a comment.

    #3057 · 2026-08-20

v2026.08.20.10

2026-08-20
  • A CI watcher settled while two required checks did not yet exist

    Absent is not incomplete

    docs docs developers operators

    AGENTS.md prescribed a count floor for merge watchers. A job whose dependencies have not resolved is never created, so it cannot be incomplete, and the floor passes straight over it.

    #3051 · 2026-08-20

  • A session with no profile no longer fails the reads that scan it

    One bad row should not sink the org

    fixed control developers operators

    Provenance and session-replay reads now tolerate a session whose profile column is null, instead of failing the whole request.

    #3054 · 2026-08-20

v2026.08.20.9

2026-08-20
  • Provenance answers now say how far the scan looked

    An empty answer should say why

    added control developers

    Every scan-backed provenance response reports how many sessions it read, the cap, and which bound ended the scan.

    added sdk developers

    ScanExtent and ScanCompletion are exported so a client can branch on why a scan stopped.

    #3033 · 2026-08-20

  • Record the cross-suite test collision that no single file can reveal

    Your green is someone else's red

    docs docs developers

    AGENTS.md now records the collision class where a new test suite breaks a neighbour's global-count assertion, and why seeding-side fixes relocate the problem rather than removing it.

    #3040 · 2026-08-20

  • The identity check in AGENTS.md passed on another agent's handle

    Resolving is not owning

    docs docs developers operators

    AGENTS.md told you to verify your own address with a bb send --dry-run. That proves a handle exists, never that it is yours, so the check returned a clean pass on a peer's identity.

    #3043 · 2026-08-20

v2026.08.20.7

2026-08-20
  • Report what a profile-store reclaim would remove, removing nothing

    Count it before you cut it

    added control operators developers

    An opt-in control worker logs what a profile-store reclaim would remove, reconciling the node's directory list against session records. It deletes nothing, and cannot: this build has no delete capability at all.

    #3031 · 2026-08-20

v2026.08.20.6

2026-08-20
  • Redeploy drains browser sessions instead of stranding them

    Let them out before the gate shuts

    fixed node operators

    The node now shuts down on SIGTERM, and drains live browser sessions before stopping — under a time budget, so it exits cleanly inside the container grace period.

    #3030 · 2026-08-20

v2026.08.20.5

2026-08-20
  • Ask the provenance oracle about many hashes in one request

    Many questions, one pass

    added control developers

    POST /v1/artifacts/provenance takes a list of content hashes and answers one entry per hash. A hash nothing produced comes back as an entry with an empty set, never a 404, so absence stays a usable answer.

    #3026 · 2026-08-20

v2026.08.20.4

2026-08-20
  • Pin the act response wire shape in an end-to-end guard

    Pin the shape, catch the drift

    internal control developers

    The workspace jail end-to-end suite now pins the shape of the act success and refusal envelopes against committed fixtures, so an unannounced field addition or removal fails CI instead of shipping silently.

    #3019 · 2026-08-20

  • Provenance now records what the node did to an artifact's bytes

    Two axes, not one

    added control developers

    Artifact provenance gains an optional processing field: raw, derived or unknown. Read it together with direction.

    #3021 · 2026-08-20

v2026.08.20.3

2026-08-20
  • Command-scoped provenance: one call for what a command touched

    Ask the command what it touched

    added control developers

    A new v1 route resolves a command span id to its occurrences: the verb, the outcome, and the artifacts it touched.

    added sdk developers

    The SDK gains commands.provenance, mirroring the existing artifacts.provenance.

    #3020 · 2026-08-20

v2026.08.20.2

2026-08-20
  • Agents can find a page region by the hash of its content

    The hash is the address

    added mcp developers

    A new projection_search tool asks which subtree projects to a given sha256 — the inverse of the projection-hash check that wait and act already carry.

    #3013 · 2026-08-20

v2026.08.20.1

2026-08-20
  • Superseded auth-state versions now follow your org's retention window

    History fades, the head remains

    added control operators developers

    Captured auth-state versions older than your organisation's retention preset are now reclaimed. The active version is never removed, nor is one a live session could still resume from.

    #3008 · 2026-08-19

v2026.08.19.12

2026-08-20
  • Tool descriptions no longer say no artifact collector exists

    A warning outlived the fact it rested on

    fixed mcp developers operators

    The artifact tool descriptions told every agent that no hosted surface exposed a collector. That stopped being true when POST /v1/artifacts/collect shipped, so the text now names the endpoint and the authority it needs.

    #3007 · 2026-08-19

v2026.08.19.11

2026-08-20
  • Find a region by the hash of its content, over the v1 API

    A verb earns its own gate

    added control developers

    The v1 API can now ask which subtree projects to a given sha256 — the inverse of the projection-hash check that wait and act already carry.

    #2999 · 2026-08-19

v2026.08.19.10

2026-08-20
  • The act result's delta is now a declared shape, not an untyped blob

    Declare what the wire already carries

    fixed mcp developers

    act and credential_fill declared their delta with no type at all. The wire carried 28 fields and 6 closed enums that no generated client could see.

    #2998 · 2026-08-19

v2026.08.19.9

2026-08-20
  • Reclaim expired controller idempotency records after a grace period

    The tombstone still speaks

    added control operators

    The controller idempotency table now has a reaper. It was the fourth ticket store and nothing had ever deleted from it.

    changed control developers

    An Idempotency-Key reused long after its retention horizon now re-executes instead of returning an expired error. Well before that, the error is unchanged.

    #2990 · 2026-08-19

v2026.08.19.8

2026-08-19
  • A fully swept run no longer reports itself as active forever

    A mark that outlives its evidence

    fixed control operators developers

    Run status is computed on read, and its "this run never had activity" test asked whether the sessions and connections tables were empty. Once retention reclaimed those rows the test passed again, so a finished run looked new.

    #2991 · 2026-08-19

v2026.08.19.7

2026-08-19
  • You can now collect a profile's unreachable artifacts through the API

    Expose what exists, at the authority it declares

    added control operators

    POST /v1/artifacts/collect runs the node's reachability-based artifact sweep for one profile and returns what it collected.

    #2979 · 2026-08-19

  • Make a chromiumoxide upgrade trip the workaround it could make removable

    The upgrade is the reminder

    internal node developers

    A same-document navigation workaround is pinned to the chromiumoxide version it was reasoned against, so the next upgrade fails the build instead of quietly outliving its cause.

    #2985 · 2026-08-19

  • Artifact provenance now reports which way the bytes flowed

    One hash, two possible origins

    added control developers

    The provenance oracle now reports a direction for each artifact plus the command span that minted it. Direction is derived from a closed verb set and reports unknown rather than guessing when the verb cannot determine it.

    #2992 · 2026-08-19

  • Locate a region by the hash of its content, not by a container that re-renders

    One region, four depths

    added node developers

    The node can now answer which subtree projects to a given sha256, the inverse of the projection-hash check that wait and act already carry.

    #2993 · 2026-08-19

v2026.08.19.6

2026-08-19
  • An upload now names the artifacts it attached

    Echoed, not observed

    added control developers

    act with verb upload now returns the artifact refs it attached, on the receipt. Proving N files are attached no longer means finding N chips in a perception digest that is capped and gets denser as N grows.

    #2980 · 2026-08-19

v2026.08.19.5

2026-08-19
  • Restore the reach namespace's lost documentation in the SDK

    A comment must touch what it describes

    fixed sdk developers

    The SDK reach namespace lost its docs when artifacts was inserted between the comment and the member it described. Hover and the published types showed nothing, including the note that claim is excluded on purpose.

    #2976 · 2026-08-19

  • Describe what perceive actually returns in its MCP output schema

    Declare the shape you send

    fixed mcp developers

    The perceive output schema said its perception field was passed through verbatim. That is only true in full mode, and the default is compact.

    added mcp developers

    The 12 keys the renderer adds to perception are now declared and documented, so clients can read the shape they receive.

    #2981 · 2026-08-19

v2026.08.19.4

2026-08-19
  • The provenance oracle now tells you its answer may be incomplete

    Empty is not not-found

    fixed control developers

    The provenance route's docs presented two causes of an empty answer as the complete set and called the ambiguity a security property. A third cause, the 500-session scan bound, is a completeness limit and now says so.

    #2959 · 2026-08-19

  • The SDK can now ask which session produced an artifact

    A hash is a question

    added sdk developers

    artifacts.provenance(hash) resolves a content hash to the sessions that produced it, with the verb, page and time.

    #2965 · 2026-08-19

  • A reaped session's recording is finalized before its browser is torn down

    Finalize first, then tear down

    fixed control operators

    The transport reaper tore down a crashed session's browser without first asking the node for its recording, so an opted-in capture was left unsealed and unindexed - and therefore unreadable.

    #2968 · 2026-08-19

  • Artifacts are not collected with the session, whatever our docs said

    Say what is true, and say the negative out loud

    fixed control developers operators

    The download-to-artifact endpoint promised that artifacts are garbage-collected with the session. Nothing collects them at session end.

    fixed mcp developers

    The download_to_artifact tool carried the same false guarantee. An agent read it, ended its session, and nothing was collected.

    #2971 · 2026-08-19

  • Dead session capabilities are reclaimed instead of waiting for org deletion

    A spent key is not a record

    fixed control operators

    A revoked or expired session capability row had no release path at all: only deleting the organisation removed it.

    #2972 · 2026-08-19

v2026.08.19.3

2026-08-19
  • Docs deprecate the env-var Bearer pattern, now that a saved login exists

    A frozen copy is not a credential

    deprecated docs developers operators

    Every MCP host recipe now leads with nightjar auth login. Carrying the key in an environment variable or header template is marked deprecated, with the incident that motivated it as the reason. No recipe is removed.

    #2946 · 2026-08-19

  • OAuth tokens are reclaimed once their grant is revoked, not once they expire

    The revoked row is the evidence

    fixed control operators

    The retention sweep deletes oauth tokens past their expiry whose grant is already revoked. An expired token under a live grant is kept: revoke reads it with no expiry filter, so deleting it would make revocation a silent no-op.

    #2955 · 2026-08-19

v2026.08.19.2

2026-08-19
  • Stop the recording gate's anti-vacuity control arm from flaking under load

    One deadline cannot serve two opposite polarities

    internal control developers

    One mock-node helper served two opposite expectations through a single timeout, so the deadline expiring was the PASS for four denial tests and the FAILURE for the arm that proves them non-vacuous.

    #2949 · 2026-08-19

  • Terminal reach grants are listed for 90 days, then reclaimed

    History has a stated length

    changed control operators developers

    A revoked or expired reach grant stays in the owner-scoped list for 90 days after it became terminal, and its row is then reclaimed.

    #2951 · 2026-08-19

v2026.08.19.1

2026-08-19
  • Retention keeps every idempotency ticket a replay can still reach

    Keep every ticket a replay can reach

    fixed control developers operators

    Retention keyed on session status, so it reclaimed idempotency tickets that the API would still serve replays for. It now keys on the handler's own reachability condition, and sweeps the fill-credential store too.

    #2942 · 2026-08-19

v2026.08.18.10

2026-08-19
  • The egress-audit dedup set now belongs to its session instead of the process

    Owned, so nothing is left to forget

    fixed node operators

    The egress-audit drain kept one dedup set for the whole node process, keyed by session and never pruned, so entries outlived the sessions that produced them.

    #2933 · 2026-08-18

v2026.08.18.9

2026-08-19
  • nightjar auth login: a saved login, so no token ever sits in a repo file

    The login names the destination, not the repo

    added cli developers operators

    'nightjar auth login NAME' signs you in by device flow and saves the credential to an owner-only local store under a name you choose. Nothing is typed at a prompt and no token is passed on a command line.

    added control developers

    The OAuth token response now names the binding it minted: the org and agent ids, plus their display names when the deployment has them. All value-free ids, never secret material.

    #2914 · 2026-08-18

  • The crashed-session reaper now reaches sessions that never held an identity

    A filter is not a definition

    fixed control operators

    The reaper's candidate query joined identity leases, so a session that never assumed an identity could never be a candidate for reclamation.

    #2928 · 2026-08-18

v2026.08.18.8

2026-08-18
  • Look up which session produced an artifact, by its content hash

    Ask the hash who made it

    added control developers

    A new provenance read on the /v1 artifacts path answers which session minted an artifact, with which verb, against which page, and when.

    #2895 · 2026-08-18

  • Reclaim stale MCP transport connection rows in the retention sweep

    Nothing else drains this table

    fixed control operators

    The retention sweep now deletes transport_connections rows that no live session can still be reaped through.

    #2916 · 2026-08-18

v2026.08.18.7

2026-08-18
  • Whether a command needs the server is now declared, not defaulted

    Absence of a declaration is not evidence of a value

    internal cli developers

    Every operation declares whether it needs the server; the CLI reads that instead of a denylist of one.

    #2892 · 2026-08-18

v2026.08.18.6

2026-08-18
  • MCP handshakes are now queryable per API key, not only greppable in logs

    Ask the platform, not the logs

    added control operators developers

    Each MCP handshake now records its outcome per API key, so a connect-failure rate is one security-log query instead of a day of log forensics.

    #2889 · 2026-08-18

v2026.08.18.5

2026-08-18
  • The console selector fields no longer claim CSS is the only form

    One parser, eight forms, three surfaces

    fixed console operators developers

    The Drive panel's selector inputs said "CSS selector", but the value is resolved with the full eight-form locator grammar — so seven forms were advertised as unavailable.

    Before
    After
    The session Drive panel's act selector: the placeholder now demonstrates both a bare CSS selector and a prefixed form, and the hint names all eight.

    #2883 · 2026-08-18

  • The typed client can now ask for part of a session journal

    Ask for the window, not the whole capture

    added sdk developers

    journal() and journalWithMeta() take an optional args object, so a caller can narrow a recorded journal by sequence cursor, time window, or verb instead of fetching all of it.

    #2885 · 2026-08-18

  • The typed client can filter a session's console log and network capture

    Take the slice, leave the document whole

    added sdk developers

    consoleLog() and networkHar() take an optional args object, so a caller can narrow by cursor, tab, level, URL, method or status range instead of refetching everything to poll.

    #2887 · 2026-08-18

  • Identity lease transitions are now recorded as events

    Write it down before it disappears

    added control operators developers

    Taking, releasing, force-releasing and reaping an identity lease now each write an event.

    #2888 · 2026-08-18

v2026.08.18.4

2026-08-18
  • Credential store errors now speak the auth surface's words

    One word, one meaning

    fixed cli operators developers

    Credential store errors now say credential rather than profile, which had three other meanings a reader could land on.

    #2871 · 2026-08-18

  • An act receipt now names the span its network traffic is stamped with

    Start from the act, not the journal

    added node developers

    ActReceipt now carries commandSpanId - the same key network_log entries publish as _commandSpanId - so a client can go from an act straight to the traffic it provoked.

    #2882 · 2026-08-18

v2026.08.18.3

2026-08-18
  • Troubleshooting now states which field carries what, on each path

    Match the code, not the message

    added docs developers

    A troubleshooting section stating which error field rides which path, and where to read it.

    fixed mcp developers

    Corrected a module header that described the MCP error result as carrying only a code and a message.

    #2878 · 2026-08-18

  • Network log entries now name the act that was in flight when they started

    Which requests did this act cause

    added control developers

    Each network_log entry can now carry _commandSpanId - the command span in flight when that request STARTED - so act-caused traffic is identifiable without matching timestamps.

    #2881 · 2026-08-18

v2026.08.18.2

2026-08-18
  • Fetch a session's timeline for a time window, not just from a cursor

    A cursor cannot name the ten minutes it went wrong

    added control developers

    The journal and session-activity reads take since and until, so you can ask for the window a session misbehaved in instead of paging from a cursor.

    added control developers

    Journal events now carry the tab they belong to, and the journal read takes a coarse verb filter.

    #2874 · 2026-08-18

  • The v1 error contract now says which token the code field carries

    Same name, different token

    docs control developers

    V1Error.code now documents that it carries the RENDER token, and which field the same token rides on the other paths that emit a Nightjar error.

    #2875 · 2026-08-18

  • CLI help now describes the full locator grammar it accepts

    Say what the flag really takes

    fixed cli operators developers

    Sixteen selector flags said CSS selector while accepting eight locator forms; four that really are CSS-only were left alone.

    #2879 · 2026-08-18

v2026.08.18.1

2026-08-18
  • Docs qualify the OAuth login as remote-MCP, before a second one lands

    Name it before there are two

    docs docs developers operators

    Nine docs sites that said OAuth login now say remote-MCP OAuth login, so the shipped host flow stays distinguishable once nightjar auth login adds a second one.

    #2853 · 2026-08-18

  • Docs honesty gate now checks that cited symbols exist in the tree

    A citation that names nothing is not a citation

    internal docs developers

    A Today page that cites a symbol now fails CI if that symbol resolves to no source file.

    #2857 · 2026-08-18

  • Artifacts now record the page they were produced against

    Every artifact remembers where it came from

    added node developers

    Session artifacts now carry the page URL they were minted against, captured best-effort at mint time.

    #2869 · 2026-08-18

v2026.08.17.2

2026-08-18
  • Declare the mcp serve command, its operation contract and its error family

    Declared before it is built

    added cli developers

    A repo can now declare its MCP entry as a command that names a saved login, rather than an HTTP entry carrying a credential in a header template.

    #2828 · 2026-08-17

  • The SDK now refuses a publish that would ship an uninstallable package

    Publish with the tool the manifest was written for

    fixed sdk developers

    0.1.0 reached the registry uninstallable, because npm publish neither applies publishConfig nor rewrites a workspace range. The tree is fixed for 0.1.1, and a prepublishOnly guard now refuses the wrong publisher.

    #2832 · 2026-08-17

  • The credential security guide promised a scope clamp that no longer holds

    A gate is not a wall

    fixed docs operators developers

    The published guide said a grant can never carry a write or admin scope. Since the owner-consent addendum an owner may consent to one, so the guarantee was false in the reassuring direction.

    #2838 · 2026-08-17

  • The publish guard now covers every package, and builds before it checks

    An empty package is a broken package

    fixed sdk developers

    api-types 0.1.0 shipped with a correct manifest and an empty tarball, so the SDK installed and imported but failed every consumer tsc. The guard is now shared, and prepublishOnly builds first.

    #2840 · 2026-08-17

v2026.08.17.1

2026-08-17
  • Document where the agent credential store lives, and why it refuses to guess

    No fallback for a secret

    docs docs operators developers

    The credential-security guide now states the store root, the NIGHTJAR_CREDENTIALS_DIR override, and why an unset home is an error rather than a fallback.

    #2830 · 2026-08-17

v2026.08.16.2

2026-08-17
  • The token response now names which credential AND which instance

    One stable anchor, one moving marker

    added control developers operators

    The OAuth token response gains two value-free extension members: a credential id that is stable across refreshes, and a token instance id that is new on every refresh. Both are ids, never secret material.

    #2794 · 2026-08-16

  • Reach claim now retires every superseded join token

    One live key at a time

    security control operators developers

    Claiming a reach grant now revokes the join tokens it supersedes, so an older secret stops authorizing a daemon join the moment a newer one is issued.

    #2798 · 2026-08-16

  • Refuse to open a credential store on a root we cannot lock

    A locked door in an open corridor is a locked door

    security cli operators developers

    Opening the credential store now locks and checks its directory first, and refuses rather than proceeding when it cannot.

    #2800 · 2026-08-16

  • Add the MCP proxy credential-attach policy for ADR-056 C2

    The credential goes one place only

    added mcp developers

    The stdio MCP proxy re-reads its credential per request, sends it only to the profile's pinned origin, and reports which credential it attached without ever printing it.

    #2806 · 2026-08-16

  • Document the agent credential store's shipped storage guarantees

    Storage is part of the security model

    docs docs developers operators

    The credential security model now covers where an agent's own platform credential lives on disk, and what the file backend guarantees about it.

    #2812 · 2026-08-16

  • Motto gate: arcs are no longer rejected for their flags

    fixed docs developers

    The changelog gate read an elliptical arc's flags and radii as coordinates, so any motto drawn with a curve failed the safe-band check wherever its art actually sat. Path data is now parsed per command.

    #2817 · 2026-08-16

  • Guard the workspace member and node Dockerfile COPY invariant

    A member with no COPY line is a build that cannot start

    internal node developers

    Adding a crate to the workspace without a matching COPY line in the node Dockerfile now fails a lane-tooling arm that names the crate, instead of failing the image build much later.

    #2818 · 2026-08-16

  • Refuse a pasted credential where a saved login name is expected

    A token is not a name

    security mcp operators developers

    Pasting a Nightjar key where a saved login name belongs is now refused, instead of being repeated back inside the error message.

    #2821 · 2026-08-16

  • Pin an MCP origin to an IPv6 address without naming a port

    The brackets are the boundary

    fixed mcp operators developers

    A bracketed IPv6 literal without a port was refused, because the authority was split on its last colon and an IPv6 address carries colons inside the host.

    #2822 · 2026-08-16

  • Changelog summaries may now name the identifier they are about

    changed docs developers

    The underscore enters the summary allowlist, so an entry can write NIGHTJAR_REQUIRE_DB_TESTS instead of circumlocuting it. Headlines keep the narrow set and stay scannable at chip size.

    #2823 · 2026-08-16

  • Credential refusals name the profiles you have, never the one you typed

    Answer the next question, not the last mistake

    security mcp operators developers

    Pasting a credential where a profile name goes no longer puts it into an error message, and so into every log or screenshot that captures one.

    #2824 · 2026-08-16

  • The changelog contract now tells you what to do when no component fits

    Count the gap you cannot see

    docs docs developers

    The live contract now carries the rule for declaring changelog:none when no component fits, so an author meets it where they already look.

    #2825 · 2026-08-16

v2026.08.16.1

2026-08-16
  • The credential leaves the environment

    Read at request time, not at launch

    added docs developers operators

    ADR-056 decides the agent credential binding: a local multi-profile credential store consumed by a stdio MCP proxy that attaches authorization at request time, replacing the env-var Bearer header pattern that cost a five-hour incident.

    #2759 · 2026-08-16

  • The access-request deep link no longer says a pending request is resolved

    Say only what you can see

    fixed console operators

    Opening a request deep link while a different org is active told you the request was already resolved. It now says only that the request is not in this org's queue.

    Before
    After
    The deep-linked request is absent from the active org's queue. Before: the note declares it already resolved with nothing left to action. After: the note states only that it is not in this org's queue, and offers the org switch.

    #2763 · 2026-08-15

  • Tell the two screenshot refusals apart, so nobody hunts a build that works

    Two silences that need opposite answers

    fixed docs developers

    When a capture refuses because it cannot find your text, it now says whether the page rendered or not.

    #2764 · 2026-08-15

  • The deploy verify takes a ref, so an expected build cannot be mistyped

    Do not check for the mistake; remove the chance

    changed deploy operators

    The expected build can now be given as any ref, resolved internally, instead of a copied commit id. A ref has nothing to transcribe, and a bad one is reported as a caller error rather than as a failed deploy.

    #2770 · 2026-08-15

  • Name the hosted URL when the CLI cannot reach a Nightjar server

    Say where else the server might be

    changed control operators developers

    When the CLI cannot reach a server it now names the hosted platform URL as well as the local options, so a first run against the cloud does not fail with only localhost advice.

    #2773 · 2026-08-16

  • Stop a required reach test flaking when a sibling test reaps first

    Assert the row, not the batch

    internal control developers

    Three reach tests asserted on the reaper's batch report instead of on the grant they were testing, so a required postgres check could fail with a zero-scan signature.

    #2776 · 2026-08-16

  • Changelog entries can name the CLI as their component

    The audience arrived, so the slot opened

    added docs developers

    The changelog contract gains a cli component, so a change to the command-line tool can be classified as what it is instead of borrowing a neighbouring slot.

    #2778 · 2026-08-16

  • Assert reaper idempotence on the row rather than a global batch counter

    Two sweeps pass, the row is unchanged

    internal control developers

    Four assertions in the transport reap suite compared a globally-scoped batch counter, so a sibling test's candidate could red a healthy run while never asserting anything about the row under test.

    #2783 · 2026-08-16

  • Type-check the Windows-only code that CI could never compile

    No code ships that no compiler has read

    added docs developers

    CI now type-checks every crate that contains Windows-only code, instead of skipping it in silence.

    #2787 · 2026-08-16

  • Split the credential id so a stale token binding is visible

    One id says which; only two say which one, now

    internal cli developers

    A session credential now carries a stable id and a per-refresh instance id, instead of one id that conflated them.

    #2789 · 2026-08-16

  • Ask for a fresh reach claim code when the old one is lost

    One lost code, one deliberate replacement

    added control operators developers

    POST /v1/reach/ensure accepts remintClaim. Declare it and the outstanding claim code is revoked and replaced atomically; omit it and repeated polls reuse the live code exactly as before.

    added mcp developers

    The local reach ensure tool gains the same optional remintClaim argument, defaulting to false.

    #2792 · 2026-08-16

  • Lock the credential store to its owner on Windows, and prove it

    A permission you did not verify is a permission you do not have

    security cli operators developers

    On Windows the credential store's files are now restricted to their owner, and the restriction is read back and proven rather than assumed.

    #2793 · 2026-08-16

  • Refuse a spec check that would compare the branch against itself

    A file is not the file you asked for

    fixed docs developers

    A spec drift check could fetch its baseline from the wrong commit and report no drift forever, without ever failing.

    #2796 · 2026-08-16

v2026.08.15.2

2026-08-16
  • Pickup grants now say how long the agent has to collect its key

    A window you can see closing

    changed console operators

    Approving a pickup grant now shows when the collection window closes, instead of only saying the agent will fetch its own key.

    #2724 · 2026-08-15

  • A map of how work is modeled here

    The map names what the territory assumes

    added docs developers

    A new repo-root reference, WORK CONCEPTS, explains how work is modeled: the units of design, work, planning, tracking, specification and memory, their relations, and which concepts are materialized versus convention versus implicit.

    #2725 · 2026-08-15

  • Retire the hand-maintained changelog and preserve its releases on the site

    Nothing was deleted, only moved

    changed docs developers operators

    The changelog page now carries the two releases that predate the per-PR system, under a Before the per-PR system section, and the root file is a dated pointer rather than a second source of truth.

    #2728 · 2026-08-15

  • Add a console screenshot tool that refuses to shoot a broken page

    Better no picture than a plausible one

    added docs developers

    changelog-capture takes the console screenshots this changelog has required since day one, and refuses rather than write one it cannot vouch for.

    added docs developers

    It refuses an over-size capture before the browser starts, with the arithmetic and a remedy.

    #2732 · 2026-08-15

  • Flag path segments that could hide a test input from the CI gate

    A short list beats a silent zero

    added control developers

    A guard now keeps an annotated review list of every path built from chained join() literals, and fails only on one whose segments could compose a path the CI filter drops.

    #2733 · 2026-08-15

  • Underline inline links on the docs site, and put that site in the a11y net

    A link you can find without colour

    fixed docs developers operators

    Inline links in docs prose are underlined, so they are distinguishable without relying on colour. Nine of twelve pages carried this, and it was the only serious accessibility violation on the whole site.

    internal docs developers

    The docs site is now covered by the accessibility job, which previously ran two other apps and had no test files at all for this one.

    #2736 · 2026-08-15

  • Pin that an opted-out org can never be handed self-reach by the key template

    A gate is only as good as its refusal

    internal control developers

    The agent-key template's opt-in condition now has a negative arm on the mint path: an org that has not enabled agent self-reach must never be handed reach:self.

    #2739 · 2026-08-15

  • Show the changelog reminder on the checks tab, and say when it was not checked

    A warning nobody reads is not a warning

    changed docs developers

    The entry-contract check now writes its advisories to the run summary, where they are visible without opening a log.

    fixed docs developers

    Running the check on your own machine now says that it did not look at whether this branch owes an entry.

    #2745 · 2026-08-15

  • A key mint now says when the agent template did not apply, and why

    A 2xx should not hide a surprise

    added control developers

    The 201 from POST /v1/keys now carries templateApplied, plus a closed-enum reason when the agent-key template was eligible but something blocked it.

    #2750 · 2026-08-15

  • Verify which build a site is actually serving, not just that it answers

    The deploy already told us; nobody was reading

    added deploy operators

    A deploy can now be checked against the build it shipped, rather than against a 200. Both sites answer 200 on every path, so the old check could not tell a current site from one serving an old build.

    #2760 · 2026-08-15

  • Links inside prose are underlined again, everywhere, by default

    Colour is not an affordance

    fixed docs operators developers

    An inline link in a block of text no longer relies on colour alone to be recognisable as a link.

    #2761 · 2026-08-15

  • The public changelog stops linking where visitors cannot follow

    A link a visitor cannot follow is worse than none

    fixed docs operators developers

    Every reference on the public changelog page that pointed into the private source repository is now plain text, so a visitor no longer clicks through to a login wall.

    #2762 · 2026-08-15

v2026.08.15.1

2026-08-15
  • The grant screen stops claiming a key was shown when none was minted

    Say only what happened

    fixed console operators

    Approving an access request now reads the receipt before deciding what to show, instead of always revealing a secret.

    The access requests screen, where approving a request decides between revealing a key and handing off to pickup.
    The access requests screen, where approving a request decides between revealing a key and handing off to pickup.

    #2692 · 2026-08-15

  • A malformed key-mint body now returns a readable error, not a bare 422

    Refusing is only half; being readable is the rest

    fixed control developers

    Sending a malformed body to the key-mint route now returns the normal error envelope, which names what was wrong. Previously the rejection arrived as a bare 422 with no envelope, so the explanation was discarded before the caller saw it.

    #2693 · 2026-08-14

  • Add the changelog authoring flow: a finalize script and a skill

    Draft it, then give it a number

    added docs developers

    A finalize script promotes your draft into its PR directory and stamps the number.

    added docs developers

    A changelog-entry skill covers the fields, the prose rules, and how to draw a motto.

    #2695 · 2026-08-15

  • A person on the OAuth approval leg gets a page, not a JSON blob

    A human leg deserves a human answer

    fixed control operators

    The three browser-facing legs of the device-approval flow now render a titled HTML error page instead of the API's JSON error body.

    #2696 · 2026-08-15

  • The changelog is a page you can read, not a file you have to find

    Every change, drawn and dated

    added docs operators developers

    The docs site gained a changelog page that renders every shipped entry, newest first, with its drawing.

    #2697 · 2026-08-15

  • Report a suppressed screenshot as a confirmed failure, not as never started

    The capture ran; the answer never arrived

    fixed node developers

    A screenshot withheld because a secret field could not be safely redacted now reports its outcome certainty as a confirmed failure, not as an operation that never started.

    fixed node developers

    The same corrected certainty is visible to MCP clients reading the error envelope of a suppressed screenshot.

    #2701 · 2026-08-15

  • Approving a device sign-in now works when you are signed out

    The code survives the trip

    fixed control operators

    Following a device sign-in link while signed out used to drop the code and leave you on the console with nothing to approve. The approval page now renders after you log in.

    changed control operators

    If you belong to more than one organisation, the approval page now asks which one to approve as, instead of returning an error that named an HTTP header.

    #2713 · 2026-08-15

  • The console tells you when your build is behind the changelog

    You are three releases behind

    added console operators

    A banner appears when the console you are running is not current with the shipped changelog, and links to what you are missing.

    #2719 · 2026-08-15

  • Drive the device-grant approval walk against a real control

    Assert the form, not the status

    internal control developers

    The device-grant approval leg is now exercised end to end against a real control and a real postgres, covering the six states a fixture can hold honestly.

    #2720 · 2026-08-15

v2026.08.14.7

2026-08-15
  • Add the illustrated per-PR changelog and its contract gate

    Every PR tells its own story

    added docs developers

    Every PR now ships a small illustrated changelog entry: what changed, who it affects, and a drawing.

    added docs developers

    A CI gate validates every entry: schema, filing, prose, illustration and screenshots.

    #2683 · 2026-08-14

  • Access request audits now name the human who approved them

    A record that names a person

    added control operators

    An access request actioned by a signed-in human now records that person, not only the key they acted through. A row names a key approver or a human approver, never both.

    #2684 · 2026-08-14

  • Refuse a mistyped access request instead of accepting it silently

    A typo should not look like success

    fixed control developers

    Filing an access request with a misspelled field now fails with a 400 that names the offending field. Previously the unknown field was ignored and the request was accepted, so a typo produced a scopeless request that looked like success.

    added control developers

    The create and status responses now echo back the scopes and delivery mode as recorded, including the defaulted delivery mode, so a caller can confirm what was actually stored.

    #2687 · 2026-08-14

v2026.08.14.6

2026-08-14
  • Rotate a key with no paste: the operator initiates, the key picks itself up

    The last paste, removed

    added control operators developers

    Rotating an agent credential no longer moves a secret by hand. The operator initiates the rotation, and the replacement is minted only when the key itself collects it.

    #2682 · 2026-08-14

Before the per-PR system

Releases before ADR-055 — the decision that introduced the per-PR changelog you are reading — were recorded by hand in the project's root CHANGELOG.md. That file is now retired and its contents are preserved here unchanged, so this page is the complete record.

v2026.06.28.1 — 2026-06-28

⚠ BREAKING — egress

  • intranet_mode is now enforced unconditionally. A cloud session's tunnel reach to undeclared private/loopback hosts (RFC1918, CGNAT, IPv6-ULA literal IPs, loopback IPs, and localhost-family names) is now denied unless the org sets intranet_mode=true in governance — regardless of the NIGHTJAR_TUNNEL_REQUIRE_DECLARED operator switch. Previously, with that switch at its default (off), private/loopback tunnel reach was permitted. Every org defaults to intranet_mode=false, so any org relying on undeclared private or loopback tunnel automation must turn intranet mode on (Settings → governance, org:admin), or declare the specific host/CIDR on the network's allowlist (a declared target stays reachable even with intranet mode off). The always-on egress floor (cloud-metadata 169.254.169.254, link-local, platform-internal CIDRs) and the env screens (NIGHTJAR_EGRESS_SCREEN_INTERNAL, NIGHTJAR_PLATFORM_CIDRS) are unchanged — only the private/loopback class decision moved under intranet_mode. (#653; ADR-021 amendment.) Rollback: deploy/deploy.sh --version v2026.06.27.6.

Added

  • Org capture-policy v1 (#652): a per-org default capture_mode (minimal / standard / diagnostic / forensic — the one capture ordinal the node enforces on the start_session wire), alongside the existing per-org network_log default (all four tiers, node-enforced). Both are authored from Settings → Data governance (org:admin). Migration 0027 is additive and nullable (NULL = no org default → the session falls through to the node default diagnostic), so existing orgs are unchanged. The other model knobs (separate journal/screenshots/dom_perception, viewport_recording, credential_fill_window) are deliberately not authored: the node has no per-facet param, so a separate org column would be inert. (ADR-015 §8.)
  • Cross-language summarize() parity gate (#651): shared fixtures assert the Rust (replay.rs) and TypeScript (real.ts) journal-event summarizers produce identical output; CI fails on divergence. (Codegen-unification of the two summarizers stays deferred; one best-effort fallback arm is a tracked known-divergence.)
  • Tunnel egress-floor integration test (#649): asserts the never-allow floor denies a cloud-metadata target on the live CONNECT data path, not just in isolation.

Internal / architecture

  • Arch-tier guard (#648): a new rs-foundation-data-tower tier in .nj-arch.toml machine-enforces the nightjar-data decomposition's no-back-edge invariant — the three pure leaves (nightjar-net-registry, nightjar-perception-data, nightjar-session-data) may depend down on rs-foundation but the base can no longer depend up on them. nightjar-profile-data deliberately stays at rs-foundation (the base legitimately depends on its ProfileSpec).

v2026.06.27.6 — 2026-06-27

  • Console power-user kernel (ADR-030) landed, with the design-system debt burned down: every list screen sits on the kernel and the legacy ExpandableTable/ExpandableRow primitives are removed; an accessibility gate guards the showcase.
  • nightjar-data god-crate decomposition (#601): three leaf crates extracted (nightjar-net-registry, nightjar-perception-data, nightjar-session-data), plus nightjar-svc and ws-bind split into per-responsibility modules.
  • App-Surface hardening (ADR-033 Slice 1): loopback-only egress floor with DNS-rebinding / TOCTOU dial-pinning on attach/backfill/observer, a deterministic size cap on imported app-evidence payloads, and a perceiveControls() advisory instead of a silent drop.
  • Org-default network-capture tier + honest /trust disclosure (#416 v0, #420), plus a per-agent default network_log tier with New-session pre-fill (#417).
  • Migration-gate hardening (fail on duplicate / non-increasing migration version), the architecture size-gate turned into a tightening ratchet, and adversarial KMS envelope-crypto tests.