Skip to main content

OpsCli

OpsCli (by Caipora Labs) is the product name. The PyPI project, primary console script, and Python import are curupira. The short command curu is the same entry point.

OpsCli runs automations on your machine. It takes a GitHub issue or pull request, or a local cron occurrence, and hands it to a coding-agent CLI you already have.

Each automation in the settings TOML watches one source (issues, pull requests, or a cron schedule) and carries its own prompt. All automations share one discovery, scheduling, and execution pipeline: run executes a single currently available task, while watch polls every automation continuously.

Requirements

  • Python 3.11 or newer (3.11–3.14 supported; Linux, macOS, and Windows)
  • gh installed and authenticated (gh auth login)
  • Only the CLIs used by the configured profiles need to be installed: opencode, codex, claude, or the Cursor CLI (agent)

Installation

Install the published package from PyPI:

uv tool install "curupira==0.1.0"

The project is caipora-labs/curupira. curupira --version and the short alias curu --version report the installed version.

Documentation

See the full guide in Portuguese for installation, automation configuration, providers, and operational commands.

Configuration

The default settings file is ~/.curupira/settings.toml. Download the example configuration directly to that location, then adjust repositories, paths, queries, and prompts:

mkdir -p ~/.curupira
curl -fsSL https://raw.githubusercontent.com/caipora-labs/curupira/main/curupira.example.toml \
  -o ~/.curupira/settings.toml

The ~/.curupira directory is created automatically when the default file is first loaded. Pass --config path/to/settings.toml to use a different file; relative workspace, state, and automation paths are resolved from that file's directory.

[settings]
max_active_tasks = 1
workspace_dir = "~/.curupira/workspaces"
state_db_path = "~/.curupira/state.sqlite3"
# Optional OTLP/HTTP trace endpoint; omit it to disable telemetry.
# otlp_endpoint = "http://localhost:4318/v1/traces"

[settings.polling]
poll_interval_seconds = 30
batch_size = 100
cron_poll_interval_seconds = 1

[coding_agents.defaults]
profile = "opencode-default"
timezone = "UTC"

[coding_agents.profiles.opencode-default]
provider = "opencode"

[coding_agents.automations.resolve-ready-issues]
trigger_type = "issue"
repo = "acme/api"
query = "is:open label:agent-ready sort:created-asc"
prompt = "Resolve issue ${issue_number}: ${issue_title}\n\n${issue_body}"

Automations

[coding_agents.automations.<name>] is a keyed map; the map key is the automation ID and is carried into every task identity. trigger_type selects the source:

  • "issue" — discovers matching issues with query
  • "pull_request" — discovers matching pull requests with query
  • "cron" — produces occurrences from schedule instead of querying GitHub

Every automation requires repo, prompt, and — depending on the trigger — query or schedule. Optional profile selects a named CLI profile; otherwise the default profile applies. Optional path pins the automation to an existing checkout or an alternative clone destination; relative paths resolve from the TOML directory, as do workspace_dir and state_db_path. Different repositories cannot share one workspace path. Automations keep file order, and one-shot selection follows that order.

Providers and native options

model, effort, and agent are optional and their flags are omitted when unconfigured. agent uses the provider's native setting: it selects a custom agent in OpenCode and Claude Code, a named Codex CLI profile, and Cursor's execution mode.

Provider agent mapping model effort
opencode Custom agent via --agent Optional --model Optional --variant
claude Custom agent via --agent Optional --model Optional --effort
codex Config profile via --profile Optional --model model_reasoning_effort via --config
cursor Mode via --mode Optional --model Not supported; rejected

Cursor agent accepts agent, ask, or plan as the value of --mode.

OpenCode runs opencode run --format json; a saved session resumes with --session. Codex runs codex exec --json, resumes with codex exec resume <thread_id>, maps agent to --profile, and maps effort to --config model_reasoning_effort=<level>. Codex effort levels include low, medium, high, xhigh, max, and ultra; which levels are available depends on the selected model and CLI version. Claude Code runs claude -p --output-format stream-json --verbose, resumes with --resume, and passes agent and effort through their native flags. Cursor runs agent --print --output-format stream-json, resumes with --resume, and maps agent to --mode; it does not accept effort.

