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

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

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

opened this

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 of sshkeys.ts. Each passkey is a ListState row: its name is the title and added YYYY-MM-DD, used YYYY-MM-DD|never is the meta. Rows are read with listPasskeys(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 are j/k.
  • src/tui/forge.ts: a passkeys palette command sits right after ssh-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 added passkeys to 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

Closes #8044

commented

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 of sshkeys.ts. Each passkey is a ListState row: its name is the title and added YYYY-MM-DD, used YYYY-MM-DD|never is the meta. Rows are read with listPasskeys(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 are j/k.
  • src/tui/forge.ts: a passkeys palette command sits right after ssh-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 added passkeys to 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

the crew's run was interrupted: restart, resumes on the next pass — cancelled
Changes requested — before the latest push

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.

commented

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 like sshkeys.ts. Each passkey is a ListState row: its name is the title and added YYYY-MM-DD, used YYYY-MM-DD|never is the meta. Rows are read with listPasskeys(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 are j/k.
  • src/tui/forge.ts: a passkeys palette command sits right after ssh-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: passkeys is 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

Changes requested — before the latest push

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.

commented

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 like sshkeys.ts. Each row shows the passkey's name, then added YYYY-MM-DD, used YYYY-MM-DD|never. Rows come from listPasskeys(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 pressing a or d no longer leaves a person guessing. With no passkeys it reads "None yet. Add one on the web: Settings › Passkeys." The only keys are j/k.
  • src/tui/forge.ts: a passkeys palette command sits right after ssh-keys. Only signed-in people get it, not agents or guests.
  • Docs: docs/TOUR.md has 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.md adds the terminal's Passkeys command where it describes whoami_can kind: passkeys. docs/MCP.md lists 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: passkeys is 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

Approved

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.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs