Make pairing one sheet that says what it allows before it happens

Open
#21 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Active
Tech stack
react, typescript

Research direction

Start with the listed pairing dialogs, especially InviteSourceDialog.tsx and AddConnectionDialog.tsx, then trace the connection calls and existing tests. The issue depends on #17, #16, #19 and #20, and leaves open decisions about SSH permissions and whether thread messages can start a model run; check those before implementation. Done means both pairing directions use one sheet with the stated consent, status, failure and entry-point behavior, and the listed tests and desktop and touch-context screenshots pass.

Written by the indexing model from the issue text.

Description

enhancement

What feature would you like to see?

Pairing happens in two unrelated dialogs (a side panel to open another space, a centred dialog to show a pairing code), and both do things the person did not choose. Pressing "Pairing code" immediately and permanently switches on "Allow other Kikis to connect" and starts listening on the local network and Tailscale, which the dialog does not mention. Pairing also asks for and grants thread messages every time, and the GUI cannot leave them out.

Decided
  • One pairing sheet with two directions: "open another space" and "let another space or device open this one". It opens from three places.
  • Before a pairing code is generated, the sheet says what the other side will be allowed to do and what generating the code switches on; the person presses a button that names the consequence. The server keeps switching the gate on when a code is generated; the GUI just stops doing it silently.
  • Thread messages are opt-in on both sides of a pairing, unchecked by default.
  • A successful pairing does not switch into the new space; it offers a "Switch" button.
  • Pairing codes stay the one regular way to pair; invitations and identity strings live under Advanced (moved by the settings-merge issue).
Design

Entry points (all open the same sheet: a right-side panel on desktop, a full-height sheet on phones):

  • Switch panel: "Pair a space on another computer…" → opens directly in "open another space".
  • Settings → Spaces, section "Spaces on other computers": "Pair…" → "open another space".
  • Settings → Access → Other spaces: "Pairing code" → "let another space or device open this one".

Open another space.

Pair a space on another computer
On the other computer, open Settings → Access → Other spaces → Pairing code.

Way        [Pairing code] [SSH]       (SSH only in the desktop app with saved SSH hosts)
Address    http://192.168.1.20:58627
           https:// anywhere. http:// is enough on this machine, the local network, or a Tailscale address.
