Alloy CLI Reference
Alloy is a headless, API-first project management tool. The CLI (alloy) lets you
manage organizations, projects, tickets, sprints, time entries, and more from
your terminal. For the HTTP API, see the API Reference. New to
Alloy? Start with the Getting Started guide.
Global Flags
Every command accepts:
| Flag | Env Var | Default | Description |
|---|---|---|---|
--format <json|table|plain> | ALLOY_FORMAT | auto-detect | Output format |
--api-url <URL> | ALLOY_API_URL | http://localhost:3000 | API server URL |
Output Formats
The --format flag controls how results are displayed:
| Format | Description |
|---|---|
json | Machine-readable JSON (pretty-printed) |
table | Human-readable columns with headers |
plain | Minimal output suitable for scripting |
TTY auto-detection: When output goes to an interactive terminal, format
defaults to table. When piped or redirected, it defaults to json. Override
with --format or the ALLOY_FORMAT environment variable.
The NO_COLOR environment variable suppresses ANSI color codes when set to any
non-empty value.
Commands
health
Check API server connectivity and status.
alloy health [--format <FORMAT>]
| Flag | Description |
|---|---|
--format | Output format (json, table, plain) |
Examples:
# Quick status check
alloy health
# Machine-readable health check for monitoring
alloy health --format json
migrate
Run database migrations against the configured database.
alloy migrate
Uses ALLOY_DATABASE_URL (default: sqlite://alloy.db). Migrations are
embedded in the binary — no external migration files needed at runtime.
| Env Var | Default | Description |
|---|---|---|
ALLOY_DATABASE_URL | sqlite://alloy.db | Database connection URL |
Examples:
# Run migrations against default SQLite database
alloy migrate
# Run migrations against PostgreSQL
ALLOY_DATABASE_URL=postgres://localhost/alloy alloy migrate
serve
Start the Alloy API server.
alloy serve [--db <URL>] [--port <PORT>]
| Flag | Env Var | Default | Description |
|---|---|---|---|
--db <URL> | ALLOY_DATABASE_URL | sqlite://alloy.db | Database URL |
--port <PORT> | PORT | 3000 | Listen port |
Examples:
# Start with defaults (SQLite on port 3000)
alloy serve
# Start with PostgreSQL on a custom port
alloy serve --db postgres://localhost/alloy --port 8080
auth
Authenticate with the Alloy API and manage API keys.
auth login
Log in with email and password. Stores credentials locally.
alloy auth login --email <EMAIL> --password <PASSWORD>
| Flag | Description |
|---|---|
--email <EMAIL> | Account email address |
--password <PASSWORD> | Account password |
Credentials are saved to ~/.config/alloy/credentials.toml and include the
access token, refresh token, user ID, and email. The CLI automatically refreshes
expired tokens on 401 responses.
Examples:
# Log in and save credentials
alloy auth login --email admin@example.com --password s3cret
# Log in and capture just the user ID
alloy auth login --email admin@example.com --password s3cret --format plain
auth token
Display the currently stored authentication token (masked for security).
alloy auth token
Shows the first 12 and last 4 characters of the token with the middle masked.
Examples:
# Check which account is logged in
alloy auth token
# Get token info as JSON
alloy auth token --format json
auth api-key create
Create a new API key with optional scope and project restrictions.
alloy auth api-key create --name <NAME> [--scopes <SCOPES>] [--projects <PROJECT_IDS>]
| Flag | Default | Description |
|---|---|---|
--name <NAME> | (required) | Human-readable key name |
--scopes <SCOPES> | read,write | Comma-separated: read, write, admin |
--projects <IDS> | all projects | Comma-separated project UUIDs to restrict access |
API keys are prefixed alloy_live_ (production) or alloy_test_ (testing).
The full key is shown only once at creation time.
Scopes:
read— Read-only access to resourceswrite— Create, update, and delete resourcesadmin— Full access including user and org management
Examples:
# Create a read-write key for CI
alloy auth api-key create --name "CI Pipeline"
# Create a read-only key restricted to one project
alloy auth api-key create --name "Dashboard" --scopes read --projects 550e8400-e29b-41d4-a716-446655440000
# Create an admin key and capture it for scripting
alloy auth api-key create --name "Admin Script" --scopes read,write,admin --format plain
auth api-key list
List all API keys for the current user.
alloy auth api-key list
Examples:
# View all API keys
alloy auth api-key list
# List keys as JSON for automation
alloy auth api-key list --format json
auth api-key revoke
Revoke an API key by its ID.
alloy auth api-key revoke <ID>
Examples:
# Revoke a specific key
alloy auth api-key revoke 550e8400-e29b-41d4-a716-446655440000
# List keys then revoke one
alloy auth api-key list --format json | jq '.[0].id' -r | xargs alloy auth api-key revoke
org
Manage organizations (tenants).
org create
alloy org create --name <NAME> --slug <SLUG>
| Flag | Description |
|---|---|
--name <NAME> | Organization display name |
--slug <SLUG> | URL-friendly identifier (e.g. acme-corp) |
Examples:
# Create a new organization
alloy org create --name "Acme Corp" --slug acme-corp
# Create and capture org ID
ORG_ID=$(alloy org create --name "Acme Corp" --slug acme-corp --format json | jq -r '.id')
org list
alloy org list
Examples:
# List all organizations
alloy org list
# Get org IDs for scripting
alloy org list --format json | jq '.[].id'
org switch
Set the active organization for subsequent commands.
alloy org switch <ID>
Examples:
# Switch active organization
alloy org switch 550e8400-e29b-41d4-a716-446655440000
# Switch to the first org
alloy org switch $(alloy org list --format json | jq -r '.data[0].id')
project
Manage projects within an organization.
project create
alloy project create --org-id <ORG_ID> --key <KEY> --name <NAME> [--description <DESC>] [--team-id <TEAM_ID>]
| Flag | Description |
|---|---|
--org-id <ORG_ID> | Organization UUID |
--key <KEY> | Short project key, 1-10 chars (e.g. BACK, MOBILE) |
--name <NAME> | Project display name |
--description <DESC> | Optional description |
--team-id <TEAM_ID> | Optional team UUID |
Examples:
# Create a backend project
alloy project create --org-id $ORG_ID --key BACK --name "Backend Services"
# Create with description
alloy project create --org-id $ORG_ID --key WEB --name "Web Frontend" --description "React SPA and design system"
project list
alloy project list --org-id <ORG_ID> [--cursor <CURSOR>] [--limit <LIMIT>]
| Flag | Default | Description |
|---|---|---|
--org-id <ORG_ID> | (required) | Organization UUID |
--cursor <CURSOR> | — | Pagination cursor from previous response |
--limit <LIMIT> | 20 | Results per page |
Examples:
# List all projects in an org
alloy project list --org-id $ORG_ID
# Page through results
alloy project list --org-id $ORG_ID --limit 5 --cursor "next_cursor_value"
project get
alloy project get <ID>
Examples:
# Get project details
alloy project get 550e8400-e29b-41d4-a716-446655440000
# Get project as JSON
alloy project get $PROJECT_ID --format json
project update
alloy project update <ID> [--name <NAME>] [--description <DESC>] [--team-id <ID|none>] [--cap-type <capex|opex|none>] [--phase <preliminary|app-development|post-implementation|none>] [--cost-center-id <ID|none>] [--amortization-months <INT|none>]
Pass none to any optional field to unset it.
Examples:
# Rename a project
alloy project update $PROJECT_ID --name "Backend API v2"
# Set capitalization type for time tracking
alloy project update $PROJECT_ID --cap-type capex --phase app-development --amortization-months 36
project delete
alloy project delete <ID>
Examples:
# Delete a project
alloy project delete $PROJECT_ID
# Delete by key lookup
alloy project delete $(alloy project get $PROJECT_ID --format json | jq -r '.id')
project use
Set a default project context. This enables bare ticket number resolution
(e.g., alloy ticket get 42 resolves to PROJ-42).
alloy project use <KEY_OR_ID>
Accepts either a project key (like BACK) or a UUID. The project ID and key are
saved to ~/.config/alloy/credentials.toml.
Examples:
# Set default project by key
alloy project use BACK
# Set default project by UUID
alloy project use 550e8400-e29b-41d4-a716-446655440000
# Now bare numbers work everywhere
alloy ticket get 42 # resolves to BACK-42
alloy ticket list # lists tickets in BACK
ticket
Create, list, update, and manage tickets. Supports smart ID resolution.
Smart ID Resolution: Ticket commands accept three reference formats:
| Format | Example | Resolution |
|---|---|---|
| UUID | 550e8400-... | Used directly |
| KEY-NUMBER | BACK-42 | Resolved via API (/api/v1/tickets/resolve?ref=BACK-42) |
| Bare number | 42 | Requires project context; resolves as {PROJECT_KEY}-42 |
Set project context with alloy project use <KEY> to enable bare number references.
ticket create
alloy ticket create [--project <PROJECT_ID>] [--title <TITLE>] [--description <DESC>] [--priority <PRIORITY>] [--status <STATUS>] [--assignee-id <UUID>] [--reporter-id <UUID>]
| Flag | Default | Description |
|---|---|---|
--project <ID> | credentials project | Project UUID (prompted interactively if omitted) |
--title <TITLE> | — | Ticket title (prompted interactively if omitted) |
--description <DESC> | — | Detailed description |
--priority <PRIORITY> | medium | none, low, medium, high, urgent |
--status <STATUS> | backlog | backlog, todo, in_progress, in_review, done, cancelled |
--assignee-id <UUID> | — | Assignee user UUID (fuzzy selector in interactive mode) |
--reporter-id <UUID> | logged-in user | Reporter user UUID |
In interactive mode (TTY), missing fields are prompted with fuzzy selectors for projects, users, and priorities.
Examples:
# Create a ticket interactively (prompts for missing fields)
alloy ticket create
# Create a ticket non-interactively
alloy ticket create --project $PROJECT_ID --title "Fix login timeout" --priority high --status todo
# Create and capture the ticket ID
TICKET_ID=$(alloy ticket create --project $PROJECT_ID --title "Add caching" --format json | jq -r '.id')
ticket list
alloy ticket list [--project <PROJECT_ID>] [--status <STATUS>] [--priority <PRIORITY>] [--assignee-id <UUID>] [--cursor <CURSOR>] [--limit <LIMIT>]
| Flag | Default | Description |
|---|---|---|
--project <ID> | credentials project | Project UUID |
--status <STATUS> | — | Filter by status (comma-separated) |
--priority <PRIORITY> | — | Filter by priority |
--assignee-id <UUID> | — | Filter by assignee |
--cursor <CURSOR> | — | Pagination cursor |
--limit <LIMIT> | 20 | Results per page |
Examples:
# List tickets in the default project
alloy ticket list
# Filter by status
alloy ticket list --status todo,in_progress
# List high-priority tickets as JSON
alloy ticket list --priority high --format json
# Page through results
alloy ticket list --limit 10 --cursor "next_cursor_value"
ticket get
alloy ticket get <ID>
Accepts UUID, KEY-NUMBER, or bare number.
Examples:
# Get by project-qualified reference
alloy ticket get BACK-42
# Get by bare number (uses default project)
alloy ticket get 42
# Get by UUID
alloy ticket get 550e8400-e29b-41d4-a716-446655440000
ticket update
alloy ticket update <ID> [--title <TITLE>] [--description <DESC>] [--status <STATUS>] [--priority <PRIORITY>] [--assignee-id <UUID|none>] [--add-label <LABEL_ID>] [--remove-label <LABEL_ID>]
In interactive mode with no flags, a multi-select dialog prompts for which fields to update with fuzzy selectors for users and labels.
Examples:
# Move a ticket to in-progress
alloy ticket update BACK-42 --status in_progress
# Assign and add a label
alloy ticket update 42 --assignee-id $USER_ID --add-label $LABEL_ID
# Interactive update (prompts for fields to change)
alloy ticket update BACK-42
ticket batch-update
alloy ticket batch-update --ticket-ids <UUID,UUID,...> [--title <TITLE>] [--description <DESC>] [--status <STATUS>] [--priority <PRIORITY>] [--assignee-id <UUID>] [--sprint-id <UUID>]
Apply the same field updates to multiple tickets at once. At least one field flag must be provided.
| Flag | Description |
|---|---|
--ticket-ids <IDs> | Comma-separated ticket UUIDs |
--title <TITLE> | New title for all tickets |
--description <DESC> | New description for all tickets |
--status <STATUS> | New status for all tickets |
--priority <PRIORITY> | New priority (none, low, medium, high, urgent) |
--assignee-id <UUID> | Assignee UUID for all tickets |
--sprint-id <UUID> | Sprint UUID for all tickets |
Examples:
# Set all tickets to high priority
alloy ticket batch-update --ticket-ids "$ID1,$ID2" --priority high
# Move multiple tickets to Done
alloy ticket batch-update --ticket-ids "$ID1,$ID2" --status Done
ticket batch-transition
alloy ticket batch-transition --ticket-ids <UUID,UUID,...> --to-status <STATUS>
Transition multiple tickets to the same target status. Each ticket is validated against its project’s workflow. Reports successes and failures individually.
| Flag | Description |
|---|---|
--ticket-ids <IDs> | Comma-separated ticket UUIDs |
--to-status <STATUS> | Target status to transition all tickets to |
Examples:
# Transition all sprint tickets to Done
alloy ticket batch-transition --ticket-ids "$ID1,$ID2" --to-status Done
comment
Add and manage comments on tickets.
comment add
alloy comment add --ticket <TICKET_REF> --body <BODY> --author-id <UUID> [--parent-id <COMMENT_ID>]
| Flag | Description |
|---|---|
--ticket <REF> | Ticket reference (UUID, KEY-NUMBER, or bare number) |
--body <BODY> | Comment text |
--author-id <UUID> | Author’s user UUID |
--parent-id <ID> | Parent comment UUID for threading |
Examples:
# Add a comment to a ticket
alloy comment add --ticket BACK-42 --body "Deployed to staging" --author-id $USER_ID
# Reply to an existing comment (threaded)
alloy comment add --ticket 42 --body "Confirmed fixed" --author-id $USER_ID --parent-id $PARENT_COMMENT_ID
comment list
alloy comment list --ticket <TICKET_REF> [--cursor <CURSOR>] [--limit <LIMIT>]
Examples:
# List comments on a ticket
alloy comment list --ticket BACK-42
# Get comments as JSON
alloy comment list --ticket 42 --format json
comment get
alloy comment get <ID>
Examples:
# Get a specific comment
alloy comment get $COMMENT_ID
# Get comment as JSON
alloy comment get $COMMENT_ID --format json
comment update
alloy comment update <ID> --body <BODY>
Examples:
# Edit a comment
alloy comment update $COMMENT_ID --body "Updated: deployed to production"
# Update and verify
alloy comment update $COMMENT_ID --body "Fixed in v2.1" && alloy comment get $COMMENT_ID
comment delete
alloy comment delete <ID>
Examples:
# Delete a comment
alloy comment delete $COMMENT_ID
label
Manage labels for organizing tickets.
label create
alloy label create --org <ORG_ID> --name <NAME> --color <COLOR>
| Flag | Description |
|---|---|
--org <ORG_ID> | Organization UUID |
--name <NAME> | Label name (e.g. bug, feature) |
--color <COLOR> | Hex color code (e.g. #FF0000) |
Examples:
# Create a bug label
alloy label create --org $ORG_ID --name bug --color "#FF0000"
# Create a feature label
alloy label create --org $ORG_ID --name feature --color "#00FF00"
label list
alloy label list --org <ORG_ID> [--cursor <CURSOR>] [--limit <LIMIT>]
Examples:
# List all labels
alloy label list --org $ORG_ID
# Get labels as JSON
alloy label list --org $ORG_ID --format json
label get
alloy label get <ID>
Examples:
# Get label details
alloy label get $LABEL_ID
label update
alloy label update <ID> [--name <NAME>] [--color <COLOR>]
Examples:
# Change label color
alloy label update $LABEL_ID --color "#0000FF"
# Rename a label
alloy label update $LABEL_ID --name "critical-bug"
label delete
alloy label delete <ID>
Examples:
# Delete a label
alloy label delete $LABEL_ID
workflow
Define custom workflows with statuses and allowed transitions.
workflow create
alloy workflow create --org-id <ORG_ID> --name <NAME> --statuses <JSON> --transitions <JSON>
| Flag | Description |
|---|---|
--org-id <ORG_ID> | Organization UUID |
--name <NAME> | Workflow name |
--statuses <JSON> | JSON array of status definitions |
--transitions <JSON> | JSON array of allowed transitions |
Examples:
# Create a simple workflow
alloy workflow create --org-id $ORG_ID --name "Standard" \
--statuses '[{"name":"Backlog","category":"todo"},{"name":"In Progress","category":"in_progress"},{"name":"Done","category":"done"}]' \
--transitions '[{"from":"Backlog","to":"In Progress"},{"from":"In Progress","to":"Done"}]'
# Create a workflow with review step
alloy workflow create --org-id $ORG_ID --name "With Review" \
--statuses '[{"name":"Todo","category":"todo"},{"name":"Working","category":"in_progress"},{"name":"Review","category":"in_progress"},{"name":"Done","category":"done"}]' \
--transitions '[{"from":"Todo","to":"Working"},{"from":"Working","to":"Review"},{"from":"Review","to":"Done"},{"from":"Review","to":"Working"}]'
workflow list
alloy workflow list --org-id <ORG_ID> [--cursor <CURSOR>] [--limit <LIMIT>]
Examples:
# List workflows
alloy workflow list --org-id $ORG_ID
# Get workflow details as JSON
alloy workflow list --org-id $ORG_ID --format json
workflow show
alloy workflow show <ID>
Examples:
# Show workflow with statuses and transitions
alloy workflow show $WORKFLOW_ID
# Get workflow as JSON for editing
alloy workflow show $WORKFLOW_ID --format json
workflow update
alloy workflow update <ID> [--name <NAME>] [--statuses <JSON>] [--transitions <JSON>]
Examples:
# Rename a workflow
alloy workflow update $WORKFLOW_ID --name "Engineering Flow"
# Add a new status and transition
alloy workflow update $WORKFLOW_ID \
--statuses '[{"name":"Todo","category":"todo"},{"name":"In Progress","category":"in_progress"},{"name":"QA","category":"in_progress"},{"name":"Done","category":"done"}]' \
--transitions '[{"from":"Todo","to":"In Progress"},{"from":"In Progress","to":"QA"},{"from":"QA","to":"Done"}]'
workflow delete
alloy workflow delete <ID>
Examples:
# Delete a workflow
alloy workflow delete $WORKFLOW_ID
tag
Manage key-value tags on entities (projects, tickets, users, teams, time entries).
tag set
Set one or more key-value tags on an entity (upsert — creates or updates).
alloy tag set --org <ORG_ID> --entity-type <TYPE> --entity-id <ID> --tag <KEY=VALUE>...
| Flag | Description |
|---|---|
--org <ORG_ID> | Organization UUID |
--entity-type <TYPE> | Entity type: project, ticket, user, team, time_entry |
--entity-id <ID> | Entity UUID |
--tag <KEY=VALUE> | Tag key-value pair (repeatable) |
Examples:
# Tag a project with environment and team
alloy tag set --org $ORG_ID --entity-type project --entity-id $PROJECT_ID \
--tag env=production --tag team=backend
# Tag a ticket with a priority label
alloy tag set --org $ORG_ID --entity-type ticket --entity-id $TICKET_ID --tag sprint=12
tag get
Get all tags for an entity.
alloy tag get --org <ORG_ID> --entity-type <TYPE> --entity-id <ID>
| Flag | Description |
|---|---|
--org <ORG_ID> | Organization UUID |
--entity-type <TYPE> | Entity type |
--entity-id <ID> | Entity UUID |
Examples:
# Get tags for a project
alloy tag get --org $ORG_ID --entity-type project --entity-id $PROJECT_ID
# Get tags as JSON
alloy tag get --org $ORG_ID --entity-type ticket --entity-id $TICKET_ID --format json
tag delete
Delete a tag by key from an entity.
alloy tag delete --org <ORG_ID> --entity-type <TYPE> --entity-id <ID> --key <KEY>
| Flag | Description |
|---|---|
--org <ORG_ID> | Organization UUID |
--entity-type <TYPE> | Entity type |
--entity-id <ID> | Entity UUID |
--key <KEY> | Tag key to delete |
Examples:
# Remove the "env" tag from a project
alloy tag delete --org $ORG_ID --entity-type project --entity-id $PROJECT_ID --key env
tag search
Search for entities by tag key-value pair.
alloy tag search --org <ORG_ID> --key <KEY> --value <VALUE> [--cursor <CURSOR>] [--limit <LIMIT>]
| Flag | Default | Description |
|---|---|---|
--org <ORG_ID> | (required) | Organization UUID |
--key <KEY> | (required) | Tag key to search for |
--value <VALUE> | (required) | Tag value to search for |
--cursor <CURSOR> | — | Pagination cursor |
--limit <LIMIT> | 20 | Results per page |
Examples:
# Find all entities tagged env=production
alloy tag search --org $ORG_ID --key env --value production
# Search with pagination
alloy tag search --org $ORG_ID --key team --value backend --limit 10 --format json
team
Manage teams within an organization.
team create
alloy team create --name <NAME> [--description <DESC>]
| Flag | Description |
|---|---|
--name <NAME> | Team name |
--description <DESC> | Optional team description |
Examples:
# Create a team
alloy team create --name "Backend"
# Create with description
alloy team create --name "Platform" --description "Infrastructure and DevOps"
team list
alloy team list
Examples:
# List all teams
alloy team list
# Get teams as JSON
alloy team list --format json
team delete
alloy team delete <ID> [--cascade] [--dry-run]
| Flag | Description |
|---|---|
--cascade | Cascade-delete all dependents (members, projects) |
--dry-run | Preview what would be deleted (requires --cascade) |
Examples:
# Delete a team
alloy team delete $TEAM_ID
# Preview cascade delete
alloy team delete $TEAM_ID --cascade --dry-run
# Cascade delete team and all dependents
alloy team delete $TEAM_ID --cascade
project member
Manage project membership. Nested under project.
project member add
alloy project member add --project-id <PROJECT_ID> --user-id <USER_ID>
| Flag | Description |
|---|---|
--project-id <ID> | Project UUID |
--user-id <ID> | User UUID to add |
Examples:
# Add a user to a project
alloy project member add --project-id $PROJECT_ID --user-id $USER_ID
project member remove
alloy project member remove --project-id <PROJECT_ID> --user-id <USER_ID>
| Flag | Description |
|---|---|
--project-id <ID> | Project UUID |
--user-id <ID> | User UUID to remove |
Examples:
# Remove a user from a project
alloy project member remove --project-id $PROJECT_ID --user-id $USER_ID
project member list
alloy project member list --project-id <PROJECT_ID>
| Flag | Description |
|---|---|
--project-id <ID> | Project UUID |
Examples:
# List project members
alloy project member list --project-id $PROJECT_ID
# Get members as JSON
alloy project member list --project-id $PROJECT_ID --format json
report
Generate capitalization and finance reports.
report capitalization
Generate a capitalization report as JSON with optional grouping and filters.
alloy report capitalization --period <YYYY-MM> [--group-by <GROUP>] [--include-users] [--include-budget] [--team-id <ID>] [--user-id <ID>] [--cost-center-id <ID>] [--activity-type <TYPE>] [--tag <KEY:VALUE>]
| Flag | Default | Description |
|---|---|---|
--period <YYYY-MM> | (required) | Reporting month |
--group-by <GROUP> | — | Group by team or user |
--include-users | false | Include individual user breakdowns |
--include-budget | false | Include budget data |
--team-id <ID> | — | Filter by team UUID |
--user-id <ID> | — | Filter by user UUID |
--cost-center-id <ID> | — | Filter by cost center UUID |
--activity-type <TYPE> | — | Filter by activity type |
--tag <KEY:VALUE> | — | Tag filter (repeatable) |
Examples:
# Basic capitalization report
alloy report capitalization --period 2026-03
# Report grouped by team with user breakdowns
alloy report capitalization --period 2026-03 --group-by team --include-users
# Filtered report
alloy report capitalization --period 2026-03 --team-id $TEAM_ID --activity-type development
report export
Export a capitalization report as CSV to stdout.
alloy report export --period <YYYY-MM> [--team-id <ID>] [--user-id <ID>] [--cost-center-id <ID>] [--activity-type <TYPE>] [--tag <KEY:VALUE>]
| Flag | Default | Description |
|---|---|---|
--period <YYYY-MM> | (required) | Reporting month |
--team-id <ID> | — | Filter by team UUID |
--user-id <ID> | — | Filter by user UUID |
--cost-center-id <ID> | — | Filter by cost center UUID |
--activity-type <TYPE> | — | Filter by activity type |
--tag <KEY:VALUE> | — | Tag filter (repeatable) |
Examples:
# Export March report as CSV
alloy report export --period 2026-03
# Save CSV to file
alloy report export --period 2026-03 > march-2026.csv
# Export filtered by team
alloy report export --period 2026-03 --team-id $TEAM_ID
export
Export complete project data as portable JSON or SQLite. Uses human-readable keys (emails, project keys, label names) instead of UUIDs.
alloy export [--org <ORG_ID>] [--project <KEY>] [--export-format <FORMAT>] [--output <FILE>]
| Flag | Default | Description |
|---|---|---|
--org <ORG_ID> | stored org | Organization UUID (defaults to org from login) |
--project <KEY> | — | Filter to a single project by key |
--export-format <FORMAT> | json | Export format: json or sqlite |
-o, --output <FILE> | alloy-export.db | Output file path (for sqlite format) |
Examples:
# Export everything as JSON (uses stored org from login)
alloy export
# Export with explicit org ID
alloy export --org $ORG_ID
# Export a single project
alloy export --project PROJ
# Save to file
alloy export --project PROJ > proj-backup.json
# Export as SQLite database
alloy export --export-format sqlite --output alloy-export.db
import
Import data from an Alloy JSON export file, a Jira JSON export, or a Linear JSON export. Reads from a file path or stdin. Supports --dry-run to preview what would be imported without making changes. Use --from jira or --from linear to import from external tools.
alloy import [FILE] [--org <ORG_ID>] [--from <SOURCE>] [--dry-run]
| Argument/Flag | Default | Description |
|---|---|---|
[FILE] | stdin | Path to JSON export file (reads stdin if omitted) |
--org <ORG_ID> | stored org | Organization UUID (defaults to org from login) |
--from <SOURCE> | alloy | Source format: alloy (native), jira (Jira export), or linear (Linear export) |
--dry-run | — | Preview import without making changes |
Examples:
# Import from an Alloy export file
alloy import backup.json
# Preview what would be imported
alloy import backup.json --dry-run
# Import from stdin (e.g. pipe from export)
alloy export --project PROJ | alloy import
# Import with explicit org ID
alloy import backup.json --org $ORG_ID
# Import from a Jira JSON export
alloy import jira-export.json --from jira
# Preview a Jira import without making changes
alloy import jira-export.json --from jira --dry-run
# Import from a Linear JSON export
alloy import linear-export.json --from linear
# Preview a Linear import without making changes
alloy import linear-export.json --from linear --dry-run
Jira import mapping:
| Jira concept | Alloy concept | Notes |
|---|---|---|
| Projects | Projects | Key and name preserved |
| Issues | Tickets | Number extracted from issue key |
| Issue types | Labels | Mapped as type:<IssueType> labels |
| Priorities | Priorities | Blocker/Highest→Urgent, High/Major→High, etc. |
| Statuses | Workflow statuses | Grouped into a “Jira Import” workflow |
| Versions | Sprints | Released versions become Completed sprints |
| Components | Labels | Mapped to labels with a warning |
| Comments | Comments | Author and body preserved |
| Worklogs | Time entries | Duration converted from seconds to minutes |
| Labels | Labels | Preserved as-is |
| Links | — | Skipped with a warning |
| Custom fields | — | Skipped with a warning |
| Resolutions | — | Logged as warnings (status preserved) |
Linear import mapping:
| Linear concept | Alloy concept | Notes |
|---|---|---|
| Teams | Projects | Key and name preserved |
| Issues | Tickets | Number extracted from identifier |
| Priorities | Priorities | 1=Urgent, 2=High, 3=Medium, 4=Low, 0=None |
| States | Workflow statuses | Grouped into a “Linear Import” workflow |
| Cycles | Sprints | Completed cycles become Completed sprints |
| Labels | Labels | Color preserved from Linear |
| Comments | Comments | Author and body preserved |
| Users | Users | Email preserved; display name used |
| Projects | — | Skipped with a warning (teams used instead) |
| Relations | — | Skipped with a warning |
| Estimates | — | Skipped with a warning |
| Sub-issues | Tickets | Imported as top-level tickets with a warning |
board
Show the sprint board — tickets organized by workflow status columns.
alloy board <SPRINT_ID> [--format <FORMAT>]
| Argument/Flag | Description |
|---|---|
<SPRINT_ID> | Sprint UUID |
--format | Output format (json, table, plain) |
Table output shows the sprint header, then each status column with its ticket count and the tickets listed with priority, title, and assignee.
Examples:
# View the sprint board
alloy board $SPRINT_ID
# Get board as JSON for scripting
alloy board $SPRINT_ID --format json
# Pipe plain output for processing
alloy board $SPRINT_ID --format plain
burndown
Show sprint burndown chart data — daily progress with total, completed, and remaining ticket counts.
alloy burndown <SPRINT_ID> [--format <FORMAT>]
| Argument/Flag | Description |
|---|---|
<SPRINT_ID> | Sprint UUID |
--format | Output format (json, table, plain) |
Table output shows a dated table with total, completed, and remaining columns.
Examples:
# View burndown data
alloy burndown $SPRINT_ID
# Get burndown as JSON
alloy burndown $SPRINT_ID --format json
# Export for a spreadsheet
alloy burndown $SPRINT_ID --format plain > burndown.tsv
sprint
Manage sprints within projects. Sprints have a lifecycle: planning → active → completed.
Use alloy board <sprint-id> to view the sprint board and alloy burndown <sprint-id>
to view the burndown chart.
sprint create
alloy sprint create --project <PROJECT_ID> --name <NAME> --start-date <DATE> --end-date <DATE> [--goal <GOAL>]
| Flag | Description |
|---|---|
--project <ID> | Project UUID (fuzzy selector in interactive mode) |
--name <NAME> | Sprint name (e.g. Sprint 12) |
--start-date <DATE> | Start date (YYYY-MM-DD) |
--end-date <DATE> | End date (YYYY-MM-DD) |
--goal <GOAL> | Optional sprint goal |
Examples:
# Create a two-week sprint
alloy sprint create --project $PROJECT_ID --name "Sprint 12" \
--start-date 2026-03-25 --end-date 2026-04-08 \
--goal "Ship authentication and onboarding"
# Create a sprint and capture its ID
SPRINT_ID=$(alloy sprint create --project $PROJECT_ID --name "Sprint 13" \
--start-date 2026-04-08 --end-date 2026-04-22 --format json | jq -r '.id')
sprint list
alloy sprint list --project <PROJECT_ID> [--cursor <CURSOR>] [--limit <LIMIT>]
Examples:
# List sprints for a project
alloy sprint list --project $PROJECT_ID
# Get sprints as JSON
alloy sprint list --project $PROJECT_ID --format json
sprint start
Transition a sprint from planning to active.
alloy sprint start <ID>
Examples:
# Start a sprint
alloy sprint start $SPRINT_ID
# Start and verify status
alloy sprint start $SPRINT_ID && alloy sprint list --project $PROJECT_ID
sprint complete
Transition a sprint from active to completed.
alloy sprint complete <ID>
Examples:
# Complete a sprint
alloy sprint complete $SPRINT_ID
time
Log and manage time entries for capitalization tracking. Entries follow a
lifecycle: draft → submitted → approved.
time log
alloy time log [--user-id <UUID>] [--ticket <TICKET_REF>] [--project <PROJECT_ID>] [--date <DATE>] [--duration <MINUTES>] [--description <DESC>] [--activity-type <TYPE>]
| Flag | Default | Description |
|---|---|---|
--user-id <UUID> | logged-in user | User UUID |
--ticket <REF> | — | Ticket reference (prompted if missing) |
--project <ID> | from ticket | Project UUID |
--date <DATE> | today | Date in YYYY-MM-DD format |
--duration <MINUTES> | — | Duration in minutes (prompted if missing) |
--description <DESC> | — | What was done |
--activity-type <TYPE> | — | Activity category (prompted if missing) |
Activity types: Coding, Testing, CodeReview, Design, Documentation,
Meeting, Planning, DevOps, BugFix, Refactoring, Research, Support, Other
Examples:
# Log time interactively (prompts for missing fields)
alloy time log
# Log 90 minutes of coding against a ticket
alloy time log --ticket BACK-42 --duration 90 --activity-type Coding --description "Implemented auth middleware"
# Log time for yesterday
alloy time log --ticket 42 --duration 60 --activity-type CodeReview --date 2026-03-24
time list
alloy time list --ticket <TICKET_REF> [--cursor <CURSOR>] [--limit <LIMIT>]
Examples:
# List time entries for a ticket
alloy time list --ticket BACK-42
# Get time entries as JSON
alloy time list --ticket 42 --format json
time get
alloy time get <ID>
Examples:
# Get time entry details
alloy time get $TIME_ENTRY_ID
time submit
Move a time entry from draft to submitted for approval.
alloy time submit <ID>
Examples:
# Submit a time entry for approval
alloy time submit $TIME_ENTRY_ID
# Log and submit in one flow
ENTRY=$(alloy time log --ticket 42 --duration 60 --activity-type Coding --format json | jq -r '.id')
alloy time submit $ENTRY
time approve
Approve a submitted time entry (manager action).
alloy time approve <ID>
Examples:
# Approve a time entry
alloy time approve $TIME_ENTRY_ID
time report
Generate capitalization reports for a given month.
alloy time report --period <YYYY-MM> [--output <csv|json>]
| Flag | Default | Description |
|---|---|---|
--period <YYYY-MM> | (required) | Reporting month |
--output <csv|json> | csv | Report format |
Examples:
# Export March 2026 as CSV
alloy time report --period 2026-03
# Get report as JSON
alloy time report --period 2026-03 --output json
# Save CSV report to file
alloy time report --period 2026-03 > march-2026.csv
invite
Create and manage organization invitations.
invite create
alloy invite create --org-id <ORG_ID> [--email <EMAIL>] [--role <ROLE>]
| Flag | Default | Description |
|---|---|---|
--org-id <ORG_ID> | (required) | Organization UUID |
--email <EMAIL> | — | Invitee email (omit for open invite link) |
--role <ROLE> | Member | Owner, Admin, Member, Viewer |
Examples:
# Invite a specific person
alloy invite create --org-id $ORG_ID --email dev@example.com --role Member
# Create an open invite link for the team
alloy invite create --org-id $ORG_ID --role Member
# Get just the invite code for scripting
alloy invite create --org-id $ORG_ID --email new@example.com --format plain
invite list
alloy invite list --org-id <ORG_ID>
Examples:
# List pending invitations
alloy invite list --org-id $ORG_ID
# List invites as JSON
alloy invite list --org-id $ORG_ID --format json
onboard
First-run setup wizard. Creates the initial admin user, organization, and API key. Only works when no organizations exist in the system.
alloy onboard --email <EMAIL> --password <PASSWORD> --org-name <NAME> --org-slug <SLUG>
| Flag | Description |
|---|---|
--email <EMAIL> | Admin email address |
--password <PASSWORD> | Admin password (min 8 characters) |
--org-name <NAME> | Organization display name |
--org-slug <SLUG> | URL-friendly organization identifier |
Returns an API key that is shown only once — save it immediately.
Examples:
# Set up a fresh Alloy instance
alloy onboard --email admin@example.com --password mysecretpw --org-name "Acme Corp" --org-slug acme
# Capture the API key for automation
API_KEY=$(alloy onboard --email admin@example.com --password mysecretpw \
--org-name "Acme" --org-slug acme --format plain)
completions
Generate shell completion scripts.
alloy completions <SHELL>
Supported shells: bash, zsh, fish, powershell, elvish.
Examples:
# Generate Zsh completions
alloy completions zsh > ~/.zfunc/_alloy
# Generate Bash completions
alloy completions bash > /etc/bash_completion.d/alloy
usage
Print agent-optimized self-documentation (<1500 tokens). Useful for LLM agents that need to discover available commands.
alloy usage [SUBCOMMAND]
| Argument | Description |
|---|---|
SUBCOMMAND | Optional command name for detailed help |
Examples:
# Get concise overview of all commands
alloy usage
# Get detailed help for a specific command
alloy usage ticket
Credential Storage
Credentials are stored at ~/.config/alloy/credentials.toml (platform-specific
via the directories crate). The file contains:
access_token = "eyJ..."
refresh_token = "abc123..."
user_id = "550e8400-..."
email = "admin@example.com"
org_id = "660e8400-..." # set by `alloy org switch`
project_id = "770e8400-..." # set by `alloy project use`
project_key = "BACK" # set by `alloy project use`
The CLI auto-refreshes expired tokens: on a 401 response, it calls
/api/v1/auth/refresh with the stored refresh token, updates credentials on
disk, and retries the original request.
Common Workflows
Create an organization and invite your team
# First-time setup
alloy onboard --email admin@acme.com --password s3cretpw \
--org-name "Acme Corp" --org-slug acme
# Log in
alloy auth login --email admin@acme.com --password s3cretpw
# Create a project
alloy project create --org-id $ORG_ID --key BACK --name "Backend"
alloy project use BACK
# Invite team members
alloy invite create --org-id $ORG_ID --email dev1@acme.com --role Member
alloy invite create --org-id $ORG_ID --email dev2@acme.com --role Member
alloy invite create --org-id $ORG_ID --email lead@acme.com --role Admin
Sprint planning
# Create a sprint
alloy sprint create --project $PROJECT_ID --name "Sprint 12" \
--start-date 2026-03-25 --end-date 2026-04-08 \
--goal "Ship user authentication"
# Create tickets for the sprint
alloy ticket create --project $PROJECT_ID --title "Implement login endpoint" --priority high
alloy ticket create --project $PROJECT_ID --title "Add password reset flow" --priority medium
alloy ticket create --project $PROJECT_ID --title "Write auth integration tests" --priority medium
# Start the sprint
alloy sprint start $SPRINT_ID
# Check sprint status
alloy sprint list --project $PROJECT_ID
Time tracking for a week
# Set your default project
alloy project use BACK
# Log daily entries
alloy time log --ticket 42 --duration 120 --activity-type Coding --date 2026-03-24 --description "Auth middleware"
alloy time log --ticket 42 --duration 90 --activity-type Testing --date 2026-03-25 --description "Auth tests"
alloy time log --ticket 43 --duration 60 --activity-type CodeReview --date 2026-03-25 --description "PR review"
alloy time log --ticket 44 --duration 45 --activity-type Meeting --date 2026-03-26 --description "Sprint planning"
alloy time log --ticket 42 --duration 180 --activity-type Coding --date 2026-03-27 --description "Token refresh"
# Submit all entries
alloy time list --ticket 42 --format json | jq -r '.data[].id' | xargs -I{} alloy time submit {}
# Generate monthly report
alloy time report --period 2026-03
Bulk ticket updates with JSON output piping
# Close all done tickets
alloy ticket list --status done --format json | jq -r '.data[].id' | \
xargs -I{} alloy ticket update {} --status cancelled
# Reassign all tickets from one user to another
alloy ticket list --assignee-id $OLD_USER --format json | jq -r '.data[].id' | \
xargs -I{} alloy ticket update {} --assignee-id $NEW_USER
# Export all high-priority tickets
alloy ticket list --priority high --format json | jq '.data[] | {id, title, status}'
Shell Completions
Alloy can generate shell completion scripts for tab-completion of commands, subcommands, flags, and enum values.
alloy completions <SHELL>
| Argument | Values | Description |
|---|---|---|
SHELL | bash, zsh, fish | Shell to generate completions for |
Bash
Add to your ~/.bashrc:
# Generate and source completions
eval "$(alloy completions bash)"
Or install persistently:
# Create completions directory if needed
mkdir -p ~/.local/share/bash-completion/completions
# Generate the completion script
alloy completions bash > ~/.local/share/bash-completion/completions/alloy
# Reload your shell
source ~/.bashrc
Zsh
Add to your ~/.zshrc:
# Generate and source completions
eval "$(alloy completions zsh)"
Or install persistently:
# Ensure completions directory is in fpath (add to ~/.zshrc before compinit)
mkdir -p ~/.zfunc
echo 'fpath=(~/.zfunc $fpath)' >> ~/.zshrc
# Generate the completion script
alloy completions zsh > ~/.zfunc/_alloy
# Rebuild completion cache
rm -f ~/.zcompdump && compinit
Fish
# Generate and install completions
alloy completions fish > ~/.config/fish/completions/alloy.fish
Fish automatically loads completions from ~/.config/fish/completions/, so no
additional configuration is needed.
Verifying Completions
After installation, restart your shell (or source the relevant config file) and test by typing:
alloy <TAB>
You should see all available subcommands (health, project, ticket,
sprint, time, team, completions, etc.) as completion suggestions.