Agent participants on every surface + pairux CLI - #113
Merged
Merged
Conversation
AI agents (Claude Code, moshcode, scripts) can now join a live PairUX
session as labelled participants that read and post in the chat.
- DB: session_participants.kind ('human'|'agent'), agent_owner_id,
agent_client; join_session_as_agent RPC (service role only, max 5 live
agents, settings.allowAgents, stale agents retired after 2 min).
- CLI sign-in: OAuth 2.1 auth code + PKCE S256 over a loopback redirect,
rotating refresh tokens with family revocation on reuse; hashes only.
/cli/authorize consent page, /api/v1/cli/{authorize,token,revoke,me}.
- Agent API: /api/v1/agents/join, GET/DELETE /api/v1/agents/:id (poll =
roster + chat + heartbeat, 410 when removed/ended), POST .../messages.
- Web + PWA: Agent badge in chat roster and host sidebar; agents get only
"Remove agent" (no DM, mute, control, make-host).
- Desktop: same in both roster components.
- Mobile: new AgentStrip on host + viewer screens, long-press remove.
- packages/cli: @profullstack/pairux with `pairux login|logout|whoami|
join|listen|say|who|status|leave`, --json for agents.
- Docs: /docs/agents, llms.txt, sitemap.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
| url.searchParams.set('error', 'access_denied'); | ||
| url.searchParams.set('state', state); | ||
| setDone('denied'); | ||
| window.location.href = url.toString(); |
| ).saveConfig( | ||
| { | ||
| tokens: { | ||
| accessToken: 'pux_at_x', |
| { | ||
| tokens: { | ||
| accessToken: 'pux_at_x', | ||
| refreshToken: 'pux_rt_x', |
| return { | ||
| status: 200, | ||
| body: { | ||
| access_token: 'pux_at_new', |
| status: 200, | ||
| body: { | ||
| access_token: 'pux_at_new', | ||
| refresh_token: 'pux_rt_new', |
| ).saveConfig( | ||
| { | ||
| tokens: { | ||
| accessToken: 'pux_at_old', |
| { | ||
| tokens: { | ||
| accessToken: 'pux_at_old', | ||
| refreshToken: 'pux_rt_old', |
| d.configPath | ||
| ); | ||
| expect(await run(['whoami'], d)).toBe(0); | ||
| expect((await readConfig()).tokens).toMatchObject({ refreshToken: 'pux_rt_2' }); |
| ).saveConfig( | ||
| { | ||
| tokens: { | ||
| accessToken: 'pux_at_x', |
| { | ||
| tokens: { | ||
| accessToken: 'pux_at_x', | ||
| refreshToken: 'pux_rt_x', |
ThreatCrush Security Scan47 finding(s) HIGH/CRITICAL: 4 | MEDIUM: 27 | LOW: 16
Snippets are redacted; ThreatCrush never prints matched credential material. |
… tolerates payloads without participants Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ct at the consent page's navigation Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
AI agents (Claude Code, moshcode, scripts) can join a live PairUX session as labelled participants that follow and post in the chat. Before this, "agentic" existed only as marketing copy (#101, #102); there was no agent in the roster and no CLI.
What's in it
session_participants.kind(human/agent),agent_owner_id,agent_client.join_session_as_agentRPC, service-role only: max 5 live agents,settings.allowAgents=falseopt-out, agents idle 2+ min retired.cli_auth_codes+cli_tokens(hashes only, RLS on, no policies)./api/v1/cli/{authorize,token,revoke,me}is OAuth 2.1 auth code + PKCE S256 over a loopback redirect, with rotating refresh tokens and family revocation on reuse./api/v1/agents/join,GET/DELETE /api/v1/agents/:id(poll = roster + chat + heartbeat; 410 when removed/ended),POST /api/v1/agents/:id/messages./cli/authorizeconsent page and/docs/agents.AgentStripon host and viewer screens (polls every 10s); hosts long-press to remove.packages/cli→@profullstack/pairux, binpairux:login / logout / whoami / join / listen [--json] / say / who / status / leave. No runtime dependencies, config file at 0600.Before merge
20260924120000_agent_participants.sqlto prod (yuwjbjskkghlyrdkhexu). No CI step applies migrations. Until it's applied, the agent routes return errors; existing UI is unaffected (kindis optional and absent means human). I checked prod read-only: none of the new columns or tables exist yet, andprofiles.display_name/usernameare there.@profullstack/pairuxto npm.v*tag.Known limits
pairux loginneeds the browser on the same machine as the CLI (loopback redirect). On remote boxes, join anonymously; a device-code flow would be the follow-up.Tests
liveAgents)Typecheck and lint are clean on web, desktop, mobile and cli, and prettier is clean on changed files. Full
next buildwas not run: the dev box root disk is at 100%.🤖 Generated with Claude Code