Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 33 additions & 12 deletions specs/auth/agents-and-auth.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Agents & Authentication

Status: **draft** (2026-07-18) — the contract for real per-Agent identity, login, and user
management, replacing the single shared operator password that HT-51 shipped as a
deliberate placeholder. Authored native (Helpthread's own domain model); the *experience*
is modelled on the Help Scout / FreeScout user-management UX (black-box observation only —
never their source), rendered entirely in Helpthread's own design system.
Status: **draft** (2026-07-18, amended 2026-07-19 — see Changelog draft.6) — the contract for
real per-Agent identity, login, and user management, replacing the single shared operator
password that HT-51 shipped as a deliberate placeholder. Authored native (Helpthread's own
domain model); the *experience* is modelled on the Help Scout / FreeScout user-management UX
(black-box observation only — never their source), rendered entirely in Helpthread's own
design system.
Comment on lines +3 to +8

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use “Agent management” terminology consistently.

“User management” and “user-management UX” are ambiguous here because this document describes human support staff. Rename these references to “Agent management” / “Agent-management UX” to preserve the repository’s vocabulary contract.

As per coding guidelines, human support staff must be referred to as “Agents” and AI actors as “Assistants”.

Proposed wording
- real per-Agent identity, login, and user management, replacing the single shared operator
+ real per-Agent identity, login, and Agent management, replacing the single shared operator
...
- (black-box observation only — never their source), rendered entirely in Helpthread's own
+ (black-box observation only — never their source), rendered entirely in Helpthread's own

Also replace “user-management UX” with “Agent-management UX” on Line 6.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@specs/auth/agents-and-auth.md` around lines 3 - 8, Update the introductory
contract description to consistently use “Agent management” for human
support-staff administration and “Agent-management UX” for the modeled
experience. Replace the existing “user management” and “user-management UX”
references, while preserving the distinction between Agents and Assistants.

Source: Coding guidelines


This supersedes the single-operator posture of `agent-inbox-v1.md` §1/§5/§6, whose own note
mandates the direction: *"when multi-Agent lands it is expected to **replace** this single
Expand All @@ -19,7 +20,11 @@ splitting them at a seam:
with no dependency on any hosted identity service or third-party provider. That is
**username/password** — a real, self-contained auth system.
- **Resonant IQ's own deployment, and paying customers:** want Google SSO, magic-link,
passkeys, SAML. These are **licensed marketplace modules**, not part of the free core.
SAML/enterprise SSO. These are **licensed marketplace modules**, not part of the free
core. **Passkey login (WebAuthn) is the one exception — it is core, not a marketplace
module:** security hygiene is always free (module catalog §1, HT-66, 2026-07-18); when
built, it ships as a second **core** auth provider on this same seam (catalog §2.2),
never through the marketplace path below. It is not yet built in this increment (§11).

The mechanism that makes both true at once is an **auth-provider seam** (§4). The core ships
the seam and exactly one provider — `password`. A marketplace module is a package that
Expand Down Expand Up @@ -88,7 +93,8 @@ This is the table that makes the marketplace work. **One Agent, many login metho
CREATE TABLE agent_auth_identities (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
agent_id uuid NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
provider text NOT NULL, -- 'password' (core); 'google','passkey',... (marketplace)
provider text NOT NULL, -- 'password' (core, v1); 'google','saml',... (marketplace);
-- 'passkey' is core too but not yet built (§1, §11)
subject text NOT NULL, -- provider's stable identifier for this Agent
secret_hash text, -- scrypt hash for 'password'; NULL for OAuth-style providers
created_at timestamptz NOT NULL DEFAULT now(),
Expand All @@ -112,11 +118,13 @@ CREATE UNIQUE INDEX agent_auth_identities_one_password_per_agent
guarding a freed old email against later collision — deferred rather than half-built. An
Agent record is re-created if the email must change.
- A marketplace `google` module inserts `provider='google', subject=<google sub>,
secret_hash=NULL` — **no core migration**. A `passkey` module inserts its own rows. The
secret_hash=NULL` — **no core migration**. A `saml` module inserts its own rows. The
seam (§4) is the only code that reads this table by provider.
- Deleting an Agent cascades their identities. An Agent may have several rows (password +
google + passkey) — all resolving to the same `agents.id`. Linking additional methods to an
existing Agent is a marketplace-module concern; core only ever writes `password`.
google + saml) — all resolving to the same `agents.id`. Linking a *marketplace* method to
an existing Agent is a marketplace-module concern; in this increment core only ever writes
`password` (passkey is core too, per §1, but is not yet built — it lands as a second
core-written provider, not a marketplace one).

### 3.3 `assignee` graduates from a flag to an identity — **breaking**

Expand Down Expand Up @@ -497,8 +505,12 @@ is retired (§8).

## 11. What this is NOT (scope)

- **No marketplace providers** (Google SSO, magic-link, passkey, SAML) — only the seam + the
free `password` provider. Premium modules wait on the HT-5 §7 exception text.
- **No marketplace providers** (Google SSO, magic-link, SAML/enterprise SSO) — only the seam
+ the free `password` provider. Premium modules wait on the HT-5 §7 exception text.
- **No passkey provider either** — passkey (WebAuthn) is core, not a marketplace module
(module catalog §1/§2.2, HT-66), but it is not yet built in this increment. It lands later
as a second **core** auth provider on the §4 seam, wired in `root.ts` alongside
`PasswordAuthProvider`, not through the marketplace path.
- **No entitlement/licensing machinery** — separate marketplace infrastructure.
- **No per-Agent mailbox scoping** (§3.4) — deferred; the model accommodates it.
- **No teams/groups, granular permissions, or per-mailbox roles** (FreeScout has these;
Expand Down Expand Up @@ -528,6 +540,15 @@ is retired (§8).

## Changelog

- **draft.6 (2026-07-19, catalog reconciliation, HT-76):** flagged by CodeRabbit on PR #82 —
this spec (written 2026-07-18, pre-dating the module catalog) classified passkey login as
a marketplace-only add-on; the catalog decision the same day (`specs/modules/catalog.md`
§1/§2.2, HT-66) made passkey login core, security hygiene, never paid. Reclassified
throughout (§1, §3.2, §11): passkey is core, just not yet built — it will land as a second
**core** auth provider on the §4 seam, not a marketplace module. Google SSO, magic-link,
and SAML/enterprise SSO remain marketplace, unchanged. The provider-abstraction
architecture (§3.2, §4) is unaffected — it already supports multiple core providers, not
just marketplace ones.
- **draft.5 (2026-07-18, TJ fidelity review):** mailbox-access semantics pinned and the
Permissions UI pulled forward (§3.4): admins implicit-all, auto-grant-on-create,
admin-only grant endpoints (§6: `GET /mailboxes`, `GET`/`PUT /agents/{id}/mailboxes`);
Expand Down
Loading