Skip to content

Team mode M8: mobile invitation, sign-in and self-pairing - #4165

Draft
DoodleBears wants to merge 9 commits into
mainfrom
claude/4146-mobile-sign-in
Draft

DoodleBears wants to merge 9 commits into
mainfrom
claude/4146-mobile-sign-in

Conversation

@DoodleBears

@DoodleBears DoodleBears commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Issue #4146 | Hub #4138 | ADR-0336 | Contract

Why the change

A Team mode member can now join a Host from the iOS or Android app with an invitation link and their one-time password, and pair their other phones without a password, while their phone traffic runs as that member, never as the Owner.

Special things to note

  • Do not merge before native QA. Screens are typechecked and unit-tested only; iOS Simulator, physical iPhone and Android results are queued in the shared device queue and will be added here. Expo Web preview is not used because the flows depend on the native Noise carrier.
  • Security-sensitive: member device credentials (member.<token>, hashed) are dispatched by the Device Gateway through the member's DSH Peer and remote-access policy; Owner-paired devices keep their path; the Owner cookie is never used for member traffic. Invitations carry no secret; the phone pins the Host fingerprint before sending a password, and the Host refuses a mismatched fingerprint.
  • Named migration member-devices appended after migration-ledger (append-only ledger, feat(database): named schema migrations with an append-only ledger #4230).
  • Synced with main on 2026-11-16 (a0dd514d1): invitations now need members.manage within the target-role ceiling; the implicit Owner is refused member self-pairing; phone grants are listed and revoked through the Team service; the pinned Host key refusal (host-key-mismatch) again takes precedence over the M8 fingerprint check (the CI failure). Affected suites 9,176 passed / 26 skipped / 0 failed; typecheck, lint, format, docs and smoke pass.
  • Also blocked on Team mode: follow-ups from the #4109 remote Host review #4201 H1/H2 (shared host-client package and desktop member sign-in) landing first.

Change outline

HTTP    POST /botharness-device/team/device-sign-in {username,password,deviceName,fingerprint}
        POST /botharness-device/team/device-password (Device member.<token>) {current,next}
Bridge  memberInvitation {humanId} · memberPairingOffer {}
CLI     members invite <username> · members pairing-offer
Link    deepseekbot://team?i=<base64url {v,host{id,name,fingerprint},routes,username,expiresAt}>
 packages/core/src/team/   device-http.ts, devices.ts (+), service/http/mount: device grants, gate, self-pairing
 packages/core/src/devices/   gateway, encrypted-gateway, pairing: member credential → member Peer
 apps/mobile/src/host/   team-invitation.ts, team-client.ts, member-identity.ts (+); host-session pairMember
 apps/mobile/app/
+  pair/team.tsx          invitation link → password → forced change → identity-switch confirm
+  member-pairing.tsx     one-time QR to pair another of the member's phones
   pair/index.tsx         "Join with an invitation"
   host-connection.tsx    "Signed in as …" + "Pair another device"
   +native-intent.tsx     deepseekbot://team?i=… → /pair/team

Verification

  • Host and modules (Codex): 260/260 focused regressions (every sign-in refusal incl. fingerprint mismatch, password gate, member Peer unary/stream dispatch with DSH-native refusal, self-pairing single use/expiry, invitation parsing, identity replacement); real isolated Host CLI/Noise sign-in and password change.
  • Client: pnpm lint (CLI parity), mobile typecheck and tests pass.
  • Native: pending in the shared device queue (iOS Simulator, physical iPhone, Android).

Agent tasks: claude/local/74a5ee4a-f6fe-4aab-870f-5e465b0b8474 (contract, screens, review); codex/local/01a1d77c-e36b-75a0-af02-f39c78f7232d (Host logic, mobile modules, CLI, tests).

Closes #4146

🤖 Generated with Claude Code

DoodleBears and others added 3 commits November 14, 2026 10:23
Add member-scoped device grants, password gating and Peer-based HTTP/mux
dispatch, with single-use self-pairing and fingerprint-pinned mobile APIs.
Persist one confirmed identity per Host and isolate cached member content.

Issue: #4146
Agent-Task: codex/local/01a1d77c-e36b-75a0-af02-f39c78f7232d
Issue: #4146
Agent-Task: claude/local/74a5ee4a-f6fe-4aab-870f-5e465b0b8474
Agent-Task: codex/local/01a1d77c-e36b-75a0-af02-f39c78f7232d

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…own phones

Invitation entry (deep link, pair chooser and pasted link), password sign-in
with the forced change on the phone, identity switch confirmation, the
signed-in account on the Host connection sheet, and a one-time QR to pair
another of the member's phones.

Issue: #4146
Agent-Task: claude/local/74a5ee4a-f6fe-4aab-870f-5e465b0b8474

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Nov 14, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

DoodleBears and others added 6 commits November 16, 2026 04:48
Preserve current role permissions, lifecycle and Host relationships; append member-devices after the named migration ledger. Keep member pairing distinct from Owner-bound offers.

Issue: #4146
Co-Authored-By: Codex <noreply@openai.com>
Check the existing encryption pin before the M8 member fingerprint and identity-switch guards. A changed or removed pinned key retains host-key-mismatch; member fingerprint validation remains enforced.

Issue: #4146

Co-Authored-By: Codex <noreply@openai.com>
List member phone grants with their name and device kind, revoke them through the Team grant owner, and apply the current member-management target ceiling to invitations. Cover ledger-backed upgrades and preserve separate Owner and member pairing authority.

Issue: #4146

Co-Authored-By: Codex <noreply@openai.com>
The Gateway unwraps bridge results before returning them. Validate the invitation payload and its target member through that public contract.

Issue: #4146
Co-Authored-By: Codex <noreply@openai.com>
Keep the rollback fixture before migration-ledger so it still exercises legacy backfill after new migrations are appended. Keep the member-device upgrade fixture before member-devices. Preserve the missing-ledger refusal and rollback assertions.

Issue: #4146
Co-Authored-By: Codex <noreply@openai.com>
Main now resolves the implicit Owner as an active Human. Refuse the member-only pairing offer for that identity, preserving the existing Owner pairing path and M8 refusal assertion. Select the M13 upgrade fixture by its named migration instead of applying the final ledger entry.

Issue: #4146
Co-Authored-By: Codex <noreply@openai.com>

This branch has not been deployed

No deployments
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.

Team mode M8: Mobile invitation, sign-in and self-pairing

1 participant