Skip to main content

semacli

PyPI version Python versions License: MIT Build Publish codecov Docstring coverage Quality Gate Status Maintainability Rating Reliability Rating Security Rating Bugs Vulnerabilities Code Smells Technical Debt

A CLI tool to manage Semaphore UI (ansible-semaphore) via its HTTP REST API.

Designed for LLM/agent and automation use — deterministic commands, JSON output, exit codes.

Features

  • List projects, templates, inventories, environments
  • Templates: create / update / audit / sync, with the per-run overrides (--limit, --tags, …) declared explicitly — see Templates
  • Launch and monitor tasks
  • Read task output
  • Schedules: cron or one-shot --run-at triggers, carrying the same ansible overrides as a run (--limit / --tags / --skip-tags / --inventory / --cli-args) so a planned run can target a subset of hosts without a dedicated template — see sem sched create --help
  • JSON output support
  • Bearer-token authentication (User Settings → API Tokens)
  • VS Code extension: running / finished tasks in the sidebar, task detail with its output, stop — reads the same semacli.ini (see VS Code extension)

Installation

# From PyPI
pip install semacli

# From source
pip install git+https://github.com/lduchosal/semacli.git

# Development
git clone https://github.com/lduchosal/semacli.git
cd semacli
pdm install

VS Code extension

Each GitHub release attaches semacli-vscode-<version>.vsix (no Marketplace):

gh release download semacli-<version> -R lduchosal/semacli -p '*.vsix'
code --install-extension semacli-vscode-<version>.vsix

It finds semacli.ini from the workspace folder upwards (then ~/.semacli.ini, /usr/local/etc/semacli.ini) and honours [auth], load_dotenv and the TLS settings like the CLI. Details: vscode/README.md.

Quick Start

Configuration

Create semacli.ini in the current directory or ~/.semacli.ini:

[semaphore]
url = https://monitor.example.com/semaphore
project = 1

[auth]
method = bearer_token
bearer_token = your-api-token-here

[settings]
timeout = 30
verify_ssl = true

Get a bearer token from the Semaphore UI: User Settings → API Tokens → Create.

Basic Usage

# Ping the API
sem ping

# List projects
sem projects

# (more commands wired in as the CLI grows)

Output Options

# JSON output
sem projects --json

# Verbose debugging
sem projects -v
sem projects -vv
sem projects -vvv

Configuration Options

Authentication Methods

[semaphore]
url = https://monitor.example.com/semaphore

[auth]
method = bearer_token
bearer_token = your-api-token

Bearer token from environment variable

[semaphore]
url = https://monitor.example.com/semaphore

[auth]
method = env_var
env_var = SEMAPHORE_TOKEN

TLS / system certificate store

requests ships with the certifi CA bundle and ignores the OS trust store by default. On corporate Windows machines, root CAs installed via Group Policy are therefore not trusted and you'll see SSLError: unable to get local issuer certificate against an internal Semaphore. Same trap on macOS if your corp CA only lives in Keychain.

semacli defaults to use_system_ca = auto — on (Windows) / off (macOS, Linux). Force it either way if needed:

[settings]
# use_system_ca = auto   # default: true on Windows, false elsewhere
# use_system_ca = true   # force-use OS trust store (e.g. macOS Keychain)
# use_system_ca = false  # force-use certifi bundle (e.g. cross-platform CI)

Implementation: when on, semacli calls truststore.inject_into_ssl() (via the truststore library, maintained by the urllib3 author). TLS verification stays on — only the source of trust anchors changes.

Auto-load .env (opt-in)

When method = env_var, the token must be in your shell before you run sem. Two ways to make that happen:

  1. direnv (recommended for active dev) — brew install direnv + eval "$(direnv hook zsh)", then drop a .envrc (or .env with dotenv directive) in the project. Auto-loads on cd.
  2. [settings] load_dotenv = true (no extra tool) — semacli reads .env next to your semacli.ini at startup. Existing shell vars always win, so the file only fills gaps.
[settings]
load_dotenv = true
# load_dotenv_file = .env   # optional; relative paths resolve against
                            # the semacli.ini directory.
# .env (gitignored, chmod 600)
SEMAPHORE_TOKEN=ninjwlgclse7_...

The file is parsed by python-dotenv, so quoting, comments, and ${VAR} interpolation all work as expected. A warning is printed if .env is group/world-readable — chmod 600 .env to silence it.

Shell hooks around sem run

Declare [hook] keys in semacli.ini to fire shell commands before/after a template run. Useful for syncing a remote repo, sending notifications, or paging on failure. Relative paths resolve against the .ini directory.

[hook]
# Aborts the run with exit 6 on non-zero. Receives env vars:
#   SEMACLI_TEMPLATE, SEMACLI_LIMIT, SEMACLI_TAGS, SEMACLI_PROJECT,
#   SEMACLI_TEMPLATE_ID, SEMACLI_CONFIG, SEMACLI_EVENT
task_run_prehook = scripts/sync-svn.sh

# Fires after watch completes (any status). Failures = warnings only.
# Also receives SEMACLI_TASK_ID and SEMACLI_STATUS.
task_run_posthook = scripts/notify.sh

# Same envelope as posthook, fires only when status != success.
task_run_failhook = scripts/page-oncall.sh