Code       XXXX-XXXX
Name       (optional; empty uses the other computer's name)
☐ Also ask for thread messages      Let this space's agents message that space's threads and wait for replies.
☑ Show its working and waiting counts in the switch panel      Reads two numbers only, never its threads.
                                                         [Cancel] [Pair]

zh copy fixed by the design: title "配对另一台电脑上的空间"; lead "在对方的电脑上打开:设置 → 接入 → 其他空间 → 配对码。"; "方式 [配对码][SSH]"; "名称 (可选,留空用对方电脑的名字)"; "☐ 同时请求线程消息 — 让这个空间的智能体给对方的线程发消息并等待回复。"; "☑ 在切换面板里显示它的进行中与待处理数量 — 只取两个数字,不加载对方的任何线程。"; buttons "取消" "配对". The address hint is the existing st.remote.endpointHint.

  • The request is connections.pair({ endpoint, code, label?, backgroundSummary, requestBridge }) with requestBridge from the first checkbox (the field added by the requestBridge issue).
  • The SSH way reuses today's AddConnectionBySshDialog flow inside the sheet. The SSH connect path always asks for thread messages today (packages/kap-server/src/services/connections/manager.ts:125) and has no field to decline, so the thread-message checkbox is shown only for the pairing-code way; a checkbox that cannot take effect is not shown.
  • States: filling (today's inline address rules); "正在配对… / Pairing…"; success: the sheet closes, the new row appears, and a toast "已配对 {名称}。[切换]" (en: "Paired {name}. [Switch]"); the window stays in its current space.
  • Failure lines (zh fixed by the design; en follows): invalid or expired code "配对码不对,或已经过期。"; address unreachable "连不上这个地址。"; the other side's gate is off (inbound_disabled) "对方没有打开“允许其他空间连接”。"; the address is this very space (identity_changed from claiming one's own code) "这个地址就是当前这个空间。". Keep the existing rate-limit line (st.remote.fail.pairingRate).
  • In the phone app the launcher already offers "Scan QR code" first and manual entry second; nothing changes there.

Let another space or device open this one. A first screen comes before any request:

Pairing code
After pairing with this code, the other side can:
☑ Open this space (browse and chat)
☐ Message this space's threads, and start a model run here

Generating a code turns on “Allow other spaces to connect” and lets this computer
accept pairing on the local network and Tailscale until you turn that switch off.
                                        [Cancel] [Turn on and generate code]

zh copy fixed by the design: "配对码" / "对方用配对码配对后可以:" / "☑ 打开这个空间(浏览与对话)" / "☐ 给这个空间的线程发消息,并在这里发起一轮模型运行" / "生成配对码会打开“允许其他空间连接”,并让这台电脑在局域网和 Tailscale 上接受配对,直到你关掉这个开关。" / "[取消][打开并生成配对码]".

  • "Open this space" is shown checked and cannot be unchecked: every pairing grants it.
  • The thread-message box maps to createPairCode({ allowBridge }); unchecked sends allowBridge: false. When checked, the operations sent in bridgeOperations must be exactly the ones the copy promises (see the open question below).
  • When the gate is already on, the paragraph about turning it on is not shown and the button reads "生成配对码 / Generate code".
  • No request is sent until that button is pressed. Today InviteSourceDialog calls createPairCode({}) as soon as it mounts.
  • After generating: today's content (code, QR, countdown, "对方可以使用的地址 / Addresses the other side can use", "换一个码 / New code", "完成 / Done"); with no direct address, today's st.inbound.codeNoAddress line. When the other side uses the code, the sheet shows "{名称} 已配对。" (en: "{name} is paired.") and the new row appears in the list; when it expires, "这个配对码已过期。[换一个码]" (en: "This code has expired. [New code]"). When the runtime cannot accept pairing (authentication bypassed), the button is disabled with today's reason.

Incoming list facts. On Settings → Access → Other spaces, each allowed row gains the same facts as the outgoing rows: whether it can open this space, and the thread-message direction ("线程消息:双向 / 仅发出 / 仅接收 / 无 / 读不到"), from lib/threadBridges.ts; its menu gains "线程消息… / Thread messages…" (the ThreadMessagesPanel from the thread-message issue) next to "撤销… / Revoke…". Remove st.inbound.bridgeNote once the facts are shown.

Removal and revocation copy (replace today's text; zh fixed by the design):

  • Remove a pairing: "移除后,这个空间不能再打开 {名称},保存的凭据会被删除。不会关掉对方,也不改对方的设置。"
  • Revoke an incoming pairing: "{名称} 正在进行的连接会中断,以后也不能再打开这里。不影响其他配对。"

Switch panel. Point its "Pair a space on another computer…" entry at this sheet (in the switch-panel issue it opens Settings → Spaces).

Strings: add keys to both packages/session-core/src/i18n/en.ts and zh.ts; en copy follows the zh meaning where the design gives only zh.

Where
  • apps/kiki-gui/src/components/settings/remote/InviteSourceDialog.tsx:42-60 (generates the code on mount with createPairCode({})), :75-132 (code, QR, addresses, regenerate, done).
  • apps/kiki-gui/src/components/settings/remote/AddConnectionDialog.tsx:69-90 (connections.pair call), :52-58 (way state), and AddConnectionBySshDialog.tsx.
  • apps/kiki-gui/src/components/settings/InboundConnectionsSection.tsx:150-158 (the "Pairing code" button), :189-199 (grant rows).
  • Server side that stays as is: packages/kap-server/src/services/connections/admission.ts:179-196 (createPairCode switches the gate on), packages/kap-server/src/start.ts:1421 (the gate starts the peer listeners), packages/protocol/src/rest/connections.ts:94-100 (pairCodeCreateInputSchema, allowBridge default true).
  • Today's copy that this replaces: st.inbound.inviteBody ("Browsing and thread messages come up together."), st.remote.addBody, st.inbound.bridgeNote, st.remote.removeBody, st.inbound.revokeBody in packages/session-core/src/i18n/en.ts and zh.ts.
Done when
  • With the gate off, opening "Pairing code" sends no request until "Turn on and generate code" is pressed (test).
  • Generating a code without ticking thread messages sends allowBridge: false, and after the other side pairs, this space's thread-bridge list has no new entry (test against the fixture, or integration).
  • Pairing to open another space without ticking thread messages sends requestBridge: false (test in remoteConnections.test.ts or the sheet's test).
  • After a successful pairing the window is still in its original space and the toast offers "Switch" (test).
  • Each failure reason in the table shows its line (test).
  • All three entry points open the same sheet in the right direction (test).
  • Screenshots at desktop and phone width, light and dark, en and zh, with node apps/kiki-gui/scripts/visual-proof.mjs: both directions' first screens, the gate-already-on variant, a generated code, a success toast, and the Access page rows with their thread-message facts. UI work is accepted only with these screenshots.
  • Phone-width screenshots are taken in a touch context (isMobile: true, hasTouch: true, as apps/kiki-gui/scripts/visual-proof-mobile-reading.mjs:294-300 does). Phone mode is (pointer: coarse) and (max-width: 639px) (apps/kiki-gui/src/lib/layoutHooks.ts:57), so a width-only --viewport narrow run of visual-proof.mjs shows the desktop layout squeezed, not the phone layout.

Additional information

Order: after the requestBridge protocol issue (the GUI sends the new field), the settings-merge issue (entry points and the Access page layout), the switch-panel issue (its entry is repointed here) and the thread-message issue (lib/threadBridges.ts and ThreadMessagesPanel.tsx). This issue owns InboundConnectionsSection.tsx after the settings merge.

Changing the default makes "pair, and agents can already message each other" stop being true for GUI pairings; the CLI (kiki pair) keeps today's default. The documentation issue of this series updates the feature docs and CLI notes.

Owner question: the design's checkbox says the other side can "start a model run here", but the pairing default grants read, send and wait without wake (admission.ts:7), and without wake a bridged message stays pending instead of starting a turn (packages/kap-server/src/services/threadBridge/bridge.ts:309); decide whether ticking the box grants wake or the clause is dropped from the copy.

Owner question: whether the SSH way should also be able to decline thread messages (it would need requestBridge on the SSH connect input, which today hard-codes true).

Order and scope. Paths and line numbers refer to the code after the pending GUI interaction and mobile pull request is merged into kiki.
Depends on: #17, #16, #19, #20.
Main files: apps/kiki-gui/src/components/settings/remote/PairSheet.tsx (new), apps/kiki-gui/src/components/settings/remote/AddConnectionDialog.tsx, apps/kiki-gui/src/components/settings/remote/AddConnectionBySshDialog.tsx, apps/kiki-gui/src/components/settings/remote/InviteSourceDialog.tsx, apps/kiki-gui/src/components/settings/InboundConnectionsSection.tsx, apps/kiki-gui/src/components/SpaceSwitchSheet.tsx, apps/kiki-gui/src/lib/remoteConnections.ts, apps/kiki-gui/src/lib/remoteConnections.test.ts, apps/kiki-gui/src/components/settings/remote/AddConnectionDialog.sshWay.test.tsx, apps/kiki-gui/src/components/settings/remote/AddConnectionBySshDialog.test.tsx, packages/session-core/src/i18n/en.ts, packages/session-core/src/i18n/zh.ts.

Dominant language
TypeScript
Stars
54
Forks
5
Avg merge
2h 54m
Merged PRs (30d)
2

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from X-T-E-R/kiki

All issues in X-T-E-R/kiki

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.