Skip to content

feat(agents): sign Pi in from Setup with provider keys and a status check - #79

Merged
dizys merged 2 commits into
mainfrom
feat/pi-sign-in
Nov 1, 2026
Merged

dizys merged 2 commits into
mainfrom
feat/pi-sign-in

Conversation

@dizys

@dizys dizys commented Nov 1, 2026 •

Copy link
Copy Markdown
Owner

Summary

Pi landed as install-only on the Agents page (#76). It had a "Pi" text tile, a status line telling you to run t3-login pi, and no sign-in status or controls. This PR gives it the same treatment as the other agents.

  • Icon. Pi's own mark, from T3 Code's Pi provider definition (packages/provider-pi/src/client.ts). It is one colour, so it follows the theme.

  • Sign-in status. The probe runs pi --list-models with PI_OFFLINE=1. Pi lists only providers it holds credentials for, so this covers saved keys, /login subscriptions, environment keys, models.json and extensions. T3 Code uses the same signal to decide Pi can start a turn. A probe that cannot answer still shows "Couldn't check its sign-in", never "Not signed in".

  • Sign in. The row's Sign in button opens a sheet that:

    • saves an API key for one of 35 providers, or any id through Other, into Pi's auth.json;
    • lists what Pi is signed in to, by provider and kind (subscription, API key or environment variable), never the secret, and removes one provider's sign-in;
    • gives the steps for subscriptions (Claude Pro or Max, ChatGPT, Copilot): t3-login pi, then /login. Only Pi itself can do that sign-in, and it has no command Setup could run.

    The row menu also has Sign in with a subscription…, which opens the sheet on those steps.

  • Manage keys. OpenCode and Pi take a key per provider, and their sheet also lists and removes saved keys. Their button now reads Add key until a key is saved and Manage keys after. Keys in Pi's environment don't count, since the sheet can't change them. The README picture shows OpenCode's row, so it is regenerated.

How keys are written

Pi has no command that saves a key, so Setup writes auth.json itself:

  • under the same proper-lockfile lock (auth.json.lock) that Pi takes for its own writes and token refreshes, with Pi's 30 second staleness rule;
  • replaced in one step, through a link if auth.json is one (a link to a missing file is refused);
  • in PI_CODING_AGENT_DIR when that is set, keeping every other provider and any extra settings saved with an earlier key;
  • never over a /login subscription without confirmation, because Pi keeps one sign-in per provider;
  • never with a key that starts with ! or contains $, because Pi would run it as a command or expand it as a variable.

Screenshots

The same fixture data on main and on this branch.

Agents, desktop

Before After, signed out After, signed in
Pi row on main with a Pi text tile and terminal instructions Pi row with its mark, Not signed in and a Sign in button Pi and OpenCode rows with Manage keys, Pi signed in to Anthropic, GitHub Copilot and OpenRouter

Agents, phone (dark)

Before After
Pi row on a phone on main Pi row on a phone, signed in

Sign-in sheet

Desktop, light Desktop, dark
Sign in to Pi sheet with provider picker, API key, subscription steps and saved sign-ins The same sheet in dark appearance
Phone Phone, from "Sign in with a subscription…" Replacing a subscription
Sign in to Pi sheet on a phone The phone sheet opened on the subscription steps Confirmation before a key replaces an Anthropic subscription

Testing

  • node --test tests/*.test.mjs: 1081 of 1082 pass. The one failure, "saved API token works through the CLI and connection test" in credentials-api.test.mjs, is flaky under parallel load. It passes 3 of 3 times alone, on this branch and on main, and touches nothing here.
  • New tests/pi-auth.test.mjs (12 tests): saving beside subscriptions, replacement only on request, refused keys and ids, removal, unreadable files left untouched, links, waiting for and clearing Pi's lock, PI_CODING_AGENT_DIR, environment keys, model-list parsing, the probe, and the HTTP routes against the real setup server (no secret in any response).
  • scripts/pi-auth-smoke.mjs against real Pi 0.80.5 (the supported floor) and 1.4.0: passes on both.
  • The probe against those real binaries: signed out, then signed in after saving a key, then signed out after removing it; a key in the environment reads as signed in.
  • scripts/opencode-auth-ui-audit.mjs (the key sheet is shared with OpenCode): every layout passes, now opening the sheet from Manage keys once accounts are loaded. scripts/harness-ui-audit.js: 29 of 29. shellcheck on smoke-test.sh: clean.
  • 360 px phone and the embedded frame, light and dark: no horizontal overflow in the row or the sheet.
  • Not run locally: the image smoke test (no Docker here). It gains two checks: the native round trip against the installed Pi, and signing Pi in and out through the Setup API.

Not in this PR

  • Running Pi's subscription /login from the console. Pi has no CLI or RPC command for it.
  • pi auth check per provider (Pi 0.84.1 and newer). The model list already covers every credential source and also works on older versions.

🤖 Generated with Claude Code

dizys and others added 2 commits November 1, 2026 10:11
…heck

Pi was install-only on the Agents page: a "Pi" text tile, no sign-in
status and no sign-in controls, only a line telling you to run
t3-login pi in a terminal.

- Icon: Pi's mark from T3 Code's own Pi provider definition, in
  currentColor so it follows the theme.
- Status: the harness probe runs `pi --list-models` offline. Pi lists
  only providers it holds credentials for, so this covers saved keys,
  /login subscriptions, environment keys, models.json and extensions,
  and matches how T3 Code decides Pi can start a turn. Pi's credential
  variables now count as present credentials.
- Sign in: a sheet with a provider picker saves an API key to Pi's
  auth.json. Pi has no command for this, so Setup writes the file under
  the same proper-lockfile lock Pi uses, replaces it in one step (through
  a link if auth.json is one), honours PI_CODING_AGENT_DIR and keeps
  other providers and extra key settings. A key never replaces a
  subscription without confirmation, and keys Pi would run (!) or expand
  ($) are refused.
- The sheet lists what Pi is signed in to (provider and kind, never a
  secret), including keys from the environment, removes one provider's
  sign-in, and gives the t3-login pi then /login steps for subscriptions,
  which only Pi itself can do.

Tests cover the credential file, lock interplay, links, the probe and the
HTTP routes. scripts/pi-auth-smoke.mjs checks the writes against a real Pi
(passes on 0.80.5 and 1.4.0) and the image smoke test signs Pi in and out
through the Setup API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OpenCode and Pi take a key per provider, and their sheet also lists and
removes saved keys. The row's button read "Add key" even with keys saved;
it now reads "Manage keys" once OpenCode or Pi's auth.json holds one, and
"Add key" until then. Keys in Pi's environment don't count: the sheet
cannot change them.

The README picture shows OpenCode's row, so it is regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dizys
dizys merged commit 7e63fb1 into main Nov 1, 2026
13 checks passed
@dizys
dizys deleted the feat/pi-sign-in branch November 1, 2026 22:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant