CLI & Scriptability API
Updated April 25, 2026
The crystl CLI lets you control Crystl from any terminal. List gems, approve permissions, read terminal output, and script multi-agent workflows — all without touching the GUI.
Setup
After installing Crystl, the CLI binary is inside the app bundle. Create an alias:
alias crystl='/Users/$(whoami)/Applications/Crystl.app/Contents/MacOS/CrystlCLI'
Or add it to your .zshrc for permanent access. The CLI automatically reads the auth token from ~/.crystl-bridge-token — no configuration needed.
Requires Crystl.app to be running. The CLI talks to Crystl’s local HTTP bridge.
Commands
status
Overview of all gems, shards, and running agents. This is the default command.
crystl status
crystl status --json
gems
List all open gems with their shards and agent status.
crystl gems
crystl gems --json
open
Open a project directory as a new gem.
crystl open ~/Projects/myapp
crystl open .
close
Close a gem by name or UUID.
crystl close myapp
shards
List shards in a gem.
crystl shards
crystl shards --gem myapp
send
Send text to a terminal shard. Like typing into the terminal.
crystl send "git status"
crystl send --gem myapp "claude 'fix the tests'"
crystl send --gem myapp --shard opal "ls -la"
screen
Dump the terminal screen content. See what an agent is doing without switching tabs.
crystl screen
crystl screen --gem myapp
crystl screen --gem myapp --shard opal
pending
List pending permission requests.
crystl pending
approve / deny
Approve or deny a pending permission request by ID.
crystl pending # see request IDs
crystl approve 1 # approve request #1
crystl deny 2 # deny request #2
token
Print the current bearer token for debugging.
crystl token
Scripting Examples
Monitor an agent
# What is the agent doing right now?
crystl screen --gem myapp
# Poll every 5 seconds
watch -n5 crystl screen --gem myapp
Approve from another terminal
crystl pending # see what's waiting
crystl approve 1 # approve it
Launch parallel agents
crystl open ~/Projects/frontend
crystl open ~/Projects/backend
crystl send --gem frontend "claude 'update the API client'"
crystl send --gem backend "claude 'add the new endpoint'"
JSON for scripting
crystl gems --json | jq '.gems[].name'
crystl pending --json | jq '.pending | length'
HTTP API
The CLI wraps a local HTTP API at http://127.0.0.1:19280/api/v1/. You can call it directly with curl:
TOKEN=$(head -1 ~/.crystl-bridge-token)
# List gems
curl -s -H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:19280/api/v1/gems | jq
# Send a command
GEM_ID="..." # from gems response
SHARD_ID="..." # from gems response
curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"text":"ls\r"}' \
"http://127.0.0.1:19280/api/v1/gems/$GEM_ID/shards/$SHARD_ID/send"
# Subscribe to real-time events (SSE)
curl -N -H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:19280/api/v1/events
Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/api/v1/gems | GET | List open gems |
/api/v1/gems | POST | Open a gem |
/api/v1/gems/:id | GET | Get gem details |
/api/v1/gems/:id | DELETE | Close a gem |
/api/v1/gems/:id/shards/:sid/send | POST | Send text to terminal |
/api/v1/gems/:id/shards/:sid/screen | GET | Get screen content |
/api/v1/pending | GET | List pending permissions |
/api/v1/pending/:id/decide | POST | Approve or deny |
/api/v1/history | GET | Recent decisions |
/api/v1/notifications | GET | Recent notifications |
/api/v1/events | GET | SSE event stream |
All endpoints require Authorization: Bearer <token> header.
Security
- Auth: Every request requires a bearer token read from
~/.crystl-bridge-token(0600 permissions, regenerated each launch) - Remote /send disabled: The
sendendpoint only works from localhost. Remote connections (Tailscale, relay) cannot send terminal input. - Rate limited: 100 requests per second per client IP