Skip to main content

Qapu CLI

A thin command-line client for the Qapu API (api.ovoo.com.tr), built for the Hermes agent (runs outside this Swarm, in a separate datacenter, and only ever talks to Qapu through this public API) - but usable by anything else that needs to script against Qapu from outside the private network.

Status: early development. Gated by a temporary shared-secret header, not real auth yet - see "Auth (current placeholder)" below before using this against production.

Why a separate tools/ project, not a services/

This isn't a deployed backend service - it's a distributable client tool, installed wherever Hermes (or anyone else) runs. Kept in the same monorepo (per CLAUDE.md's ADR-0001 - one repo, low context-switching for a 2-person team) rather than its own repo, since it's small and needs to stay in sync with the API it calls.

Install

Anyone with GitHub access to this (private) repo - no local clone needed, pip installs straight from the tools/cli subdirectory over git:

pip install "git+ssh://git@github.com/ovoo-tech/qapu.git#subdirectory=tools/cli"

(needs an SSH key already authorized on your GitHub account for this repo - the usual case for anyone on the team. No SSH key set up? Use an HTTPS Personal Access Token instead: pip install "git+https://<PAT>@github.com/ovoo-tech/qapu.git#subdirectory=tools/cli".)

Working on the CLI itself (this repo already checked out) - editable install so local edits take effect immediately:

cd tools/cli
pip install -e .

Either way installs a qapu command (see pyproject.toml's [project.scripts]). This package has no dependency on the rest of the monorepo (qapu_common etc.) - it only ever talks to Qapu over HTTP, never imports it directly - which is exactly what makes the git-subdirectory install above work without cloning anything else.

Configuration

Env var Purpose
QAPU_API_URL Base URL. Defaults to https://api.ovoo.com.tr. Point at http://localhost:8000 or an internal IP for local/dev testing.
QAPU_HERMES_KEY Shared-secret value for the X-Hermes-Key header - see "Auth" below. Required for every command except qapu health.

Commands

qapu health                          # GET /health - no auth, quick connectivity check
qapu device list                     # GET /hermes/devices - every device, bulk, as a table
qapu device list --json              # same data, raw JSON
qapu device list --status online     # only devices whose Update_Time moved in the last 30 min (see ONLINE_THRESHOLD_MINUTES in main.py - there's no real online/offline field, this is a heuristic)
qapu device list --status offline
qapu device list --model B107AA_R5   # case-insensitive substring match on Hardware.Model.Name
qapu device list --limit 100
qapu device get <device_id>          # GET /hermes/devices/{device_id} - one device, human-readable summary
qapu device get <device_id> --json   # same data, raw JSON

Filtering (--status/--model/--limit) happens client-side in the CLI, not on the server - fine at the current fleet size, worth moving server-side (GET /hermes/devices?status=...) if it ever grows large enough to matter.

Auth (current placeholder - read this before pointing at production)

api.ovoo.com.tr is genuinely public on the internet. The Hermes endpoints (services/api/src/routers/hermes.py) are gated by require_hermes_key (services/api/src/dependencies.py) - a single shared-secret string compared against the X-Hermes-Key header, checked via the HERMES_SHARED_SECRET env var on the API side. This is deliberately temporary: it exists only so the CLI/API plumbing could be built and tested end-to-end before the real auth design was ready, not because a shared secret is considered good enough long-term.

Real plan (not built yet - phase 2, along with the score/comment table Hermes will eventually write to): an admin-role hermes-qapu account in the users table, with the CLI gaining a qapu login command that authenticates through the existing JWT_Auth flow every other Qapu client already uses, storing a short-lived token instead of a static shared secret. client.py is written so only it needs to change when that lands - nothing in main.py should need to know how auth works under the hood.

Until then: HERMES_SHARED_SECRET fails closed (unset = every Hermes request rejected, never silently open), but a leaked shared-secret string is a much blunter credential than a scoped, revocable JWT - don't treat this as production-grade access control.

Running locally

QAPU_API_URL=http://localhost:8000 QAPU_HERMES_KEY=dev-secret python -m qapu_cli.main device list

(or, once installed via pip install -e .: just qapu devices list with the same env vars set.)

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qapu_cli-0.1.0.tar.gz (8.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qapu_cli-0.1.0-py3-none-any.whl (9.0 kB view details)

Uploaded Python 3

File details

Details for the file qapu_cli-0.1.0.tar.gz.

File metadata

  • Download URL: qapu_cli-0.1.0.tar.gz
  • Upload date:
  • Size: 8.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.7

File hashes

Hashes for qapu_cli-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1aa5064b6f582d709463b53f7c4a5d40f7e2a45c300fefc322381c94f5fb0792
MD5 53dfa371d81536ff917bfa887ae91af2
BLAKE2b-256 a1618f28c70cb5f5fe7e456e5743c0cb0cd8b100228aed7f56775f9c8be46356

See more details on using hashes here.

File details

Details for the file qapu_cli-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: qapu_cli-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.7

File hashes

Hashes for qapu_cli-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a2f52612f1ed4cc4c16925e86fc5d9e7b93a3c6367238f2a3088636aadb2620b
MD5 c77e22e2454d40549566f8ffcc61247b
BLAKE2b-256 c855160eadc7679b1cedbc4c6fc6f2b886b63a5d863e218810448d91244acdda

See more details on using hashes here.

Release history Release notifications | RSS feed

0.6.5

2 files

0.6.4

2 files

0.6.3

2 files

0.6.2

2 files

0.6.1

2 files

0.6.0

2 files

0.5.1

2 files

0.5.0

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

This release

0.1.0 This release

2 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