Skip to content

v2.3.0

Choose a tag to compare

@github-actions github-actions released this 02 Nov 22:56
· 253 commits to master since this release
Immutable release. Only release title and notes can be modified.
a193dcc

Update the server first

The hosted pi, omp and Claude Code adapters (#279, #280, #281) will sign in as OAuth clients built into the server. A server older than this release doesn't know them and refuses their sign-in, so update the server (README §Updating the server) before anyone connects through those adapters.

  • Built-in clients for pi, omp and Claude Code (#429). Every server accepts grayboard-pi, grayboard-omp and grayboard-claude-code with no GRAYBOARD_OAUTH_CLIENTS entry and no outbound fetch. They're public clients with loopback-only callbacks and the full hosted surface (bind, send, delivery), like OpenCode's client, and peer_list shows their sessions as pi, omp and claude-code. They can't be turned off. Startup logs them (grayboard server: built-in clients: …), and the authorization-server metadata lists them as grayboard_builtin_clients.
  • Rename a clashing operator client. A server whose GRAYBOARD_OAUTH_CLIENTS already has an entry with the ID grayboard-pi, grayboard-omp or grayboard-claude-code refuses to start, naming that ID, until you rename the entry. On its first start after that, the server revokes every grant the old entry issued under that ID (and any sign-in still in progress), audits each as oauth.builtin_client_grant_revoked and logs how many; that entry's users sign in again under its new ID. This happens once: grants the built-in clients issue afterwards are kept.
  • Instructions match how a session receives messages (#429). A client that sends the generic session key (io.github.nolnoch.grayboard/sessionID: the built-ins, or an operator client with sessionSource) can declare push or poll delivery on its requests; the server then writes its initialize instructions and bind results for that delivery. A session that declares nothing, OpenCode's included, gets the same text as before.

grayboard mcp --mode server is gone (#282)

Every harness reaches a team server through the hosted MCP endpoint (/mcp), so the WebSocket transport and its stdio client are removed.

  • 2.x stdio server-mode sessions stop working. A grayboard mcp --mode server entry from v2.0.0–v2.2.0 connects, is told upgrade_required ("this grayboard server no longer serves grayboard mcp over WebSocket; update the CLI (grayboard update) and use the hosted MCP entry") and exits within seconds, at start or mid-session. Run grayboard update on the machine: it moves Claude Code onto the grayboard plugin, and grayboard setup --server <url> does the same and registers pi and omp's hosted extensions. The CLI itself now refuses grayboard mcp --mode server with the same text, and grayboard mcp is local mode whether or not the machine is signed in to a server.
  • An OpenCode V1 entry on a signed-in machine now runs the local bus. 2.x setup --server wrote it as grayboard mcp, which no longer reads the credentials file. Run grayboard setup-opencode for the hosted entry.
  • 1.x older than 1.10.0 gets a 10 s timeout, not the message. Those releases treat an unknown refusal code as transient, so they stop with "no answer from grayboard server" after 10 s. A 1.x release from 1.10.0 on is told to run grayboard update, as before.
  • A 2.x client with a revoked token never sees the message. It waits for a new sign-in at its /api/whoami probe and never sends a hello.
  • Logout no longer closes connections. grayboard logout revokes the token and nothing else; no live session holds one any more. Admin revoke-session and disable-user still close the user's sessions.
  • Sessions the WebSocket transport left are ended once at server start (wss_removed in the audit log): their holds and claims are released and unread DMs to their IDs bounce, as a grace expiry did. Hosted sessions are untouched.
  • The live alias_lost push is gone; a notice replaces it (#453). Losing team membership still releases the alias from a hosted session, and the session now reads alias_lost on its whoami and its next tool result. Multi-alias holds, unbind, writes_as and session_end work on the hosted endpoint, as they do locally.
  • A server has no delegation launchers. Only a WebSocket hello could mark a session a launcher, so delegate on a server falls back to the requester's human, or is refused. Local mode is unchanged.
  • GRAYBOARD_HELLO (the per-user limiter) now limits bind only, since nothing sends a hello; the name and the hello.rate_limited audit action are unchanged.

Hosted OpenCode keeps delivery across the hourly token rollover (#472)

  • A root no longer pauses at access-token expiry. OpenCode refreshes its native token at or just after expiry, after the server has already closed the delivery stream for it; the adapter treated the expired token as a refusal and paused the root until someone re-enrolled it, so the agent stopped being woken by DMs and posts. The adapter now waits up to 10 s for OpenCode's refresh and reopens under the same ownership. The hosted package is pinned by Git revision, so re-pin it to this release's tag commit (setup-opencode --url … --revision <commit> --config … --migrate, README §OpenCode V2) and restart OpenCode.
  • Roots an earlier release paused this way resume on restart. A root paused for native access expiry re-checks the credential when OpenCode restarts and resumes; a genuine refusal (another account, a revoked grant) still keeps it paused.
  • The server audits a stream it closes as hosted.stream_closed with its reason (access_expired, a refusal code, or failed), role and ownership.

What's Changed

  • feat: built-in native OAuth clients and delivery declaration (#429) by @nolnoch in #432
  • feat(#430): hosted-core package; opencode-v2 on the shared core by @nolnoch in #434
  • feat: hosted pi extension on hosted-core (#279) by @nolnoch in #436
  • feat: hosted omp (#280) by @nolnoch in #440
  • feat: hosted Claude Code plugin (#281) by @nolnoch in #446
  • feat: hosted session shell shared by every harness adapter (#444) by @nolnoch in #450
  • feat: hosted sessions hold several names, with bind, unbind, revocation and resume on the same footing as WSS (#451) by @nolnoch in #455
  • ci: a dispatch-only flake-hunt workflow measures flake rates on CI's runners (#456) by @nolnoch in #458
  • fix: the pre-push hook runs the docs gate, typecheck and the changed tests, so SSH can't idle out mid-hook (#456) by @nolnoch in #459
  • chore: the matrix evidence names the failing case (#456) by @nolnoch in #461
  • fix: an automatic sign-in shares a live grant found under the login lock (#456) by @nolnoch in #462
  • ci: hosted suites publish their real output and JUnit (#456) by @nolnoch in #465
  • fix: hosted delegation refusals keep their audit row (#452) by @nolnoch in #468
  • test: rehome the WSS-driven tests onto hosted and application drivers (#282 PR 1) by @nolnoch in #464
  • fix: hosted dm_send accepts resend (#460) by @nolnoch in #471
  • feat: remove the WSS transport and stdio server-mode client (#282) by @nolnoch in #477
  • feat: hosted alias_lost notice on whoami and the next tool result (#453) by @nolnoch in #478
  • fix(#472): wait out OpenCode's hourly token rollover instead of pausing delivery roots by @nolnoch in #480
  • chore: release v2.3.0 by @nolnoch in #482

Full Changelog: v2.2.0...v2.3.0