Explicit permission overrides are also provider-specific (auto_approve for OpenCode, sandbox/auto_review for Codex, permission_mode/permission_prompts for Claude Code, force/trust for Cursor). When omitted, each CLI keeps its native policy.

Prompts and placeholders

Placeholders use ${name} syntax and are validated when the configuration loads. Common fields: ${repo}, ${automation_id}, ${task_type}, ${task_number}, ${task_title}, ${task_body}, ${task_url}. Issues add ${issue_number}, ${issue_title}, ${issue_body}, ${issue_url}. Pull requests add ${pull_request_number}, ${pull_request_title}, ${pull_request_body}, ${pull_request_url}, ${pull_request_is_draft}, ${pull_request_head_ref}, and ${pull_request_base_ref}. For cron tasks, ${task_number} is the occurrence timestamp.

Discovery, concurrency, and cron semantics

Queries use GitHub search syntax and fetch up to batch_size items per poll (default 100, up to 1000). When a full cycle finds nothing, the shared poller waits poll_interval_seconds (default 30s); consecutive empty cycles double the wait up to 5 minutes, and any discovery resets it. Each automation deduplicates its own items, so two automations may process the same issue with different prompts.

Polls that use the project: search qualifier keep the open state and filter board items to the Todo status automatically.

Trello listener

The Trello listener is named trello-cli and uses the Scale-Flow CLI at https://github.com/Scale-Flow/trello-cli. If trello is not already installed, install it from that repository's GitHub Releases or with Homebrew:

brew tap Scale-Flow/tap
brew install trello-cli

Authenticate with the CLI Connector Power-Up on the Trello board:

trello auth login

Follow the pairing instructions printed by the CLI. This is the Scale-Flow CLI; do not install the unrelated npm packages also named trello-cli.

max_active_tasks bounds concurrently running coding agents (default 1). By default, each task runs in a new worktree beside its base checkout, so tasks for the same repository can run concurrently without sharing edits. The worktree branch is created from the fetched remote default branch and is not pushed. Set checkout = "main" to use the shared checkout instead (this means the shared checkout, not a branch named main, and restores the previous exclusive behavior). path continues to select the base checkout. With checkout = "main", the agent runs on the shared checkout exactly as it is: OpsCli does not fetch, pull, or switch branches there. Checkouts are created on demand with gh repo clone under workspace_dir/owner/repo. Nothing modifies issues or pull requests.

An optional setup_script is a repository-relative executable path (no absolute paths or ..). It runs directly, with the checkout root as its working directory, only when the base checkout has just been cloned. It does not run for an existing checkout or in the task worktree, so files or dependencies installed there are not available to the agent. Use checkout = "main" when the agent must run where setup wrote files. A nonzero setup exit prevents the agent from starting; the newly cloned checkout is removed, while an existing checkout is preserved. validate checks the path syntax but does not require the script to exist. run --dry-run does not fetch, clone, create a worktree, or run setup, so it cannot verify that the script or worktree will work. Existing automation TOML remains valid, but now uses a worktree by default; configure checkout = "main" to keep the old shared-checkout behavior.

Each cron automation coalesces overdue ticks into a single pending occurrence; the same automation never runs concurrently with itself. schedule is a five-field cron expression, timezone is IANA (defaulting to coding_agents.defaults.timezone), and start_date/end_date form an optional inclusive window interpreted in that timezone. Without start_date, the window starts when the automation is first recorded.

OpenTelemetry

