ADR-0004: A `loomscope` command-line client
Edit this pageStatus: Proposed Date: 2026-08-14
Context
Every routine interaction with Loomscope currently goes through a browser. That is wrong for several of its actual users:
- An engineer who wants to know whether a host appeared overnight, from a terminal, without breaking flow.
- A CI pipeline that should fail when a deployment introduces a critical CVE.
- An operator on an air-gapped console with no browser, or on a machine where opening one is a procedure.
- Anyone doing bulk work — importing fifty networks, acknowledging a class of findings — where clicking is the wrong tool.
Loomscope also already ships a Go binary and a generated Go API client, so the distribution machinery for a second static binary exists.
Decision
Ship loomscope, a single static Go binary, as a first-class client of
the public REST API (ADR-0003).
Design principles.
- Human output by default, machine output on request. Tables for a
terminal;
--output jsonor--output csvfor a pipe. Detect a non-TTY and drop colour automatically. - Exit codes carry meaning.
0success,1runtime error,2usage error, and — critically — a documented non-zero code when a query matches something the caller asked to be alerted about.loomscope vuln list --severity critical --fail-on-matchshould fail a pipeline. - Configuration cascades: flags, then environment
(
LOOMSCOPE_URL,LOOMSCOPE_API_KEY), then~/.config/loomscope/config.yml. Never a key on the command line by default, since that leaks into shell history and process listings. - Every command is a thin API call. No business logic in the CLI. If a command needs something the API cannot express, the API is what is missing.
Initial surface.
loomscope host list [--site] [--since] [--search]
loomscope host get <id>
loomscope service list [--host] [--signature]
loomscope vuln list [--severity] [--state] [--fail-on-match]
loomscope vuln ack <id>
loomscope cert list [--expiring-in 30d]
loomscope network add <cidr> [--site]
loomscope scan run --network <id> [--wait]
loomscope snapshot take
loomscope snapshot diff <from> <to>
loomscope topology export <kind> --format mermaid|drawio
loomscope site list
loomscope config set-context / get-contexts
Distribution. Static binaries for Linux, macOS and Windows on amd64 and
arm64, attached to GitHub releases and built by the existing pipeline. Also
shipped inside the server image so docker compose exec reaches it in an
air-gapped install.
Versioning. The CLI carries the API version it targets and warns clearly on mismatch rather than failing obscurely.
Alternatives considered
A Node CLI in the monorepo. Rejected. It would share TypeScript types with
the server, which is genuinely attractive, but it requires a Node runtime on
every machine that runs it — unacceptable for an air-gapped console or a
minimal CI image — and npx-based distribution is slower and less predictable
than a static binary.
A kubectl-style plugin model. Rejected as premature. There is no
extension demand yet, and it would complicate the first release for a
speculative benefit.
Document curl recipes instead. Rejected as the primary answer, though
the documentation will still show raw HTTP. curl plus jq covers one-off
queries but not authentication management, pagination, output formatting or
meaningful exit codes — and the CI use case needs all four.
Wait until after 1.0. Considered seriously. The counter-argument is that the CLI is the cheapest possible proof that the public API is usable: if a command is awkward to implement, the API design is wrong, and it is far better to learn that before the contract is frozen.
Consequences
Accepted costs.
- A second user-facing artefact to version, document, release and support.
- Cross-platform release engineering, including signing on macOS and Windows if we want it to run without warnings.
- The CLI will inevitably lag the UI in feature coverage, and users will notice.
Gains.
- Loomscope becomes scriptable, which is the difference between a dashboard and a tool that fits an existing workflow.
- The CI use case — fail a build on a critical finding — turns Loomscope into part of a delivery pipeline rather than something consulted afterwards.
- It exercises the public API as a real client, exposing design problems while they are still cheap to fix.
Dependency. Blocked on ADR-0003. Building the CLI against internal endpoints would defeat its main secondary purpose.