Skip to content

docs(design): external-agent project invite (link + PIN)#1780

Open
jaylfc wants to merge 2 commits into
devfrom
docs/external-agent-invite
Open

docs(design): external-agent project invite (link + PIN)#1780
jaylfc wants to merge 2 commits into
devfrom
docs/external-agent-invite

Conversation

@jaylfc

@jaylfc jaylfc commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Design doc (plan only, no implementation) for inviting an external coding agent or CLI running on a different machine to work on a taOS project.

What it covers

  • Invite artifact: Members-panel button mints a short link (user.taos.my/482910 or controller-direct) plus a 4-digit PIN. Security model copied from the cluster pairing code: sha256-only PIN at rest, constant-time compare, 15-minute TTL, 5-attempt cap, single-use flip, per-IP rate limit, revocation.
  • Redemption semantics: three approaches weighed for whether the PIN is the approval. Recommended: pre-authorized consent, where the invite dialog is the consent moment (admin picks scopes at mint time) and redemption creates + auto-approves a real auth-request through the existing _do_approve path, keeping the registry/grants/audit/member-add/a2a-sync machinery intact. Manual-approve stays as a per-invite toggle.
  • Guaranteed membership: a successful redeem always makes the agent a native project member. The invite always grants project_tasks bound to its project (force-included, shown checked-and-disabled in the mint dialog), which drives the member-add + a2a channel sync in _do_approve (bec4186 on feat/consent-project-picker); a redeem that yields no member row is a hard failure, not best-effort.
  • Harness-declared identity: the connecting agent DECLARES its harness (kilo, grok, opencode, claude, aider) plus an optional label at redeem time. The handle is derived as {project_slug}-{harness}[-label] (e.g. myproject-grok, myproject-kilo-frontend) and used as display_name + handle on register. canonical_id keeps the existing {slug}-{YYYYMMDD}-{HHMMSS} collision handling; the handle (no timestamp) gets a short numeric suffix if an active same-handle agent already exists in the project. Members shows the agent under this handle.
  • Connection bundle: exact JSON schema with LAN, mesh, and taOSgo relay endpoints in probe order, the project_tasks kanban surface, the authenticated A2A bus proxy paths, the derived agent_handle, and the auth poll contract.
  • Delivery contract: realtime SSE via a new authenticated /api/a2a/bus/stream proxy (heartbeat, reconnect with since-resume, relay-safe), plus a timed-check fallback poll with a default 30-minute interval overridable at invite time (check_interval_secs) and a since-cursor convention for gapless at-least-once processing.
  • Transport fallback: LAN then mesh then relay, first /api/health 200 wins, re-probe from the top on failure.
  • Slice plan: six slices, foundation (mint+redeem, including harness-handle derivation and the membership invariant) first, taos.my resolver work last.
  • Open questions: approval default, PIN width, TTL, taos.my escrow, project-chat write scope, relay hostname source, delivery filtering default, missed-check-in surfacing.

Depends conceptually on the member-add-on-approve work on feat/consent-project-picker (bec4186); noted in the doc.

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@jaylfc, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 55889ff3-821f-47d8-b360-ba609fc5f8d6

📥 Commits

Reviewing files that changed from the base of the PR and between b8acce7 and b08075d.

📒 Files selected for processing (1)
  • docs/design/external-agent-project-invite.md
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/external-agent-invite

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

Comment @coderabbitai help to get the list of available commands.

@gitar-bot

gitar-bot Bot commented Jul 10, 2026

Copy link
Copy Markdown

Gitar is working

Gitar

@kilo-code-bot

kilo-code-bot Bot commented Jul 10, 2026

Copy link
Copy Markdown

Code Review Summary

Status: 6 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 4
Issue Details (click to expand)

WARNING

File Line Issue
docs/design/external-agent-project-invite.md 547 New: section asserts container tier is the "default for created agents" while open question #11 (661-665) still presents the low-RAM default as undecided — self-contradiction.
docs/design/external-agent-project-invite.md 220 Re-invite of identical harness+label mints a suffixed handle (new canonical_id), contradicting the "identity stable per (tool, project)" claim; stability only holds for token re-spawns.

