Skip to content

AI agents in qrypt.chat: invite by email, SMS or link; E2EE chat (0.7.0, qc 0.6.0) - #295

Merged
ralyodio merged 1 commit into
masterfrom
feat/agents-in-qrypt
Oct 6, 2026
Merged

ralyodio merged 1 commit into
masterfrom
feat/agents-in-qrypt

Conversation

@ralyodio

@ralyodio ralyodio commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Anthony: "we need to be able to chat with our agents in qrypt.chat … a user should be able to invite an agent to qrypt.chat via email or phone or shared link".

Flow

  1. Settings → AI agents: name the agent, then either copy the link or send it by email (Resend) or text (Telnyx).
  2. The agent runs npx -y @profullstack/qryptchat agent join "<link>" [--name Athena] [--username athena_bot].
  3. qc makes the agent's ML-KEM-1024 keypair locally. POST /api/agents/redeem gets only the public key. The server creates an agent account (operator = the inviter), stores the key, opens a direct conversation with the inviter, and returns a session. qc seals it at rest like qc login.
  4. From then on the agent uses qc listen / qc send / qc mcp, end to end encrypted like any user.

Security

  • Invite tokens are 256-bit, single-use and expire after 7 days. Only their SHA-256 is stored.
  • The link carries the token in the fragment (/agents/join#…), so it never appears in a request line, server log or Referer.
  • Redemption claims the invite atomically before creating anything, and rolls back (deletes the auth user, frees the invite) if a later step fails.
  • An agent cannot invite agents. Open invites per user are capped at 25.
  • agent_invites is RLS-enabled and revoked from anon/authenticated: service role only.

Shown in the app

  • Chat shows an AI agent badge on agents' messages.
  • /u/<agent> says "AI agent", and its OpenProfile.md is Kind: agent with an Operator section linking the person's OpenProfile, as the spec asks.

DB: migration 20261007000000_agents.sql is already applied on dev2. It extends the account_type CHECK with agent, adds users.operator_user_id and the agent_invites table, and PostgREST has been reloaded.

Tests: 707/707. New tests cover tokens and link parsing, a successful redemption, refusing used/revoked/expired invites, bad keys and taken usernames, rollback, and the agent OpenProfile. next build passes.

Note: messaging is Preshy's area; Anthony asked for this directly.

🤖 Generated with Claude Code

….0, qc 0.6.0)

- Migration 20261007000000 (applied on dev2): account_type 'agent',
  users.operator_user_id, agent_invites (sha256 of a 256-bit token only).
- Settings > AI agents: invite by link, email (Resend) or SMS (Telnyx);
  list invites and agents; revoke open invites.
- /agents/join#<token>: human- and agent-readable instructions; the token
  lives in the fragment, never in a request line or Referer.
- POST /api/agents/redeem: the agent sends only its ML-KEM-1024 public key;
  the server creates the agent account (operator = inviter), stores the key,
  opens a direct conversation and returns a session. Claimed atomically and
  rolled back on failure.
- qc agent join <link> [--name --username]: makes the keypair locally, seals
  the session like qc login; then qc listen / send / mcp.
- Chat shows an AI agent badge; an agent's OpenProfile is Kind agent with an
  Operator section.

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

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown

ThreatCrush Security Scan

13 finding(s)

MEDIUM: 9 | LOW: 4

Severity Rule Location
MEDIUM js-unescaped-html-sink src/app/blog/[slug]/page.jsx:38
MEDIUM js-unescaped-html-sink src/app/blog/[slug]/page.jsx:66
MEDIUM js-unescaped-html-sink src/app/faq/page.jsx:57
MEDIUM js-unescaped-html-sink src/app/layout.jsx:137
MEDIUM js-unescaped-html-sink src/app/layout.jsx:141
MEDIUM js-unescaped-html-sink src/app/page.jsx:47
MEDIUM redos-nested-quantifier src/lib/auth/dns-name.js:88
MEDIUM js-unescaped-html-sink src/lib/components/chat/MessageItem.jsx:84
MEDIUM js-unescaped-html-sink src/lib/components/chat/MessageItem.jsx:129
LOW secret-generic-credential src/app/api/auth/register-anon/route.test.js:32
LOW secret-jwt tests/debug-sms.js:10
LOW secret-generic-credential tests/private-key-import-export.test.js:252
LOW secret-generic-credential tests/private-key-import-export.test.js:264

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio merged commit a7941de into master Oct 6, 2026
11 checks passed
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