Early Access — This CLI is under active development and not yet officially supported. We'd love your feedback! Please open an issue or reach out with suggestions.
A command-line interface for managing your Clerk instances. This CLI provides tools for managing users, organizations, sessions, domains, Clerk Protect, and more.
From Homebrew:
## new install:
brew tap clerk/cli [email protected]:clerk/cli.git && brew install clerk
## or to update:
brew update && brew upgrade clerk
From NPX:
npx --yes github:clerk/cli@latest [command] [options]
Build from source:
go build -o clerk ./cmd/clerkRun the setup wizard to configure your first profile:
clerk initThis will guide you through:
- Entering your Clerk Secret Key (find it in the Clerk Dashboard → API Keys)
- Optionally creating a named profile
Alternatively, create a profile directly:
clerk config profile create default --api-key sk_live_xxxxxclerk whoamiclerk users list
clerk protect rules list SIGN_INIf you run a command without an API key configured, the CLI will prompt you to enter one in interactive terminals.
These options can be used with any command:
| Option | Description |
|---|---|
-p, --profile <name> |
Use a specific profile |
-o, --output <format> |
Output format: table, json, or yaml (default: table) |
--dotenv |
Use CLERK_SECRET_KEY from .env file (see Project-Level Configuration) |
--debug |
Enable debug mode (outputs HTTP requests to stderr) |
-h, --help |
Display colorized help |
Help output is automatically colorized when running in an interactive terminal. You can control this behavior with environment variables:
NO_COLOR=1- Disable colorsFORCE_COLOR=1- Force colors even in non-interactive mode
# Output as JSON
clerk -o json protect rules list SIGN_IN
# Output as YAML
clerk --output yaml users get user_abc123
# Combine options
clerk --profile staging -o json protect rules listYou can abbreviate commands as long as they're unambiguous:
clerk prot rul list SIGN_IN # protect rules list
clerk conf prof li # config profile list
clerk w # whoami
clerk us ls # users listIf a prefix matches multiple commands, an error is shown.
Create custom shortcuts for frequently used commands:
# Create aliases
clerk config alias add prl -- protect rules list
clerk config alias add pra protect rules add
# Use aliases
clerk prl SIGN_IN # expands to: clerk protect rules list SIGN_IN
clerk pra SIGN_IN -g "block" # expands to: clerk protect rules add SIGN_IN -g "block"See clerk config alias for full documentation.
Run the interactive setup wizard to configure the CLI. This is the recommended way to get started.
clerk initThe wizard will prompt you for:
- Clerk Secret Key
- Profile name (default: "default")
Note: This command requires an interactive terminal.
Display the currently active profile and how it was selected.
clerk whoami
# Active profile: production
# (set via CLERK_PROFILE environment variable)The CLI uses an INI-based configuration system where profiles can override default settings. Each profile can have its own API key, output format, debug mode, and other settings.
When resolving a setting value, the CLI checks in this order:
- Command-line flag (e.g.,
--output json) - Environment variable (e.g.,
CLERK_SECRET_KEY) .envfile (forclerk.keyonly, when applicable — see below)- Active profile's value
- Default value
The CLI can automatically detect and use a CLERK_SECRET_KEY from a .env file in your project directory. This is useful for development workflows where you want to use project-specific API keys without configuring global profiles.
When you run a command without the -p flag, the CLI searches for a .env file starting from the current directory and walking up through parent directories. If found, it reads the CLERK_SECRET_KEY value.
# Example .env file in your project root
CLERK_SECRET_KEY=sk_test_xxxxxThe .env file is used as a fallback when no profile key is configured:
- If your profile already has a
clerk.keyconfigured → profile key is used - If your profile has no key →
.envfile is used automatically
When a .env file exists but your profile has a key configured, the CLI warns you:
⚠ Found .env file at /path/to/project/.env but using profile key. Use --dotenv to use the .env file instead.
Use the --dotenv flag to explicitly use the .env file, even when your profile has a key configured:
# Force using .env file instead of profile key
clerk users list --dotenv
# See which key would be used
clerk whoami --dotenv
# Check config resolution
clerk config list --dotenvThe .env file is skipped in these cases:
- When
-p <profile>flag is specified (explicit profile selection) - When
CLERK_SECRET_KEYenvironment variable is set (env var takes priority) - When
--dotenvis not specified and the active profile has a key configured
# Project structure
my-app/
├── .env # Contains CLERK_SECRET_KEY=sk_test_project_key
└── src/
# In the project directory (no profile key configured)
cd my-app
clerk users list # Uses sk_test_project_key from .env
# With a profile key configured
clerk config set clerk.key sk_test_profile_key
clerk users list # Uses sk_test_profile_key (warns about .env)
clerk users list --dotenv # Uses sk_test_project_key from .env
# Using explicit profile
clerk users list -p staging # Uses staging profile, ignores .envThe CLI supports standard .env file format:
# Comments are ignored
CLERK_SECRET_KEY=sk_test_xxxxx
# Quoted values are supported
CLERK_SECRET_KEY="sk_test_xxxxx"
CLERK_SECRET_KEY='sk_test_xxxxx'
# Spaces around = are allowed
CLERK_SECRET_KEY = sk_test_xxxxxOnly CLERK_SECRET_KEY is read from .env files. Other Clerk environment variables (like CLERK_API_URL) should be set via profiles or shell environment variables.
| Setting | Description | Env Var |
|---|---|---|
clerk.key |
Clerk secret API key | CLERK_SECRET_KEY |
clerk.api.url |
Clerk API URL (default: https://api.clerk.com) |
CLERK_API_URL |
output |
Default output format (table, json, yaml) |
|
debug |
Enable debug mode (true, false) |
CLERK_CLI_DEBUG |
ai.provider |
AI provider (openai, anthropic) |
|
ai.openai.key |
OpenAI API key | OPENAI_API_KEY |
ai.openai.model |
OpenAI model (default: gpt-4o) |
|
ai.anthropic.key |
Anthropic API key | ANTHROPIC_API_KEY |
ai.anthropic.model |
Anthropic model (default: claude-sonnet-4-20250514) |
|
ai.mcp.config |
Path to MCP servers config file (default: ~/.config/clerk/cli/mcp.json) |
Set a configuration value. Use --profile to set in a specific profile.
| Option | Description |
|---|---|
-p, --profile <name> |
Set value in a specific profile |
--type <type> |
Value type: command (executes shell command to get value) |
# Set default output format
clerk config set output json
# Set API key in a specific profile
clerk config set clerk.key sk_live_xxxxx --profile production
# Use a command to fetch the API key from a secrets manager
clerk config set clerk.key "op read 'op://Vault/Clerk/api-key'" --type=command --profile productionGet a configuration value.
| Option | Description |
|---|---|
-p, --profile <name> |
Get value for a specific profile |
--resolve |
Execute command-type values to get the actual value |
clerk config get output
# json
clerk config get clerk.key --profile production
# ****xxxx
# For command-type values, use --resolve to execute
clerk config get clerk.key --profile production --resolve
# sk_live_xxxxxRemove a configuration value.
| Option | Description |
|---|---|
-p, --profile <name> |
Unset from a specific profile |
clerk config unset output
clerk config unset debug --profile developmentList all configuration settings and their current values.
| Option | Description |
|---|---|
-p, --profile <name> |
Show resolved values for a specific profile |
clerk config list
# Profile: default
#
# KEY VALUE SOURCE
# clerk.key sk_te****xxxx profile
# clerk.api.url https://api.clerk… default
# output table default
# debug (not set) -Show the configuration file path.
clerk config path
# /Users/you/.config/clerk/cli/profilesManage CLI profiles. Profiles allow you to switch between different Clerk instances (development, staging, production) with different settings.
List all configured profiles.
clerk config profile list
# NAME
# * default
# staging
# productionCreate a new profile.
| Option | Description |
|---|---|
--api-key <key> |
Clerk secret API key |
--api-url <url> |
Custom API URL |
# Basic usage
clerk config profile create production --api-key sk_live_xxxxx
# With custom API URL
clerk config profile create staging --api-key sk_test_xxxxx --api-url https://api.staging.clerk.comUpdate an existing profile. Use clerk config set with --profile to update individual settings.
clerk config set clerk.key sk_live_new_key --profile productionDelete a profile.
| Option | Description |
|---|---|
-f, --force |
Skip confirmation prompt |
clerk config profile delete stagingSet the active profile.
clerk config profile use productionShow profile details. If no name is provided, shows the active profile.
clerk config profile show production
# Profile: production
# clerk.key: ****xxxx
# clerk.api.url: https://api.clerk.comDisplay the path to the profiles configuration file.
clerk config profile path
# /Users/you/.config/clerk/cli/profilesManage command aliases for creating shortcuts to frequently used commands.
Create a command alias. Arguments passed when using the alias are appended to the command.
clerk config alias add prl protect rules list
clerk config alias add pra protect rules add
clerk config alias add cpl config profile listRemove a command alias. Also available as clerk config alias rm.
clerk config alias remove prl
clerk config alias rm praList all configured aliases. Also available as clerk config alias ls.
clerk config alias list
# NAME COMMAND
# prl protect rules list
# pra protect rules addShow the aliases file path.
clerk config alias path
# /Users/you/.config/clerk/cli/aliases.jsonWhen you use an alias, any additional arguments are appended:
# If prl = "protect rules list"
clerk prl SIGN_IN --limit 5
# Expands to: clerk protect rules list SIGN_IN --limit 5clerk config alias add prl protect rules list
clerk config alias add pra protect rules add
clerk config alias add prg protect rules get
clerk config alias add prd protect rules delete
clerk config alias add pre protect rules edit
clerk config alias add prr protect rules reorder
clerk config alias add prf protect rules flush
clerk config alias add ps protect schema show| Variable | Description |
|---|---|
CLERK_PROFILE |
Profile name to use (overrides the default profile) |
CLERK_SECRET_KEY |
API key (overrides profile's API key) |
CLERK_API_URL |
API URL (overrides profile's API URL) |
CLERK_CLI_DEBUG |
Set to 1 or true to enable debug mode |
OPENAI_API_KEY |
OpenAI API key for AI-powered rule generation |
ANTHROPIC_API_KEY |
Anthropic API key for AI-powered rule generation |
The CLI determines which profile to use in this order:
--profile <name>command-line flagCLERK_PROFILEenvironment variable- Default profile from configuration file
- Falls back to a profile named "default"
# Use a specific profile for one command
clerk --profile staging protect rules list SIGN_IN
# Set profile via environment variable
export CLERK_PROFILE=production
clerk protect rules list SIGN_IN
# Override API key for CI/CD
CLERK_SECRET_KEY=${{ secrets.CLERK_KEY }} clerk protect rules list SIGN_INAll protect subcommands accept the following option:
| Option | Description |
|---|---|
--mcp-config <path> |
Path to MCP servers config file (overrides profile setting and default) |
Manage Clerk Protect rules for blocking suspicious authentication attempts.
Rules are organized into rulesets based on the event type:
| Ruleset | Description |
|---|---|
ALL |
Rules applied to all event types |
SIGN_IN |
Rules for sign-in authentication attempts |
SIGN_UP |
Rules for new user registrations |
SMS |
Rules for SMS verification requests |
EMAIL |
Rules for email verification requests |
List all rules in a ruleset. If no ruleset is specified, lists rules from all rulesets.
| Option | Description |
|---|---|
--limit <n> |
Maximum number of rules to return |
--after <id> |
Pagination cursor (rule ID to start after) |
clerk protect rules list SIGN_INGet details of a specific rule.
clerk protect rules get SIGN_IN rule_abc123Open a rule's expression in your preferred editor ($VISUAL or $EDITOR).
| Option | Description |
|---|---|
--description <text> |
Also update the rule description |
clerk protect rules edit SIGN_IN rule_abc123Note: Set the EDITOR or VISUAL environment variable to use a specific editor (e.g., export EDITOR=nano). For GUI editors that detach, use a wait flag (e.g., export EDITOR="code --wait").
Add a new rule. If ruleset or expression are not provided and the terminal is interactive, you will be prompted to enter them.
| Option | Description |
|---|---|
--expression <expr> |
Rule expression (must evaluate to boolean) |
-g, --generate <desc> |
Generate expression from natural language using AI |
--action <action> |
Action when expression is true (default: BLOCK) |
--description <text> |
Human-readable description |
--before <id> |
Insert before this rule ID |
--after <id> |
Insert after this rule ID |
--index <n> |
Insert at specific index |
# With all options specified
clerk protect rules add SIGN_IN \
--expression "ip.privacy.is_vpn == true" \
--description "Block VPN users" \
--action BLOCK
# Interactive mode (will prompt for ruleset, expression, and description)
clerk protect rules add
# Generate expression from natural language description
clerk protect rules add SIGN_IN --generate "block requests from datacenters"
clerk protect rules add SIGN_IN -g "when the bot score is greater than 50%"Delete a specific rule.
| Option | Description |
|---|---|
-f, --force |
Skip confirmation prompt |
clerk protect rules delete SIGN_IN rule_abc123Delete all rules in a ruleset.
clerk protect rules flush SIGN_IN --forceInteractively reorder rules within a ruleset. Rules are evaluated in order from top to bottom.
clerk protect rules reorder SIGN_INNote: This command requires an interactive terminal.
The --generate (or -g) flag on clerk protect rules add uses AI to convert natural language descriptions into valid rule expressions.
Configure an AI provider using settings, commands, or environment variables:
# Option 1: Using config settings (stores key in plain text)
clerk config set ai.provider openai
clerk config set ai.openai.key sk-...
# Option 2: Using a command to fetch from a secret manager (recommended)
clerk config set ai.provider openai
clerk config set ai.openai.key "op read 'op://Vault/OpenAI/api-key'" --type=command
# Or for Anthropic
clerk config set ai.provider anthropic
clerk config set ai.anthropic.key "vault kv get -field=api_key secret/anthropic" --type=command
# Option 3: Using environment variables
export OPENAI_API_KEY=sk-...
# or
export ANTHROPIC_API_KEY=sk-ant-...When using --type=command, the command is executed each time the API key is needed, ensuring you always have fresh credentials.
# Generate and create a rule
clerk protect rules add SIGN_IN --generate "block requests from datacenters"
# The CLI will:
# 1. Fetch the schema for the ruleset
# 2. Generate an expression using AI
# 3. Show you the generated expression
# 4. Ask for confirmation before creating- "block VPN users"
- "requests from Russia or China"
- "when the IP is from a datacenter"
- "high bot scores above 70%"
- "non-US phone numbers with suspicious activity"
- "block if automation score exceeds 50%"
You can connect external tool servers using the Model Context Protocol (MCP) to give the AI access to live data during rule generation. This is useful for lookups that the AI can't do on its own, such as:
- Converting an ASN name (e.g., "Cloudflare") to its ASN number
- Looking up which ASN is announcing a specific IP address
- Querying domain name registration (WHOIS) data
- Resolving hostnames or checking IP reputation
Create ~/.config/clerk/cli/mcp.json:
{
"servers": {
"asn-lookup": {
"command": "npx",
"args": ["-y", "@example/asn-mcp-server"]
},
"whois": {
"command": "/usr/local/bin/whois-mcp-server",
"env": {
"API_KEY": "your-api-key"
}
}
}
}Each server entry has:
| Field | Description |
|---|---|
command |
The executable to run (required) |
args |
Command-line arguments (optional) |
env |
Additional environment variables (optional) |
Servers are started as subprocesses using the MCP stdio transport. The CLI discovers available tools from each server at startup and makes them available to the LLM during expression generation and modification.
To use a different config file, pass --mcp-config to any protect subcommand:
clerk protect rules add --generate "block VPNs" --mcp-config /path/to/mcp.jsonYou can also set it per profile:
clerk config set ai.mcp.config /path/to/custom/mcp.json --profile productionWhen MCP servers are configured, the AI can call tools during rule generation:
$ clerk protect rules add SIGN_IN -g "block traffic from Cloudflare's ASN"
Loaded 3 tool(s) from MCP servers
Generating expression for: block traffic from Cloudflare's ASN
# The AI calls the asn-lookup tool to resolve "Cloudflare" → AS13335
# Then generates the expression using the resolved number
Generated expression:
ip.asn.number == 13335
? Create rule with this expression? Yes
If no MCP servers are configured, the AI generates expressions using only the schema and its built-in knowledge — no tools are called. Servers that fail to start are skipped gracefully.
Use --debug or CLERK_CLI_DEBUG=1 to see MCP tool calls and results:
CLERK_CLI_DEBUG=1 clerk protect rules add SIGN_IN -g "block Cloudflare ASN"
# [DEBUG] MCP tool call: resolve_asn({"name":"Cloudflare"})
# [DEBUG] MCP tool result: {"asn":13335,"name":"Cloudflare, Inc.","country":"US"}View expression schemas for rule expressions.
Show the detailed schema for an event type.
| Option | Description |
|---|---|
--flat |
Show fields as flat dot-notation paths |
clerk protect schema show SIGN_IN
clerk protect schema show SIGN_IN --flatList all available event types and their top-level fields.
clerk protect schema listShow struct type details. If no type names are specified, lists all available types.
clerk protect schema type
clerk protect schema type ip geoManage Clerk users - list, create, update, delete, ban, lock, and more. Also available as clerk user.
List all users with optional filtering and pagination.
| Option | Description |
|---|---|
--limit <n> |
Maximum number of users to return (default: 10) |
--offset <n> |
Number of users to skip for pagination |
--order-by <field> |
Sort field (prefix with - for desc, + for asc) |
--email <emails> |
Filter by email addresses (comma-separated) |
--phone <phones> |
Filter by phone numbers (comma-separated) |
--username <usernames> |
Filter by usernames (comma-separated) |
--external-id <ids> |
Filter by external IDs (comma-separated) |
--user-id <ids> |
Filter by user IDs (comma-separated) |
--organization-id <ids> |
Filter by organization membership (comma-separated) |
--query <text> |
Search across email, phone, username, name, user ID |
--last-active-since <timestamp> |
Filter users active since this Unix timestamp |
clerk users list
clerk users list --limit 50 --offset 100
clerk users list --query "john"
clerk users list --email [email protected]
clerk users list --order-by -last_active_atGet total user count with optional filtering.
| Option | Description |
|---|---|
--email <email> |
Filter by email |
--phone <phone> |
Filter by phone |
--query <text> |
Search query |
clerk users count
clerk users count --query "example.com"Get detailed information about a specific user.
clerk users get user_2abc123def456Create a new user.
| Option | Description |
|---|---|
--email <emails> |
Email addresses (comma-separated) |
--phone <phones> |
Phone numbers (comma-separated) |
--username <username> |
Username |
--first-name <name> |
First name |
--last-name <name> |
Last name |
--password <password> |
Password |
--external-id <id> |
External ID |
--public-metadata <json> |
Public metadata (JSON) |
--private-metadata <json> |
Private metadata (JSON) |
--skip-password-checks |
Skip password complexity validation |
--skip-password-requirement |
Allow creating user without password |
clerk users create --email [email protected] --first-name John --last-name Doe
clerk users create --email [email protected] --password "securepassword123"Update an existing user.
| Option | Description |
|---|---|
--first-name <name> |
First name |
--last-name <name> |
Last name |
--username <username> |
Username |
--password <password> |
New password |
--external-id <id> |
External ID |
--primary-email-id <id> |
Set primary email address by ID |
--primary-phone-id <id> |
Set primary phone number by ID |
--public-metadata <json> |
Public metadata (replaces existing) |
--private-metadata <json> |
Private metadata (replaces existing) |
--skip-password-checks |
Skip password complexity validation |
--sign-out-other-sessions |
Sign out all other sessions after password change |
clerk users update user_123 --first-name Jane --last-name Smith
clerk users update user_123 --password "newpassword123" --sign-out-other-sessionsDelete a user permanently.
| Option | Description |
|---|---|
-f, --force |
Skip confirmation prompt |
clerk users delete user_123
clerk users delete user_123 --forceBan a user, revoking all sessions and preventing sign-in.
clerk users ban user_123Remove the ban from a user.
clerk users unban user_123Lock a user account temporarily.
clerk users lock user_123Remove the lockout from a user account.
clerk users unlock user_123Verify a user's password.
| Option | Description |
|---|---|
--password <password> |
Password to verify (prompts if not provided) |
clerk users verify-password user_123 --password "testpassword"
clerk users verify-password user_123 # interactive promptManage organizations, memberships, and invitations. Also available as clerk orgs.
| Option | Description |
|---|---|
--limit <n> |
Maximum number to return |
--offset <n> |
Pagination offset |
--order-by <field> |
Sort field |
--query <text> |
Search by name or slug |
--include-members-count |
Include member counts |
clerk organizations list
clerk orgs list --query "acme" --include-members-countGet organization details.
clerk organizations get org_abc123| Option | Description |
|---|---|
--name <name> |
Organization name (required) |
--slug <slug> |
URL-friendly identifier |
--created-by <userId> |
User ID of the creator |
--max-allowed-memberships <n> |
Maximum members allowed |
--public-metadata <json> |
Public metadata |
--private-metadata <json> |
Private metadata |
clerk organizations create --name "Acme Corp"
clerk orgs create --name "Acme Corp" --slug "acme" --max-allowed-memberships 50| Option | Description |
|---|---|
--name <name> |
Organization name |
--slug <slug> |
Slug |
--max-allowed-memberships <n> |
Max membership limit |
--public-metadata <json> |
Public metadata |
--private-metadata <json> |
Private metadata |
clerk organizations update org_abc123 --name "Acme Corporation"| Option | Description |
|---|---|
-f, --force |
Skip confirmation prompt |
clerk organizations delete org_abc123 --force| Option | Description |
|---|---|
--limit <n> |
Maximum members to return |
--offset <n> |
Pagination offset |
--role <roles> |
Filter by role(s) |
clerk orgs members list org_abc123
clerk orgs members list org_abc123 --role admin| Option | Description |
|---|---|
--role <role> |
Role to assign (required) |
clerk orgs members add org_abc123 user_xyz --role basic_member| Option | Description |
|---|---|
--role <role> |
New role to assign |
clerk orgs members update org_abc123 mem_xyz --role adminclerk orgs members remove org_abc123 mem_xyz| Option | Description |
|---|---|
--limit <n> |
Maximum invitations to return |
--offset <n> |
Pagination offset |
--status <status> |
Filter by status: pending, accepted, revoked |
clerk orgs invitations list org_abc123 --status pending| Option | Description |
|---|---|
--email <email> |
Email address to invite (required) |
--role <role> |
Role to assign when accepted (required) |
--inviter-user-id <id> |
User ID of the inviter |
--redirect-url <url> |
URL to redirect to after accepting |
clerk orgs invitations create org_abc123 --email [email protected] --role basic_memberclerk orgs invitations revoke org_abc123 inv_xyzManage user sessions. Also available as clerk session.
| Option | Description |
|---|---|
--user-id <id> |
Filter by user ID |
--client-id <id> |
Filter by client ID |
--status <status> |
Filter by status |
--limit <n> |
Maximum sessions to return |
--offset <n> |
Pagination offset |
clerk sessions list --user-id user_2abc123
clerk sessions list --user-id user_2abc123 --status activeclerk sessions get sess_abc123clerk sessions revoke sess_abc123Manage API keys. Also available as clerk api-keys.
| Option | Description |
|---|---|
--subject <id> |
Filter by user ID or organization ID |
--query <text> |
Search by name |
--limit <n> |
Maximum keys to return |
--offset <n> |
Pagination offset |
clerk apikeys list
clerk apikeys list --subject user_2abc123clerk apikeys get ak_abc123| Option | Description |
|---|---|
--name <name> |
Name for the API key (required) |
--subject <id> |
User ID or organization ID (required) |
--description <text> |
Description |
--scopes <scopes> |
Comma-separated scopes |
--expires-in <seconds> |
Seconds until expiration |
clerk apikeys create --name "My API Key" --subject user_2abc123| Option | Description |
|---|---|
-f, --force |
Skip confirmation prompt |
clerk apikeys revoke ak_abc123Manage instance-level invitations. Also available as clerk invite.
| Option | Description |
|---|---|
--status <status> |
Filter by status: pending, accepted, revoked, expired |
--limit <n> |
Maximum invitations to return |
--offset <n> |
Pagination offset |
clerk invitations list
clerk invitations list --status pending| Option | Description |
|---|---|
--email <email> |
Email address to invite (required) |
--redirect-url <url> |
URL to redirect to after accepting |
--expires-in-days <n> |
Days until expiration |
--no-notify |
Don't send the invitation email |
--ignore-existing |
Create even if invitation already exists |
--public-metadata <json> |
Public metadata |
clerk invitations create --email [email protected]
clerk invitations create --email [email protected] --no-notify --expires-in-days 7Create multiple invitations at once.
| Option | Description |
|---|---|
--emails <emails> |
Comma-separated email addresses (required) |
--redirect-url <url> |
Redirect URL |
--expires-in-days <n> |
Days until expiration |
--no-notify |
Don't send invitation emails |
clerk invitations bulk-create --emails [email protected],[email protected],[email protected]| Option | Description |
|---|---|
-f, --force |
Skip confirmation prompt |
clerk invitations revoke inv_abc123Manage allowlist and blocklist restrictions for sign-ups.
List all allowlist and blocklist identifiers.
clerk restrictions list
clerk restrictions lsAdd an identifier to the allowlist or blocklist.
| Option | Description |
|---|---|
--allow |
Add to allowlist (permits sign-up) |
--block |
Add to blocklist (prevents sign-up) |
--notify |
Send notification email (allowlist only) |
# Add to allowlist
clerk restrictions add [email protected] --allow
clerk restrictions add [email protected] --allow --notify
# Add to blocklist
clerk restrictions add [email protected] --block
clerk restrictions add "@spam-domain.com" --blockRemove an identifier from the allowlist or blocklist by its ID. Also available as clerk restrictions rm.
clerk restrictions remove alid_abc123
clerk restrictions rm blid_abc123Manage email addresses for users. Also available as clerk users email.
List all email addresses for a user.
clerk users emails list user_abc123Get details of an email address.
clerk users emails get idn_abc123Add an email address to a user.
| Option | Description |
|---|---|
--email <email> |
Email address (required) |
--verified |
Mark as verified |
--primary |
Set as primary email |
clerk users emails add user_abc123 --email [email protected]
clerk users emails add user_abc123 --email [email protected] --verified --primaryUpdate an email address.
| Option | Description |
|---|---|
--verified |
Mark as verified |
--primary |
Set as primary email |
clerk users emails update idn_abc123 --verified --primaryRemove an email address.
clerk users emails remove idn_abc123Manage phone numbers for users. Also available as clerk users phone.
List all phone numbers for a user.
clerk users phones list user_abc123Get details of a phone number.
clerk users phones get idn_abc123Add a phone number to a user.
| Option | Description |
|---|---|
--phone <number> |
Phone number in E.164 format (required) |
--verified |
Mark as verified |
--primary |
Set as primary phone number |
clerk users phones add user_abc123 --phone "+15551234567"
clerk users phones add user_abc123 --phone "+15551234567" --verified --primaryUpdate a phone number.
| Option | Description |
|---|---|
--verified |
Mark as verified |
--primary |
Set as primary phone number |
clerk users phones update idn_abc123 --verified --primaryRemove a phone number.
clerk users phones remove idn_abc123Manage instance domains including satellite domains.
clerk domains listclerk domains get dom_abc123| Option | Description |
|---|---|
--name <name> |
Domain name (required) |
--proxy-url <url> |
Proxy URL |
clerk domains add --name app.example.com| Option | Description |
|---|---|
--name <name> |
New domain name |
--proxy-url <url> |
Proxy URL |
clerk domains update dom_abc123 --name new.example.com| Option | Description |
|---|---|
-f, --force |
Skip confirmation prompt |
clerk domains delete dom_abc123 --forceManage JWT templates. Also available as clerk jwt.
clerk jwttemplates listclerk jwttemplates get jtmpl_abc123| Option | Description |
|---|---|
--name <name> |
Template name (required) |
--claims <json> |
Claims as JSON object (required) |
--lifetime <seconds> |
Token lifetime in seconds |
--clock-skew <seconds> |
Allowed clock skew in seconds |
--signing-algorithm <alg> |
Signing algorithm (e.g., RS256, HS256) |
--signing-key <key> |
Signing private key |
clerk jwttemplates create \
--name "Hasura" \
--claims '{"https://hasura.io/jwt/claims": {"x-hasura-user-id": "{{user.id}}"}}'Same options as create.
clerk jwttemplates update jtmpl_abc123 --lifetime 7200| Option | Description |
|---|---|
-f, --force |
Skip confirmation prompt |
clerk jwttemplates delete jtmpl_abc123 --forceRetrieve JSON Web Key Sets for your Clerk instance.
clerk jwks get
clerk jwks get -o jsonManage instance-level settings and restrictions.
clerk instance get| Option | Description |
|---|---|
--test-mode / --no-test-mode |
Enable/disable test mode |
--hibp / --no-hibp |
Enable/disable HIBP password breach checking |
--support-email <email> |
Support email address |
--clerk-js-version <version> |
Clerk.js version |
--development-origin <origin> |
Development origin URL |
--allowed-origins <origins> |
Allowed origins (comma-separated) |
--url-based-session-syncing / --no-url-based-session-syncing |
URL-based session syncing |
clerk instance update --test-mode
clerk instance update --support-email [email protected]| Option | Description |
|---|---|
--allowlist / --no-allowlist |
Enable/disable allowlist |
--blocklist / --no-blocklist |
Enable/disable blocklist |
--block-email-subaddresses / --no-block-email-subaddresses |
Block email subaddresses |
--block-disposable-emails / --no-block-disposable-emails |
Block disposable emails |
clerk instance restrictions update --allowlist --block-disposable-emailsManage machine-to-machine authentication.
| Option | Description |
|---|---|
--machine-id <id> |
Filter by machine ID |
--limit <n> |
Maximum tokens to return |
--offset <n> |
Pagination offset |
clerk m2m tokens list --machine-id mch_abc123| Option | Description |
|---|---|
--machine-id <id> |
Machine ID (required) |
--scopes <scopes> |
Comma-separated scopes |
--expires-in <seconds> |
Seconds until expiration |
clerk m2m tokens create --machine-id mch_abc123 --scopes "read:users,write:users"| Option | Description |
|---|---|
--token <token> |
Token to verify (required) |
clerk m2m tokens verify --token clerk_m2m_xxxxx| Option | Description |
|---|---|
--limit <n> |
Maximum machines to return |
--offset <n> |
Pagination offset |
--query <text> |
Search query |
clerk m2m machines list
clerk m2m machines list --query "backend"clerk m2m machines get mch_abc123| Option | Description |
|---|---|
--name <name> |
Machine name (required) |
--scopes <scopes> |
Comma-separated scopes |
clerk m2m machines create --name "Backend Service"| Option | Description |
|---|---|
--name <name> |
New machine name |
clerk m2m machines update mch_abc123 --name "New Service Name"clerk m2m machines delete mch_abc123Retrieve the secret for a machine.
clerk m2m machines get-secret mch_abc123| Option | Description |
|---|---|
--scope <scope> |
Scope to add (required) |
clerk m2m machines add-scope mch_abc123 --scope "read:users"Manage billing plans, subscriptions, and statements.
List all billing plans.
| Option | Description |
|---|---|
--limit <n> |
Maximum plans to return (default: 10) |
--offset <n> |
Pagination offset |
clerk billing plans list
clerk billing plans ls -o jsonGet the billing subscription for a user.
clerk billing subscription get-user user_abc123
clerk billing subscription get-user user_abc123 -o jsonGet the billing subscription for an organization.
clerk billing subscription get-org org_abc123
clerk billing subscription get-org org_abc123 -o jsonManage subscription items. Also available as clerk billing items.
List all subscription items.
| Option | Description |
|---|---|
--limit <n> |
Maximum items to return (default: 10) |
--offset <n> |
Pagination offset |
clerk billing subscription-items list
clerk billing items lsDelete a subscription item.
| Option | Description |
|---|---|
-f, --force |
Skip confirmation prompt |
clerk billing subscription-items delete csub_item_abc123
clerk billing items delete csub_item_abc123 --forceExtend the free trial for a subscription item.
| Option | Description |
|---|---|
--days <n> |
Number of days to extend the trial |
clerk billing subscription-items extend-trial csub_item_abc123 --days 14Transition a subscription item to a new price.
| Option | Description |
|---|---|
--price-id <id> |
New price ID |
--immediate |
Apply transition immediately |
clerk billing subscription-items transition-price csub_item_abc123 --price-id cprice_xyz --immediateList all billing statements.
| Option | Description |
|---|---|
--limit <n> |
Maximum statements to return (default: 10) |
--offset <n> |
Pagination offset |
clerk billing statements list
clerk billing statements ls -o jsonGet details of a specific statement.
clerk billing statements get stmt_abc123
clerk billing statements get stmt_abc123 -o jsonList payment attempts for a statement.
| Option | Description |
|---|---|
--limit <n> |
Maximum attempts to return (default: 10) |
--offset <n> |
Pagination offset |
clerk billing statements payment-attempts stmt_abc123
clerk billing statements payment-attempts stmt_abc123 -o jsonThe CLI stores configuration in ~/.config/clerk/cli/:
| File | Purpose |
|---|---|
profiles |
Configuration profiles and settings (INI format) |
aliases.json |
Command aliases (JSON format) |
mcp.json |
MCP tool server configuration (JSON format, optional) |
Configuration is stored in ~/.config/clerk/cli/profiles using INI format:
[default]
profile = production
[profile default]
clerk.key = sk_test_xxxxx
output = table
[profile production]
clerk.key = sk_live_xxxxx
output = json
[profile staging]
clerk.key = sk_test_yyyyy
clerk.api.url = https://api.staging.clerk.com
[profile vault]
clerk.key = !op read 'op://Vault/Clerk/api-key'
output = tableStructure:
[default]section: Global settings and active profile[profile <name>]sections: Profile-specific settings- Lines starting with
#or;are comments - Values prefixed with
!are treated as shell commands
Aliases are stored in ~/.config/clerk/cli/aliases.json:
{
"prl": "protect rules list",
"pra": "protect rules add"
}Instead of storing API keys directly, use --type=command with config set to store a command that fetches a value dynamically. The command string is stored with a ! prefix in the profiles file and executed via your shell each time the value is needed.
clerk config set clerk.key "op read 'op://Vault/Clerk/api-key'" --type=command --profile productionclerk config set clerk.key "op read 'op://Vault/Clerk Production/api-key'" --type=command --profile productionclerk config set clerk.key "aws secretsmanager get-secret-value --secret-id clerk/api-key --query SecretString --output text" --type=command --profile productionclerk config set clerk.key "vault kv get -field=api_key secret/clerk/production" --type=command --profile productioncmd/clerk/
main.go # Entry point
internal/
api/
client.go # Base HTTP client with retry logic
users.go # Users API
organizations.go # Organizations API
sessions.go # Sessions API
apikeys.go # API Keys API
invitations.go # Invitations API
restrictions.go # Restrictions API (allowlist/blocklist)
emails.go # Email Addresses API
phones.go # Phone Numbers API
domains.go # Domains API
jwttemplates.go # JWT Templates API
instance.go # Instance API
jwks.go # JWKS API
m2m.go # M2M API (tokens + machines)
billing.go # Billing API (plans, subscriptions, statements)
protect.go # Protect Rules & Schema API
cmd/
root.go # Root command, global flags, prefix matching
args.go # Argument validation helpers
prefix.go # Prefix matching logic
init.go # Init/setup wizard
whoami.go # Whoami command
config.go # Config, profile, and alias commands
users.go # Users commands
organizations.go # Organizations commands
sessions.go # Sessions commands
apikeys.go # API Keys commands
invitations.go # Invitations commands
restrictions.go # Restrictions (allowlist/blocklist) commands
emails.go # User email addresses commands (under users)
phones.go # User phone numbers commands (under users)
domains.go # Domains commands
jwttemplates.go # JWT templates commands
instance.go # Instance commands
jwks.go # JWKS commands
m2m.go # M2M commands
billing.go # Billing commands
protect.go # Protect commands
config/
config.go # Configuration management (INI format)
aliases.go # Command aliases (JSON format)
output/
format.go # Output formatting (table/json/yaml)
colors.go # Colorized output helpers
ai/
ai.go # AI provider abstraction
openai.go # OpenAI provider
anthropic.go # Anthropic provider
mcp.go # MCP client (JSON-RPC over stdio)
mcp_config.go # MCP server configuration loader
tools.go # Tool manager (routes calls to MCP servers)
The CLI is built with Cobra and follows a modular architecture:
- cmd/ - Command definitions using Cobra. Each file defines a command group with its subcommands and flags.
- api/ - HTTP client layer. Each file implements API calls for a specific resource type. The base client handles authentication, retries with exponential backoff, and debug logging.
- config/ - Configuration management using INI-based profiles with support for command-type values that execute shell commands.
- output/ - Output formatting supporting table, JSON, and YAML formats with colorized terminal output.
- ai/ - Pluggable AI provider integration for natural language rule generation.
| Package | Purpose |
|---|---|
github.com/spf13/cobra |
CLI framework |
github.com/AlecAivazis/survey/v2 |
Interactive prompts |
github.com/fatih/color |
Terminal colors |
github.com/olekukonov/tablewriter |
Table output |
gopkg.in/yaml.v3 |
YAML output |
golang.org/x/term |
Terminal detection |
# Build
go build -o clerk ./cmd/clerk
# Run
./clerk --help
# Test commands
./clerk config path
./clerk config set clerk.key "test_key" --profile test
./clerk whoami
./clerk users list --output jsonReleases are automated via GitHub Actions. When you push a tag (e.g., v1.0.0), the workflow:
- Builds binaries for all platforms (darwin, linux, windows × amd64, arm64)
- Signs and notarizes macOS .pkg installers (if configured)
- Creates a GitHub Release with all artifacts
- Updates the Homebrew formula and Cask versions
git tag v1.0.0
git push origin v1.0.0| Channel | Type | Command |
|---|---|---|
| Homebrew (source) | Formula | brew install clerk/cli/clerk |
| Homebrew (signed pkg) | Cask | brew install --cask clerk/cli/clerk |
| NPM | Binary wrapper | npx clerk-cli |
| GitHub Releases | Direct download | Download from releases page |
To distribute signed and notarized macOS .pkg installers via Homebrew Cask, you need an Apple Developer account and certificates.
- Apple Developer Program membership ($99/year) - https://developer.apple.com/programs/enroll/
- Developer ID certificates:
- Developer ID Application (signs the binary)
- Developer ID Installer (signs the .pkg)
- App-Specific Password for notarization - generate at https://appleid.apple.com
Add these secrets in your repository settings (Settings → Secrets and variables → Actions → Secrets):
| Secret | Description |
|---|---|
APPLE_DEVELOPER_ID_APPLICATION_P12 |
Base64-encoded .p12 of Developer ID Application cert |
APPLE_DEVELOPER_ID_INSTALLER_P12 |
Base64-encoded .p12 of Developer ID Installer cert |
APPLE_CERTIFICATE_PASSWORD |
Password used when exporting the .p12 files |
APPLE_ID |
Your Apple ID email |
APPLE_APP_SPECIFIC_PASSWORD |
App-specific password for notarization |
APPLE_TEAM_ID |
Your 10-character Apple Team ID |
APPLE_DEVELOPER_NAME |
Developer name as shown in certificate (e.g., "Your Name" or "Your Company, Inc.") |
Add this variable (Settings → Secrets and variables → Actions → Variables):
| Variable | Value |
|---|---|
MACOS_SIGNING_ENABLED |
true |
- Open Keychain Access on your Mac
- Find your Developer ID Application certificate
- Right-click → Export → Save as .p12 file with a password
- Repeat for Developer ID Installer certificate
- Run the helper script to get base64-encoded values:
./scripts/export-certs-for-github.shThe release workflow includes a sign-macos job that:
- Runs on
macos-latest(required for codesign/notarytool) - Imports certificates into a temporary keychain
- Signs the Go binary with
codesign(hardened runtime) - Builds a .pkg installer with
pkgbuild - Signs the .pkg with
productsign - Submits to Apple for notarization via
notarytool - Staples the notarization ticket to the .pkg
The signed .pkg files are uploaded to GitHub Releases alongside the unsigned binaries.
The Casks/clerk.rb file defines the Homebrew Cask that installs the signed .pkg:
# Add the tap
brew tap clerk/cli https://github.com/clerk/cli
# Install via Cask (uses signed .pkg)
brew install --cask clerk/cli/clerk
# Or install via Formula (builds from source)
brew install clerk/cli/clerkNotarization fails: Check that your Apple ID has accepted the latest developer agreements at https://developer.apple.com
Certificate not found: Ensure the certificate names match exactly. Run security find-identity -v -p codesigning to list available certificates.
Gatekeeper blocks the binary: The binary must be signed with hardened runtime (--options runtime) and successfully notarized.