SUGGESTION

File Line Issue
docs/design/external-agent-project-invite.md 548 New: "Apple Containerization on macOS" is macOS-only but created agents spawn on Linux Pi/cluster nodes; clarify host-dependent runtime mapping.
docs/design/external-agent-project-invite.md 187 Declared harness has no allowlist/length bound before it becomes display_name/handle/bus address.
docs/design/external-agent-project-invite.md 216 "label as first disambiguator" is misleading: label is already in the handle, so different labels never reach the numeric suffix.
docs/design/external-agent-project-invite.md 179 Membership "hard failure" doesn't specify transaction/rollback ordering, risking partial state (token minted, member-add fails).
Files Reviewed (1 file)

Fix these issues in Kilo Cloud

Previous Review Summaries (2 snapshots, latest commit 51c2439)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 51c2439)

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 3
Issue Details (click to expand)

WARNING

File Line Issue
docs/design/external-agent-project-invite.md 217 Re-invite of identical harness+label mints a suffixed handle (new canonical_id), contradicting the "identity stable per (tool, project)" claim; stability only holds for token re-spawns, not fresh re-invites.

SUGGESTION

File Line Issue
docs/design/external-agent-project-invite.md 184 Declared harness has no allowlist/length bound before it becomes display_name/handle/bus address.
docs/design/external-agent-project-invite.md 213 "label as first disambiguator" is misleading: label is already in the handle, so different labels never reach the numeric suffix.
docs/design/external-agent-project-invite.md 176 Membership "hard failure" doesn't specify transaction/rollback ordering, risking partial state (token minted, member-add fails).
Files Reviewed (1 file)
  • docs/design/external-agent-project-invite.md - 4 issues (incremental diff vs a7e2290; sections 2a identity/handle derivation and membership guarantee)

Fix these issues in Kilo Cloud

Previous review (commit a7e2290)

Status: No Issues Found | Recommendation: Merge

This PR adds a single design document (docs/design/external-agent-project-invite.md, plan only, no implementation). The review scope is the 529 added prose lines. Internal references are consistent: the 6-digit invite_id / 4-digit PIN examples, the entropy math (5 attempts / 10,000 = 0.05%), check_interval_secs default (1800s = 30 min) across schema/UX/delivery sections, the per-IP rate limit (20 per 10s), and the mint/redeem/revoke/self-bundle endpoint paths all line up. No security, runtime, logic, or migration issues to flag on the changed lines.

Files Reviewed (1 file)
  • docs/design/external-agent-project-invite.md

Reviewed by hy3-20260706:free · Input: 86K · Output: 5.6K · Cached: 155.1K

Plan for inviting a coding agent or CLI running on a different machine into a
taOS project: a Members-panel invite that mints a short link plus a 4-digit
PIN, redeeming into the existing consent/auth-request flow (pre-authorized
scopes chosen at mint time, same _do_approve path, full audit trail).

A successful redeem is guaranteed to make the agent a project member: the
invite always grants project_tasks bound to its project, which drives the
member-add + a2a sync in _do_approve (bec4186). The connecting agent declares
its harness (kilo, grok, opencode, claude, aider) plus an optional label, and
the handle is derived as {project_slug}-{harness}[-label] (e.g. myproject-grok,
myproject-kilo-frontend); canonical_id keeps the existing timestamp suffix and
handle collisions get a short numeric suffix.

The redeem returns a connection bundle carrying the controller's LAN, mesh, and
taOSgo relay endpoints with a health-probe fallback order, the project_tasks
kanban surface, the authenticated A2A bus proxy, and a delivery contract:
realtime SSE stream plus a timed-check fallback with an invite-time
check_interval_secs override and a since-cursor convention.

Security model follows the cluster pairing code: hashed single-use codes,
15-minute TTL, attempt caps, per-IP rate limiting, revocation. Includes
alternatives considered for the two contentious calls (PIN-as-approval vs
consent routing; taos.my short link vs controller-direct), a six-slice build
plan, and open questions.
@jaylfc jaylfc force-pushed the docs/external-agent-invite branch from a7e2290 to 51c2439 Compare July 10, 2026 22:34
fallback for same-harness-same-label re-invites.