# Default 60s, applies per-hook.
timeout = 30

Pass --no-hooks on sem run to bypass them (debug / replay).

Templates

A template decides which per-run overrides a task may pass. Semaphore does not reject a forbidden override — it drops it and runs anyway, so a --limit that is not allowed runs the playbook on the whole inventory. semacli refuses that run instead, which makes the template's task_params worth getting right.

# Create: every override allowed unless you narrow it
sem template create --name deploy --playbook deploy.yml \
    --repository ansible --inventory prod --environment secrets --view DEPLOY

# A template nobody may re-target at run time
sem template create --name reboot-all --playbook reboot.yml \
    --repository ansible --inventory prod --allow-override none

# Update: read-modify-write, only the flags you pass are touched
sem template update deploy --allow-override limit,tags

# Which templates would silently ignore a --limit? (exit 1 if any)
sem template audit
sem template audit --require limit,tags
sem template --json audit   # shared flags live on the group

--arguments only accepts a JSON array of static flags ('["--diff"]'). Jinja placeholders are refused: Semaphore stores the string verbatim and ansible reads {{ limit }} as a literal host pattern.

Declarative sync

sem template sync reconciles a YAML manifest with the project: one template per declared playbook, idempotent, and never a delete (a template owns its task history). Run it with --dry-run first — it prints, field by field, what would change.

# templates.yml
defaults:
  repository: ansible          # name or id
  inventory: prod
  environment: secrets
  description: "Run ansible playbook {playbook}"
  allow_override: [limit, tags, skip-tags, inventory, debug]
playbooks: ansible             # scan ansible/*.yml, relative to this file
ignore: [requirements.yml, site.yml]
views:                         # template name -> board view
  mtree: BSD
templates:                     # explicit entries, merged over the scan
  - name: book_base
    playbook: book_base.yml
    view: BOOK
sem template sync --manifest templates.yml --dry-run   # review
sem template sync --manifest templates.yml             # create what is missing
sem template sync --manifest templates.yml --update    # + patch what drifted

Existing templates are skipped unless --update is passed, and with it only the ones that actually differ are written back. Templates present on the server but absent from the manifest are reported, never removed.

Exit Codes

Code Meaning
0 Success
1 General error
2 Configuration error
3 Authentication error
4 API error
5 Not found
6 Hook aborted the command (pre-hook returned non-zero or timed out)

sem template audit uses exit 1 for "findings" (at least one template forbids a required override) so it can be wired as a periodic check; sem template sync uses it when a create/update failed.

Development

# Clone and setup
git clone https://github.com/lduchosal/semacli.git
cd semacli
pdm install -G dev

# Run tests
pdm test

# Lint and format
pdm lint
pdm format

# Type check
pdm typecheck

# Build
pdm build

Architecture

semacli/
├── cli/                    # Click CLI interface
│   ├── commands/           # Individual commands
│   ├── decorators.py       # Common CLI options
│   └── handlers.py         # Error handlers
├── core/                   # Core business logic
│   ├── client/             # Semaphore HTTP client (per-resource mixins)
│   ├── config.py           # Configuration
│   ├── exceptions.py       # Custom exceptions
│   ├── guards.py           # Pre-flight refusals (overrides, arguments)
│   ├── manifest.py         # `template sync` manifest parsing
│   ├── models.py           # Data models
│   ├── overrides.py        # task_params vocabulary
│   ├── resolve.py          # name-or-id resolution
│   └── sync.py             # `template sync` planner (pure)
└── services/               # Business services

See ARCHITECTURE.md for the wiki classification map used by ken wiki groom.

License

MIT License - see LICENSE for details.

  • nagioscli - sibling CLI for Nagios Core (model project)

Metadata

Release files for semacli 0.5.31

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for semacli 0.5.31
File Size Uploaded Provenance Actions
semacli-0.5.31.tar.gz 162.8 kB Without provenance Details for semacli-0.5.31.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for semacli 0.5.31
File Interpreter ABI Platform Actions
semacli-0.5.31-py3-none-any.whl Python 3 none any Details for semacli-0.5.31-py3-none-any.whl

Total release size: 266.1 kB

Release files / semacli-0.5.31.tar.gz

Download URL semacli-0.5.31.tar.gz
Size 162.8 kB
Tags Source
SHA-256 checksum
How to use checksums
a3b84fadb45be4f3b9c16df5aa35cb1a9064c3b747fe918c87f2cabc5fdf45ae
BLAKE2b-256 checksum
How to use checksums
4f9f7474e9d79c43b1841152ac83c0655be172c46d7a2010df33db9a081e9389
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via pdm/2.29.2 CPython/3.12.3 Darwin/25.6.0

Release files / semacli-0.5.31-py3-none-any.whl

Download URL semacli-0.5.31-py3-none-any.whl
Size 103.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
275a3080324fe141438caec2c193b1029aa25cc5e6e4404be587a74176926a9d
BLAKE2b-256 checksum
How to use checksums
b401cd625670f893cc79a7b041c3a81362da02f0c6250ceda29af48811027865
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via pdm/2.29.2 CPython/3.12.3 Darwin/25.6.0

Security for semacli 0.5.31

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.5.31 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page