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 logout

Sessions are stored at ~/.twosignal/session.json and shared with the TUI.

Configuration

The CLI uses two local files for configuration and session state:

FilePurposeContents
~/.twosignal/config.jsonPersistent configurationapi_url — the 2Signal API endpoint
~/.twosignal/session.jsonAuthentication sessionAccess 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

VariableDescriptionDefault
TWOSIGNAL_URLOverrides api_url from config filehttps://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:

FlagDescription
--helpShow help for any command or subcommand
--jsonOutput 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 --help

Commands

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> -y

Datasets

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> -y

API 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> -y

Usage

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 ago

Add --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:

ErrorCauseFix
Authentication expiredBoth access and refresh tokens have expiredRun twosignal login again
Project not foundInvalid project ID or you don't have accessCheck the ID with twosignal projects list
Rate limitedToo many API requests in a short windowWait a few seconds and retry
Connection refusedCannot reach the API serverCheck your --url or TWOSIGNAL_URL setting
Permission deniedYour role does not allow this actionContact 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
fi

CI/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
fi

Create 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.production

Monitor 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.com

This 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.

Have questions? Join our community!

Connect with other developers and the 2Signal team.

Join Discord