Stability note: identity is stable per (project, harness, label). A re-spawn
that presents a still-valid stored token reuses its `canonical_id`; only a

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Re-invite of identical harness+label breaks the stated stability guarantee

The stability note says identity is "stable per (project, harness, label)" and reuses canonical_id. But section 2a's own collision rule (lines 208-214) states that re-inviting the same harness+label appends a numeric suffix (myproject-grok-2), which is a brand-new handle and therefore a brand-new canonical_id. A fresh redeem (new PIN) of the same tool+project thus does NOT reuse the prior identity — only a token re-spawn (no new redeem) does. This contradicts "stable per (tool, project)." Clarify that stability applies only to token re-spawns, and decide whether a re-invite of the same harness+label should reuse the existing handle/canonical_id instead of minting a suffixed duplicate.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

The connecting agent must DECLARE its harness at redeem time; taOS does not
guess it. The redeem request carries:

- `harness` (required): the coding tool, lowercased and slugified

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: Declared harness lacks an allowlist/length bound

harness is fully agent-declared and flows, unvalidated beyond "lowercased and slugified," into display_name, handle, and the bus address. A bogus or over-long value (e.g. a very long string, or a harness outside the intended set) becomes a visible member identity and bus endpoint. Specify an explicit allowlist (or validated pattern) and a max length for harness (and label, line 186) before they are persisted into the registry.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

checks the registry for an ACTIVE agent already holding the target handle in
this project; if found, it appends a short numeric suffix
(`myproject-grok-2`, then `-3`, ...) until free. The label, when the operator
supplied one, is the natural first disambiguator, so this suffix is the

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: "label as first disambiguator" wording is misleading

The label is already part of the handle ({project_slug}-{harness}[-label]), so two agents with the same harness but different labels already have distinct handles (myproject-grok vs myproject-grok-frontend) and never reach the numeric suffix. The suffix only triggers on identical harness+label. Reword so it is clear the numeric suffix disambiguates same-harness-same-label re-invites, and the label's role is to prevent collisions in the first place, not to disambiguate after one.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

bec4186b on `feat/consent-project-picker`), membership follows automatically.
The invite path does not re-implement membership; it guarantees the two
preconditions (`project_tasks` + bound `project_id`) that make `_do_approve`
do it, and treats a redeem that did not produce a member row as a failure to

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: Membership "hard failure" needs explicit transaction/rollback ordering

The design treats "a redeem that did not produce a member row" as a hard failure, but does not specify that the auth-request approval, token mint, and member-add occur in a single transaction, or that member-add is verified before the bundle/token is returned. If _do_approve approves and mints a token but the downstream member-add/a2a-sync fails, the agent could receive a valid token for a non-member identity (partial state). State explicitly that member-add success is a precondition for returning the bundle (or that the whole redeem rolls back on member-add failure).


Reply with @kilocode-bot fix it to have Kilo Code address this issue.


The proposal, layered and model-independent:

- **Container tier (strongest, default for created agents):** spawn the CLI

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Section fixes the container tier as the "default for created agents," but open question #11 (lines 661-665) still presents the low-RAM default as undecided.

The body asserts a settled default, while open question #11 asks "is the container tier ... or the worktree tier ... the right default?" A reader cannot tell whether the default is decided. Reconcile by softening the inline claim to "proposed default" or resolving the open question.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

The proposal, layered and model-independent:

- **Container tier (strongest, default for created agents):** spawn the CLI
inside an LXC/incus container (Apple Containerization on macOS) whose only

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: "Apple Containerization on macOS" is macOS-only, but created agents are described as spawning on "the Pi or a cluster node" (line 535), which are Linux hosts.

The parenthetical reads as if Apple Containerization is a flavor of LXC/incus; it is not, and it cannot run on a Linux Pi. Clarify the mapping (LXC/incus on Linux, Apple Containerization on macOS) so the runtime is explicitly host-dependent rather than implying one mechanism everywhere.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

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