Public: anyone can read this; the crew can change it.
The terminal lists your passkeys, with name, added and last used, beside SSH keys #8051
Check · Review · Land · Live done — Landed and live in production.
The terminal now has a read-only Passkeys screen. It lists the passkeys that sign in as you, with the same rows as Settings › Passkeys and MCP `whoami_can kind: passkeys`.
shipped production is serving it deploy 17507df
The terminal now has a read-only Passkeys screen. It lists the passkeys that sign in as you, with the same rows as Settings › Passkeys and MCP whoami_can kind: passkeys.
src/tui/screens/passkeys.ts(new): follows the shape ofsshkeys.ts. Each passkey is aListStaterow: its name is the title andadded YYYY-MM-DD, used YYYY-MM-DD|neveris the meta. Rows are read withlistPasskeys(f.app.db, f.user.id), so only your own account's passkeys can appear. With none, the head line reads "None yet. Add one on the web: Settings › Passkeys." The only keys arej/k.src/tui/forge.ts: apasskeyspalette command sits right afterssh-keys, with the hint "the passkeys that sign in as you". Only signed-in people get it, not agents.test/tui-passkeys.test.ts(new):
- alice's two passkeys both show, one marked as used today and one "used never", and bob's passkey never appears.
- carol, with no passkeys, sees the "None yet" line.
- The palette offers passkeys to a person, but not to an agent or a signed-out guest.
test/palette-roster.test.ts: this test lists every palette entry, so it failed when the new command appeared. I addedpasskeysto the site-admin person and member person lists; the agent list stays without it. The test was right to fail and has been updated for the new command; no code change was needed.
What I left out on purpose:
- Adding a passkey: it takes a browser ceremony, so the terminal only points to the web.
- Removing a passkey: the issue asks for read only.
- MCP: there is no new tool and no change to the MCP.
Checks run: bun scripts/gate.ts, bun x tsc --noEmit, bun scripts/design-lint.ts, and the tests below all pass. bun scripts/fast.ts named 237 files, about 19 minutes, so I ran the files that cover this change instead: mcp-size, palette, palette-entries, palette-roster, tui-neworg, tui-system, tui-asked, tui-sshkeys and tui-passkeys.
To try it: ssh in with the command in FORGE_APP_SSH, press ctrl-k, type Passkeys, then press enter.
🤖 Generated with Claude Code
HIGH: the head does not implement this issue. The title and description say a read-only terminal Passkeys screen (src/tui/screens/passkeys.ts, a palette command, test/tui-passkeys.test.ts). The diff at this head is a different feature, #7651 "forge talk": a conversation_run migration, src/crew/conversation.ts, a new POST /api/v1/conversation/messages route, an MCP say change, ssh talk, and changes to the spend queries. None of the passkeys files are in it. Fix first: rebase so the pull holds only the passkeys screen, its palette entry, test/tui-passkeys.test.ts and the palette-roster update, and move the talk work to its own pull. Two points would also block the talk work if it were reviewed here. (1) It is far too large for one pull and adds a migration. (2) say() in the MCP tool is ungated on a hosted/preview deploy beyond the rate limit; I did not find a test that a guest or an agent token is refused by the terminal door.
The terminal now has a read-only Passkeys screen. It lists the passkeys that sign in as you, with the same rows as Settings › Passkeys and MCP whoami_can kind: passkeys.
src/tui/screens/passkeys.ts(new): built likesshkeys.ts. Each passkey is aListStaterow: its name is the title andadded YYYY-MM-DD, used YYYY-MM-DD|neveris the meta. Rows are read withlistPasskeys(f.app.db, f.user.id), so only your own passkeys can appear. With none, the head line reads "None yet. Add one on the web: Settings › Passkeys." The only keys arej/k.src/tui/forge.ts: apasskeyspalette command sits right afterssh-keys, with the hint "the passkeys that sign in as you". Only signed-in people get it, not agents.test/tui-passkeys.test.ts(new):
- alice's two passkeys both show, one used today and one "used never", and bob's passkey never appears.
- carol, who has no passkeys, sees the "None yet" line.
- The palette offers passkeys to a person, but not to an agent or a signed-out guest.
test/palette-roster.test.ts:passkeysis added to the site-admin and member person lists; the agent list stays without it.
About the requested changes: the review describes a diff that is not on this branch. Before this push the head was 829b28b4. Against its merge base it changed only the four files above. No commit for #7651 ("forge talk") is on this branch or anywhere else in the clone: no conversation_run migration, no src/crew/conversation.ts, no /api/v1/conversation/messages. Its points about the talk work's size and the ungated say belong to whichever pull holds that work. This push merges current main (9796e35d) so the diff is recomputed against a fresh base; it still holds only the four passkeys files.
Checks run on this head: bun scripts/gate.ts and bun x tsc --noEmit pass, and bun test test/tui-passkeys.test.ts test/palette-roster.test.ts passes 8 of 8. This change doesn't touch src/web/, so I didn't run design-lint.
To try it, connect with FORGE_APP_SSH and open the palette. Type passkeys to see your own passkeys, or the "None yet" line if you have none.
🤖 Generated with Claude Code
The screen itself is right: it reads only the signed-in person's own passkeys via listPasskeys, is offered to signed-in people and not to agents or guests, and the tests would fail without it. One change to make in this round.
Fix first: document the new door. docs/TOUR.md:198 describes the terminal's SSH keys, and nothing says the palette now has Passkeys (ctrl+k, read only, name, added and last used, and 'None yet' pointing to Settings › Passkeys). Add that to the TOUR, beside the SSH keys paragraph, and to docs/MCP.md or docs/CREW.md if either lists the terminal commands. Both-doors requires that the docs say how to use it.
Two smaller notes, not blocking: the palette test passes {} as never as ctx, which only works because the commands are built lazily; and the screen has no ? hint saying it is read only, so a person who presses a or d gets silence.
The terminal now has a read-only Passkeys screen. It lists the passkeys that sign in as you, with the same rows as Settings › Passkeys and MCP whoami_can kind: passkeys.
src/tui/screens/passkeys.ts(new): built likesshkeys.ts. Each row shows the passkey's name, thenadded YYYY-MM-DD, used YYYY-MM-DD|never. Rows come fromlistPasskeys(f.app.db, f.user.id), so only your own passkeys appear. The head line reads "Passkeys that sign in as you. Read only: add or remove one on the web, Settings › Passkeys.", so pressingaordno longer leaves a person guessing. With no passkeys it reads "None yet. Add one on the web: Settings › Passkeys." The only keys arej/k.src/tui/forge.ts: apasskeyspalette command sits right afterssh-keys. Only signed-in people get it, not agents or guests.- Docs:
docs/TOUR.mdhas a new paragraph after the SSH keys one. It says how to open the screen (ctrl+k), that it is for people only and read only, what each row shows, what the head line says, and the "None yet" text.docs/CREW.mdadds the terminal's Passkeys command where it describeswhoami_can kind: passkeys.docs/MCP.mdlists MCP tools, not terminal commands, so it is unchanged. test/tui-passkeys.test.ts(new):
- alice sees both her passkeys (one used today, one never used) and the read-only head line; bob's passkey never appears.
- carol, who has none, sees the "None yet" line.
- The palette offers passkeys to a person, but not to an agent or a signed-out guest.
test/palette-roster.test.ts:passkeysis added to the site-admin and member person lists; the agent list stays without it.
The palette test still passes {} as never as the context. I kept it on purpose: test/palette-roster.test.ts lists the palette's entries the same way. The test only reads the command list and never runs a command, so it never needs a real context.
bun scripts/gate.ts and bun x tsc --noEmit pass, and bun test test/tui-passkeys.test.ts test/palette-roster.test.ts passes 8 of 8. Nothing under src/web/ changed, so design-lint does not apply.
To try it, connect with the command in FORGE_APP_SSH, press ctrl+k and choose Passkeys.
🤖 Generated with Claude Code
Earlier asks: docs (TOUR paragraph beside SSH keys, CREW mention) are met; the read-only head line that tells a person to add or remove on the web is met. The screen reads only the signed-in persons own passkeys via listPasskeys, is offered to signed-in people and not to agents or guests, makes no writes, and the tests (own vs another account, none yet, palette roster) would fail without it. Non-blocking: the palette test passes {} as never as ctx; fine while commands are built lazily.
The terminal now has a read-only Passkeys screen. It lists the passkeys that sign in as you, with the same rows as Settings › Passkeys and MCP
whoami_can kind: passkeys.src/tui/screens/passkeys.ts(new): follows the shape ofsshkeys.ts. Each passkey is aListStaterow: its name is the title andadded YYYY-MM-DD, used YYYY-MM-DD|neveris the meta. Rows are read withlistPasskeys(f.app.db, f.user.id), so only your own account's passkeys can appear. With none, the head line reads "None yet. Add one on the web: Settings › Passkeys." The only keys arej/k.src/tui/forge.ts: apasskeyspalette command sits right afterssh-keys, with the hint "the passkeys that sign in as you". Only signed-in people get it, not agents.test/tui-passkeys.test.ts(new):- alice's two passkeys both show, one marked as used today and one "used never", and bob's passkey never appears. - carol, with no passkeys, sees the "None yet" line. - The palette offers
passkeysto a person, but not to an agent or a signed-out guest.test/palette-roster.test.ts: this test lists every palette entry, so it failed when the new command appeared. I addedpasskeysto the site-admin person and member person lists; the agent list stays without it. The test was right to fail and has been updated for the new command; no code change was needed.What I left out on purpose:
Checks run:
bun scripts/gate.ts,bun x tsc --noEmit,bun scripts/design-lint.ts, and the tests below all pass.bun scripts/fast.tsnamed 237 files, about 19 minutes, so I ran the files that cover this change instead:mcp-size,palette,palette-entries,palette-roster,tui-neworg,tui-system,tui-asked,tui-sshkeysandtui-passkeys.To try it:
sshin with the command inFORGE_APP_SSH, pressctrl-k, typePasskeys, then pressenter.🤖 Generated with Claude Code
Closes #8044