A command line interface for Semaphore UI. It feels similar to gh and glab: noun-first commands, readable tables by default, stable JSON for automation, explicit auth, profiles, and an api escape hatch.
Disclaimer:
semctlis an independent, open-source command line interface for Semaphore UI. It is not affiliated with, endorsed by, sponsored by, or officially connected to the Semaphore UI project or its creators. This tool is intended for personal use, educational purposes, and operational convenience at your own risk. All product names, logos, and brands are property of their respective owners.
brew install moep90/tap/semctlOr:
brew tap moep90/tap
brew install semctlgo install github.com/moep90/semaphore-cli/cmd/semctl@latestDownload from GitHub Releases.
# Authenticate (API token from your Semaphore UI profile)
semctl auth login https://semaphore.example.com
# Select a default project
semctl project list
semctl project use homelab
# Discover templates and run tasks
semctl template list
semctl task run deploy-prod --message "Deploy release 1.8.3"
semctl task logs --follow# Interactive login (prompts for token, no echo)
semctl auth login https://semaphore.example.com
# Login with token from stdin
pass show semaphore/prod-token | semctl auth login https://semaphore.example.com --with-token
# One-off command with token from environment
SEMAPHORE_TOKEN=... semctl project list --host https://semaphore.example.comCredentials are stored in your OS keychain when possible. If the keychain is unavailable, the CLI fails unless you pass --plaintext, which stores the token in your config file. See semctl auth login --help.
When a command needs to authenticate, the token is resolved in this order:
SEMAPHORE_TOKENenvironment variable- OS keyring (macOS Keychain, Windows Credential Manager, Linux Secret Service)
- Active profile
tokenfield inconfig.yml
This means SEMAPHORE_TOKEN overrides everything, making it ideal for CI pipelines. For daily use, the keyring is preferred because it keeps the token out of shell history and environment dumps (/proc/*/environ).
Security tip: Avoid export SEMAPHORE_TOKEN=... in your shell profile. Use --with-token for one-off scripts, or run semctl auth login once to store the token in the keyring.
Platform-native config paths:
- Linux:
~/.config/semctl/config.yml - macOS:
~/Library/Application Support/semctl/config.yml - Windows:
%AppData%\semctl\config.yml
Example:
current_profile: prod
profiles:
prod:
host: https://semaphore.example.com
project: infra
token_source: keyring
default_output: tableSEMAPHORE_HOST
SEMAPHORE_TOKEN
SEMAPHORE_PROFILE
SEMAPHORE_PROJECT
SEMAPHORE_OUTPUT
SEMAPHORE_NO_COLOR
Precedence: explicit flags > environment variables > active profile > defaults.
semctl project list
semctl project list --json
semctl project list --output yaml
semctl task get 812 --output json | jq '.status'# Run a template
semctl task run deploy-prod --message "Deploy release 1.8.3"
# Watch a task and return its exit code
semctl task run deploy-prod --watch --exit-code
# Follow logs
semctl task logs 812 --follow
# Stop a task
semctl task stop 812semctl api GET /info
semctl api GET /projects
semctl api POST /project/1/tasks --field template_id=7
semctl api GET /project/1/tasks/last | jq '.[0]'- Tokens and cookies are never printed.
--debugredacts secrets from logs.- TLS verification is enabled by default.
semctl completion bash > /etc/bash_completion.d/semctlctl
semctl completion zsh > "${fpath[1]}/_sem"
semctl completion fish > ~/.config/fish/completions/semctl.fishRequires mise (optional but recommended).
mise install
mise run build
mise run test
mise run test-e2eWithout mise:
go build -o bin/semctl ./cmd/semctl
go test ./...Tests run against a disposable Semaphore UI instance via Docker Compose:
docker compose up -d --wait
SEMAPHORE_E2E=1 go test -tags=e2e ./... -count=1
docker compose down -vLicensed under the Apache License, Version 2.0.