Set settings.otlp_endpoint to an OTLP/HTTP trace endpoint (for example, http://localhost:4318/v1/traces) to export one span for each dispatched issue, pull request, or cron occurrence. Each span includes the repository, type, identifier, and result (success or failure); failures also include error.message. The endpoint must accept OTLP over HTTP/protobuf. If the field is omitted, no telemetry is exported.

State files

Running sessions and cron schedule state live in state_db_path (default ~/.curupira/state.sqlite3). The per-user dispatch lock is stored in ~/.curupira/dispatch.lock, and the dedicated log directory is ~/.curupira/logs. Only one run or watch process can dispatch at a time; a second process exits with an error rather than running tasks in parallel. Session records are removed when the agent process ends; watch resumes all saved sessions after a restart, and run resumes the saved session of the task it selects. If the file exists but is not a compatible database, the application exits with an error instead of deleting it — delete or move the file yourself to start fresh.

Log file

The run and watch commands append records to ~/.curupira/logs/curupira.log; restarting the process does not erase existing content. Each task records its start and completion time, repository, type, and identifier. If a task fails, the record includes the error.

Usage

Validate configuration without calling external CLIs or writing state:

curupira validate

Execute one currently available task and wait for the agent to finish:

curupira run

Preview the selected task without reserving, persisting, cloning, or executing:

curupira run --dry-run

Poll all automations with the shared bounded scheduler until interrupted:

curupira watch

The short alias curu accepts the same subcommands (curu validate, curu run, curu watch).

validate exits 0 when the configuration is valid and 2 on configuration errors. run exits with the agent process status, 0 when no task is available, and 1 on dispatch errors. watch exits 1 when any executed task failed, otherwise 0. run --dry-run never reserves or persists cron occurrences and does not perform checkout, worktree, or setup operations.

watch runs every CLI non-interactively so concurrent workers never contend for the terminal UI. Transient gh failures are retried with backoff; authentication, configuration, output-format, and agent-task failures are not retried automatically.

Public interface

OpsCli is CLI-first. The only supported programmatic surface is curupira.__version__; all other modules are internal implementation details that may change without notice.

Development and validation

uv sync --dev
uv run --no-sync pytest
uv run --no-sync ruff check .
uv run --no-sync ruff format --check .
uv run --no-sync pyrefly check
uv build
uv run --no-sync twine check dist/*

uv sync installs the Python package without compiling Rust. uv build produces a wheel that includes the curupira._native extension and needs a stable Rust toolchain. See CONTRIBUTING.md for maturin develop and the crate layout under crates/curupira-core.

To inspect branch coverage locally, run uv run --no-sync pytest --cov --cov-report=term-missing; the configured minimum is 85%.

See CONTRIBUTING.md for environment setup and the exact verification commands, and CHANGELOG.md for release notes.

License

MIT — see LICENSE.

Metadata

Release files for curupira 0.1.0

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

Source distribution (sdist)

Source distribution for curupira 0.1.0
File Size Uploaded
curupira-0.1.0.tar.gz 182.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for curupira 0.1.0
File Interpreter ABI Platform
curupira-0.1.0-cp311-abi3-manylinux_2_34_x86_64.whl CPython 3.11 abi3 Linux glibc 2.34+ x86-64 Details

Total release size: 454.8 kB

Release files / curupira-0.1.0.tar.gz

Download URL curupira-0.1.0.tar.gz
Size 182.3 kB
Tags Source
SHA-256 checksum
How to use checksums
d1a6abcdfdf79a7291cba6e0dd5638c5cfbfccb4841c83f6832fb58bc44230d5
BLAKE2b-256 checksum
How to use checksums
1a45356e03cf55973b907e4c3fed69e8bd3591fca2f5ee5d9158cd8c89571643
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release files / curupira-0.1.0-cp311-abi3-manylinux_2_34_x86_64.whl

Download URL curupira-0.1.0-cp311-abi3-manylinux_2_34_x86_64.whl
Size 272.5 kB
Tags CPython 3.11 Linux glibc 2.34+ x86-64 abi3
SHA-256 checksum
How to use checksums
bf1571a59adde9e5525ec6ca58fb60cf9b25dd51f21b85ddef1a9bbf66a7a33f
BLAKE2b-256 checksum
How to use checksums
4648e042d4dd534554008495f1af9d411adcf925e0d0346e01708319cfb5ce77
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

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