AgentID CLI
CLI-first registration and provider configuration for AgentID relying parties.
The CLI detects Clerk, Auth0, Supabase, or Better Auth, asks the developer to approve registration in the AgentID console, writes the resulting client credentials to the project's ignored .env.local file, and configures the selected provider.
For Clerk projects, setup is end-to-end from the terminal. AgentID ships an exact Clerk CLI version, uses its authenticated session to select or create an application, derives Clerk's /v1/oauth_callback, registers the AgentID client, and patches the Clerk instance with AgentID discovery, openid email profile, and PKCE. The connection is installed with sign-in disabled by default; pass --enable-sso only when you want it enabled immediately. The browser is used only when Clerk authentication or AgentID registration approval is required; no Clerk Dashboard work is needed.
Human owner identity is opt-in. In an interactive terminal, the CLI shows a scope picker for standard identity, owner email, owner name, or both. Agents and CI can make the same selection with --owner-name and --owner-email:
npx @agentmail/agentid-cli init --owner-name --owner-email
These flags configure the scopes Clerk, Auth0, Supabase, or Better Auth sends during /authorize; they do not add a registration-time scope policy to the AgentID client.
If the project contains NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY or CLERK_PUBLISHABLE_KEY, AgentID matches it to the correct Clerk application and instance. Otherwise it offers an interactive application and environment picker, including an option to create a Clerk application. Agents and CI can select explicitly:
npx @agentmail/agentid-cli init \
--clerk-app app_123 \
--clerk-instance dev
--clerk-instance accepts dev, prod, or a full Clerk instance ID. Clerk authentication is delegated to the bundled Clerk CLI; its existing CLI session is reused when available. Noninteractive runs fail fast when no session is available instead of attempting to open a browser.
Auth0
Auth0 setup creates AgentID as a Custom Social Connection, never an Enterprise connection. The CLI uses the official Auth0 CLI's browser session to select an authenticated tenant and a login-capable application, derives Auth0's /login/callback for the canonical tenant and ready custom domains, registers the AgentID client with client_secret_post, and creates or reconciles the oauth2 Social connection with PKCE and the AgentID logo.
Run the normal command. AgentID reuses a compatible system Auth0 CLI or its previously verified cache. If neither is available, interactive setup offers to download the official Auth0 CLI v1.33.0 release for the current operating system and architecture, verifies its pinned SHA-256 checksum, and stores that one binary in the user's AgentID cache. Nothing is installed globally and noninteractive runs never download executable code without prior preparation.
If Auth0 authentication has expired or lacks create:connections, AgentID opens the official Auth0 device login, prints the same device confirmation code shown in the browser, and resumes after authorization. Auth0's official CLI consent includes its normal management scopes plus create:connections; selecting automated token claims also requests the Auth0 Actions permissions needed to create, deploy, and bind the managed Action. AgentID never asks you to paste a Management API client secret.
npx @agentmail/agentid-cli init
Local AUTH0_DOMAIN/AUTH0_ISSUER_BASE_URL and AUTH0_CLIENT_ID values are only hints. The CLI verifies both against the tenants and applications available to the authenticated Auth0 account. You can select them explicitly without guessing:
npx @agentmail/agentid-cli init \
--auth0-tenant acme.us.auth0.com \
--auth0-app client_123
New Auth0 connections are left disabled for the application by default. Pass --enable-sso to enable AgentID immediately; reruns without that flag preserve the current enablement. Interactive setup uses the same owner-identity scope picker as Clerk; agents and CI can use --owner-name and --owner-email. Auth0's profile script copies the corresponding owner_name and owner_email claims from AgentID /userinfo into the Auth0 user profile.
Owner values remain on the Auth0 user profile by default, without adding more questions to the normal setup flow. To expose selected owner claims in Auth0-issued ID tokens, explicitly select at least one owner scope with --owner-name or --owner-email and provide an HTTPS claim namespace with --auth0-claim-namespace. The CLI then creates and deploys a managed Post Login Action. Auth0 binds Post Login Actions to the tenant-wide login flow, so the generated Action runs on every post-login transaction but immediately does nothing unless both the selected Auth0 application and the AgentID connection match. The CLI appends that Action without reordering existing post-login Actions. It does not add owner information to access tokens.
npx @agentmail/agentid-cli init \
--owner-name \
--owner-email \
--auth0-claim-namespace https://app.acme.com/claims
The resulting ID token claims are https://app.acme.com/claims/owner_name and https://app.acme.com/claims/owner_email. Without this option, owner values remain available on the Auth0 user profile but are not automatically included in Auth0-issued tokens. AgentID will not overwrite a same-name Action that it does not recognize as CLI-managed. If the tenant-wide flow contains a Marketplace-installed or secret-bound Action whose binding cannot be reconstructed losslessly, the CLI deploys the managed Action but asks you to add it to the flow in the Auth0 Dashboard.
Interactive setup requires the official Auth0 CLI's user login. Noninteractive and CI use a preauthenticated Auth0 CLI machine session with the required connection, application, and custom-domain read/write scopes.
Supabase
Supabase setup is also end-to-end from the terminal for hosted projects. The CLI detects a project URL or local Supabase link as a hint, verifies it against the projects available to the authenticated Supabase account, and otherwise presents a project picker. It registers AgentID's standard /auth/v1/callback, then creates or reconciles the custom:agentid OIDC provider through Supabase Auth's admin API with discovery, PKCE, nonce validation, and required identity scopes.
AgentID reuses a compatible official Supabase CLI or its previously verified cache. If neither is available, interactive setup offers to download the pinned official Supabase CLI v2.115.0 release for the current operating system and architecture, verifies its SHA-256 checksum, and keeps the binary in the user's AgentID cache. The Supabase CLI opens browser login when needed. AgentID uses that session to reveal a project secret in memory for the provider API call; it does not write or print the Supabase secret.
npx @agentmail/agentid-cli init
To select a project explicitly, use its immutable 20-character project ref:
npx @agentmail/agentid-cli init \
--supabase-project abcdefghijklmnopqrst
New Supabase providers are left disabled by default. Pass --enable-sso to enable AgentID sign-in immediately; reruns without that flag preserve the existing state. The owner scope picker and --owner-name/--owner-email flags add owner_profile and owner_email to the provider scopes. Supabase stores the resulting owner_name and owner_email values under the identity's custom_claims object.
Better Auth
Better Auth setup is local and end-to-end. The CLI detects a better-auth dependency and the conventional auth.ts server config in the project root, utils, lib, or the corresponding src directory. It reads the application origin from BETTER_AUTH_URL or NEXT_PUBLIC_BETTER_AUTH_URL, registers Better Auth 1.7's /api/auth/callback/agentid callback, and surgically adds AgentID to the existing genericOAuth configuration. If no Generic OAuth plugin exists, it adds one without replacing other Better Auth options or plugins.
Automatic setup supports stable Better Auth releases from 1.7.0 through 1.x because 1.7 made Generic OAuth a first-class social provider and changed its callback. A future major release must be tested before the CLI edits it automatically. If multiple conventional auth.* files exist, the interactive flow asks which one is the server config and noninteractive setup requires an explicit selection. For a custom config path or application URL, pass both values explicitly:
npx @agentmail/agentid-cli init \
--better-auth-config src/server/auth.ts \
--better-auth-url https://app.acme.com
--better-auth-url normally receives the application origin. The CLI reads a static basePath from the config when deriving the callback. If basePath is dynamic, pass the complete auth base URL instead, such as https://app.acme.com/private/auth.
The managed provider uses AgentID OIDC discovery, client_secret_basic, explicit PKCE, verified ID tokens, and the selected identity scopes. Existing Generic OAuth providers remain in the same config array. Reruns preserve scopes unless the owner picker or owner flags explicitly replace them. The CLI refuses to overwrite a hand-written providerId: "agentid", a modified CLI-managed block, symlinked or out-of-project configs, ambiguous noninteractive config selection, or dynamic/spread shapes it cannot inspect without risking existing plugins.
Better Auth does not have a hosted connection enablement switch. Adding the server provider does not add a button to the application. Offer AgentID sign-in from the app's UI when ready:
await authClient.signIn.social({ provider: "agentid" })
The owner flags add owner_profile and owner_email to the AgentID authorization request. Better Auth maps the standard name and email fields automatically. Persisting owner-specific fields into a custom Better Auth user or session schema remains application-specific, so the CLI does not modify the database schema.
When automatic detection cannot determine the relying-party integration, the CLI offers Clerk, Auth0, Supabase, Better Auth, Auth.js, and generic OIDC setup. Choosing Supabase enters its authenticated project picker. Choosing Better Auth resumes local dependency and config discovery and asks for the application URL only when it is not configured. Auth.js offers its conventional callback as an editable default. Generic OIDC accepts one or more callback URLs.
For agents and noninteractive environments, provide the metadata directly:
npx @agentmail/agentid-cli init \
--name Acme \
--redirect-uri https://acme.example/auth/callback
Repeat --redirect-uri to register more than one callback.
To remove the local project association without deleting the remote AgentID client or changing provider configuration, run:
npx @agentmail/agentid-cli unlink
The command removes only AGENTID_CLIENT_ID, AGENTID_CLIENT_SECRET, and AGENTID_PROJECT_BINDING from the nearest project .env.local. It preserves unrelated variables, refuses symlinked environment files, and asks for confirmation. Automated test cleanup can use agentid unlink --yes.
Running init again with valid AgentID credentials already present is idempotent. The CLI stores a non-secret AGENTID_PROJECT_BINDING beside the credentials and refuses to reuse them for a different RP or AgentID console environment. Clerk bindings use immutable application and instance IDs; Auth0 bindings use the authenticated tenant and application client ID; Supabase bindings use the immutable project ref; Better Auth bindings include the local config path and registered callback. Rerunning reapplies and validates managed provider configuration while preserving hosted-provider sign-in enablement unless --enable-sso is explicit. Use --force only when you intentionally want to register a replacement client and overwrite the local credentials; the previous client remains in the AgentID console until you delete it.
Development
Requires Node.js 20 or newer and pnpm 10.
pnpm install
pnpm check
pnpm dev -- init
To exercise a local console:
pnpm dev -- init --console-url http://localhost:3012
The CLI uses a short-lived loopback callback, PKCE, and a browser-delivered completion verifier. Client secrets are never returned to the browser.
Package
The package is published as @agentmail/agentid-cli and exposes the agentid executable.
npx @agentmail/agentid-cli init
The preferred npx agentid init command requires control of the existing unscoped agentid package on npm.
Releases
Every change runs the CLI from the packed npm tarball as part of pnpm check. Publishing is triggered by a GitHub Release whose tag exactly matches the package version, such as v0.2.0. The release workflow publishes the public scoped package from Node.js 24 using npm trusted publishing. npm provenance is unavailable while the source repository is private.
Automated publishing uses these npm and GitHub settings:
- Configure the package's npm trusted publisher for GitHub organization
agentmail-to, repositoryagentid-cli, workflowrelease.yml, environmentnpm, and allownpm publish. - Restrict the repository's
npmenvironment to tags matchingv*. Add required reviewers as well when the repository's GitHub plan supports protected environments for private repositories. - Set npm publishing access to require two-factor authentication and disallow bypass-capable tokens. Trusted publishing continues to work without a long-lived npm token.
For each release, increment package.json, merge the change, and publish a matching GitHub Release. The workflow refuses tags whose commit is not on main, runs release validation and the full packed-package suite without OIDC permission, and smoke-tests the exact tarball passed to the final publish job. Only that final job may request an npm OIDC token. No long-lived npm token is used by the workflow.