CLI
The 2Signal CLI lets you manage traces, evaluators, datasets, API keys, and more directly from your terminal. Ideal for scripting, CI/CD, and quick lookups.
Installation
pip install twosignal[cli]Authentication
# log in (prompts for email and password)
twosignal login
# pass credentials inline
twosignal login -e you@example.com -p yourpassword
# connect to a self-hosted instance
twosignal login --url https://your-instance.example.com
# check your session
twosignal whoami
# log out
twosignal logoutSessions are stored at ~/.twosignal/session.json and shared with the TUI.
Configuration
The CLI uses two local files for configuration and session state:
| File | Purpose | Contents |
|---|---|---|
~/.twosignal/config.json | Persistent configuration | api_url — the 2Signal API endpoint |
~/.twosignal/session.json | Authentication session | Access token, refresh token, expiry timestamp |
The config file is created on first twosignal login. You can also create it manually:
{
"api_url": "https://app.twosignal.dev"
}Environment Variables
| Variable | Description | Default |
|---|---|---|
TWOSIGNAL_URL | Overrides api_url from config file | https://app.twosignal.dev |
Priority order: --url flag > TWOSIGNAL_URL env var > ~/.twosignal/config.json > default.
Session Management
When you log in, the CLI stores an access token and a refresh token. The access token is short-lived; when it expires, the CLI automatically refreshes it using the refresh token. This happens transparently — you do not need to re-login unless the session has been inactive long enough for the refresh token itself to expire.
Sessions are shared between the CLI and TUI. Logging in via either tool authenticates both.
Global Options
These options are available on every command:
| Flag | Description |
|---|---|
--help | Show help for any command or subcommand |
--json | Output results as JSON instead of a formatted table |
--url <url> | Override the API endpoint for this command |
# get help for any command
twosignal traces --help
twosignal evaluators create --helpCommands
Organizations
twosignal orgs list
twosignal orgs create "My Org"Projects
twosignal projects list --org <org-id>
twosignal projects create "My Project" --org <org-id>Traces
twosignal traces list --project <project-id>
twosignal traces list --project <id> --status ERROR
twosignal traces list --project <id> --search "agent-name"
twosignal traces get <trace-id> --project <project-id>Evaluators
twosignal evaluators list --project <project-id>
twosignal evaluators create --project <id> -n "Has JSON" --type JSON_SCHEMA
twosignal evaluators toggle <id> --project <id> --enable
twosignal evaluators delete <id> --project <id> -yDatasets
twosignal datasets list --project <project-id>
twosignal datasets create --project <id> -n "Test Cases"
twosignal datasets get <dataset-id> --project <id>
twosignal datasets add-item <dataset-id> --project <id> --input '{"prompt": "Hi"}'
twosignal datasets delete <id> --project <id> -yAPI Keys
twosignal api-keys list --project <project-id>
twosignal api-keys create --project <id> -n "CI Pipeline"
twosignal api-keys revoke <key-id> --project <id> -yUsage
twosignal usage --org <org-id>Output Formats
By default, list commands output human-readable tables:
$ twosignal traces list --project abc123
ID Status Duration Cost Created
────────────────────────────────────────────────────────────────────────────
a1b2c3d4-e5f6-7890-abcd-ef1234567890 OK 1.2s $0.003 2 min ago
f9e8d7c6-b5a4-3210-fedc-ba0987654321 ERROR 4.8s $0.012 5 min ago
11223344-5566-7788-99aa-bbccddeeff00 OK 0.8s $0.001 12 min agoAdd --json for machine-readable output:
$ twosignal traces list --project abc123 --json
[
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "OK",
"duration_ms": 1200,
"cost_usd": 0.003,
"created_at": "2026-03-14T10:30:00Z"
},
...
]Error Handling
Common errors and what they mean:
| Error | Cause | Fix |
|---|---|---|
Authentication expired | Both access and refresh tokens have expired | Run twosignal login again |
Project not found | Invalid project ID or you don't have access | Check the ID with twosignal projects list |
Rate limited | Too many API requests in a short window | Wait a few seconds and retry |
Connection refused | Cannot reach the API server | Check your --url or TWOSIGNAL_URL setting |
Permission denied | Your role does not allow this action | Contact your organization admin |
Scripting
# check for error traces in CI
ERROR_COUNT=$(twosignal traces list --project $PROJECT_ID --status ERROR --json | \
python -c "import sys,json; print(len(json.load(sys.stdin)))")
if [ "$ERROR_COUNT" -gt "0" ]; then
echo "Found $ERROR_COUNT error traces"
exit 1
fiCI/CD Integration
The CLI is designed for use in CI/CD pipelines. Here are common patterns:
Check evaluator scores after deployment
# fail the pipeline if any evaluator scored below 0.5
SCORES=$(twosignal traces list --project $PROJECT_ID --json | \
python -c "
import sys, json
traces = json.load(sys.stdin)
low = [t for t in traces if any(s.get('score', 1) < 0.5 for s in t.get('scores', []))]
print(len(low))
")
if [ "$SCORES" -gt "0" ]; then
echo "Found $SCORES traces with low evaluator scores"
exit 1
fiCreate API keys for deployments
# create a deployment-specific API key
API_KEY=$(twosignal api-keys create --project $PROJECT_ID \
-n "deploy-$(date +%Y%m%d-%H%M%S)" --json | \
python -c "import sys,json; print(json.load(sys.stdin)['key'])")
# pass to your application
echo "TWOSIGNAL_API_KEY=$API_KEY" >> .env.productionMonitor usage in CI
# check if usage is approaching the plan limit
twosignal usage --org $ORG_ID --json | \
python -c "
import sys, json
usage = json.load(sys.stdin)
pct = usage['traces_used'] / usage['traces_limit'] * 100
print(f'Usage: {pct:.1f}%')
if pct > 90:
print('WARNING: approaching trace limit')
exit(1)
"Self-Hosted Instances
If you are running a self-hosted 2Signal instance, use the --url flag on login to point the CLI at your server:
twosignal login --url https://twosignal.internal.company.comThis saves the URL to ~/.twosignal/config.json so subsequent commands use it automatically. You can also set TWOSIGNAL_URL in your shell profile or CI environment to avoid passing the flag every time.