Repository navigation
feat(app): invite teammates with one link that fills in Join your team - #561
Merged
Merged
Conversation
The Invite screen and Settings → Team → Invite… copy an ace://join link carrying the directory URL and team secret. Pasting it into either join form fills both fields, and the desktop app registers its channel's scheme so opening the link brings up Join your team, filled in, for the person to check and join. Why: apps/desktop/electrobun.config.ts | each build channel registers its own scheme (ace, ace-canary, ace-dev) so a dev or Canary build never answers stable's invite links; apps/app/src/invite.ts reads all of them. Why: apps/app/src/invite.ts#function parse | an invite link only fills the join form; joining must stay an explicit Check and join, since a link can name any directory.
Chat apps linkify https, not ace://. The link opens ace.githubnext.com/join, which offers the download and hands off to ace://join. Pasting either form still fills Join your team. Why: apps/app/src/invite.ts#function link | the invite must stay in the URL fragment so the secret never reaches the site's server
) * feat(app): ask a teammate's host to join the team over the tailnet A host that isn't in a team finds peers whose hello names a team directory and offers "<person> on <machine> is in a team. Ask to join". The peer's owner approves or denies in their app; on approval the directory URL and secret travel over the tailnet and the asking host joins as with directory-set. Asks end on deny, disconnect, a repeat ask, or after five minutes. Why: apps/host/src/protocol.ts#type Hello | hello answers any tailnet peer, so team carries only the directory's host, never the secret Why: apps/host/src/gateway.ts#function asksChanged | only the local app can answer an ask (team-answer is a keychain op), so asks reach local sockets only * lane: confirm notes for ask to join * lane: sync ask-to-join memory
iamnbutler
added a commit
that referenced
this pull request
Oct 22, 2026
… from the app (#553) * feat(app): offer Get your team started or Join your team on first run * chore: confirm the app selection note * fix(app): turn off autocorrect in the team setup fields * feat(app): deploy the team's Cloudflare services from Get your team started Ace Helper ships prebuilt directory and channel bundles and deploys them with the owner's wrangler login, naming them after the tailnet, then joins the directory. The Set up step shows progress instead of a command to copy. Fly.io still runs the checkout script. Why: apps/host/src/team.ts | Ace Helper runs wrangler as plain Bun via BUN_BE_BUN, and deploys the bundles apps/desktop/scripts/helper.ts writes to Resources/services; both layouts must stay in step. * chore: confirm gateway and helper notes after adding team-deploy * lane: sync team-onboarding memory * feat(app): link Deploy to what it creates in the team's Cloudflare account * feat(app): invite teammates with one link that fills in Join your team (#561) * feat(app): invite teammates with one link that fills in Join your team The Invite screen and Settings → Team → Invite… copy an ace://join link carrying the directory URL and team secret. Pasting it into either join form fills both fields, and the desktop app registers its channel's scheme so opening the link brings up Join your team, filled in, for the person to check and join. Why: apps/desktop/electrobun.config.ts | each build channel registers its own scheme (ace, ace-canary, ace-dev) so a dev or Canary build never answers stable's invite links; apps/app/src/invite.ts reads all of them. Why: apps/app/src/invite.ts#function parse | an invite link only fills the join form; joining must stay an explicit Check and join, since a link can name any directory. * lane: confirm notes for invite link * lane: sync invite-link memory * feat(app): send invites as an https link to the join page Chat apps linkify https, not ace://. The link opens ace.githubnext.com/join, which offers the download and hands off to ace://join. Pasting either form still fills Join your team. Why: apps/app/src/invite.ts#function link | the invite must stay in the URL fragment so the secret never reaches the site's server * lane: confirm invite parse note * lane: sync invite-link memory * feat(app): ask a teammate's host to join the team over the tailnet (#563) * feat(app): ask a teammate's host to join the team over the tailnet A host that isn't in a team finds peers whose hello names a team directory and offers "<person> on <machine> is in a team. Ask to join". The peer's owner approves or denies in their app; on approval the directory URL and secret travel over the tailnet and the asking host joins as with directory-set. Asks end on deny, disconnect, a repeat ask, or after five minutes. Why: apps/host/src/protocol.ts#type Hello | hello answers any tailnet peer, so team carries only the directory's host, never the secret Why: apps/host/src/gateway.ts#function asksChanged | only the local app can answer an ask (team-answer is a keychain op), so asks reach local sockets only * lane: confirm notes for ask to join * lane: sync ask-to-join memory * lane: confirm gateway note after merging main
This was referenced Oct 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Teammates join with one invite link, not by copying a directory URL and a secret separately. Part of #538 (g2 in the onboarding review) and #550.
https://ace.githubnext.com/join#directory=…&secret=…. Chat apps linkify it, unlikeace://. The page (githubnext/ace-site) offers the download, then hands off toace://join?…. The invite stays in the fragment, so the server never sees it. A toggle shows the URL and secret separately. A new local-owner-onlyteam-invitehost op reads them from the directory config and Keychain.ace,ace-canary,ace-dev) and opens Join your team with both fields filled in.Smoke-tested:
wrangler devdirectory: theace:joinevent prefilled the form, joining succeeded, paste-to-fill worked, and Invite… copied the link.open "ace-dev://join?…"opened Join your team with the URL and secret filled in.Replacing the shared secret with tailnet identity is proposed separately.
Built in Ace
No. Claude Code wrote this while the user was away, outside Ace, and drove the desktop build with Desktop Tools to check the deep link. Ace can't yet run an unattended multi-hour polish pass across several lanes. Tracked under #5.