ScopeDocs CLI — explain services, map impact, ask questions across your engineering knowledge graph.
Project description
ScopeDocs CLI
Stateless HTTP client for the ScopeDocs knowledge graph. Three core verbs — ask, impact, why — plus auth and feedback. Designed for humans (TUI) and agents (--json) with the same code path.
$ scopedocs why payment-service
ᴡʜʏ — payment-service
════════════════════════════════════════════════════
Stripe was chosen over Adyen in 2024-Q3 to keep the
refund SLA under 5 minutes [1]. Idempotency keys are
enforced at the edge by checkout-web [2].
ɢ ᴏ ᴠ ᴇ ʀ ɴ ɪ ɴ ɢ ᴅ ᴇ ᴄ ɪ ꜱ ɪ ᴏ ɴ ꜱ
ADR-042 Refund SLA + provider choice long@
ADR-051 Idempotency at edge radha@
[1] notion://adr-042
[2] github://checkout-web/pull/1834
Install
Requires Python 3.11+.
macOS / Linux / WSL2:
curl -fsSL https://api.scopedocs.ai/install.sh | sh
Windows (PowerShell):
irm https://api.scopedocs.ai/install.ps1 | iex
Manual (any platform):
pipx install scopedocs-cli # recommended
python3 -m pip install --user scopedocs-cli # plain pip
Local dev install:
cd cli
python3 -m venv .venv
.venv/bin/pip install -e .
Authenticate
Get an API key from the ScopeDocs web UI (Settings → API keys), then:
scopedocs auth login # prompts for the key
scopedocs auth status # who am I — key, org, scopes, rate-limit
scopedocs auth status --json # same, machine-readable
scopedocs auth logout # clears saved credentials
auth status hits /api/v1/me and shows your CLI version, key name, org, scopes, rate-limit budget, and last-used timestamp. Use it as a "whoami" probe in CI to verify a key is still valid.
Credentials are saved to ~/.config/scopedocs/config.toml with 0600 perms. You can also bypass the file with the SCOPEDOCS_API_KEY env var or --api-key flag.
Core commands
scopedocs ask "<question>"
Free-form Q&A across all sources (GitHub, Linear, Slack, Notion, code). Streams tokens by default.
scopedocs ask "why is the refund flow flaky right now?"
scopedocs ask "who owns auth-service on-call?" --json
Backend: POST /api/v1/chat.
scopedocs impact <target>
Blast-radius map for a service, file, or symbol — direct consumers, pipelines, dashboards, recent incidents (≤90 days), live workarounds.
scopedocs impact payment-service
scopedocs impact backend/payment/stripe.py
scopedocs impact RefundProcessor.refund
Backend: GET /api/v1/impact/{target}.
Status: the backend endpoint is not deployed yet. The CLI calls it and exits cleanly with code
4(not-found) until backend ships it. No canned data fallback.
scopedocs why <target>
Why is this designed this way? Returns governing ADRs, chosen path, rejected alternatives, owners — decisions only, not "what does this code do" (that's your coding agent's job).
scopedocs why payment-service
scopedocs why backend/auth/jwt_auth.py
Backend: GET /api/v1/docs/search?query=...&category=adr + GET /api/v1/graph/node/{id}.
scopedocs update
Check PyPI for a newer release. Detects how the CLI was installed (pipx / pip --user / venv) and prints the matching upgrade command. Pass --apply to run it automatically (only safe for pipx — other install methods print the command for you to run manually).
scopedocs update # check + print upgrade command
scopedocs update --apply # auto-upgrade (pipx only)
scopedocs update --json # machine-readable
scopedocs update --channel pre # opt into pre-releases
The default --channel auto mirrors the channel of the installed version: stable on 0.x.y, pre-release on 0.x.ybN / 0.x.yaN. Pass --channel pre to track betas, --channel stable to ignore them.
scopedocs feedback --good | --bad "<note>"
Rate the most recent answer. Reads the latest entry from the local trace log, posts it to /api/v1/feedback with the original client_trace_id so the backend can join it back to the original query for DSPy training.
scopedocs feedback --good "matched the right ADR"
scopedocs feedback --bad "missed the live workaround for INC-204"
Interactive TUI
Run with no arguments to open a chat-style Textual app:
scopedocs
Slash commands: /ask, /impact, /why, /copy (Ctrl+Y), /clear (Ctrl+L), /help, /exit. Bare input (no leading slash) is treated as /ask. ↑/↓ walks prompt history.
Copy uses OSC 52 — works over SSH and tmux on iTerm2, Kitty, Alacritty, WezTerm, Ghostty, Windows Terminal. Silently no-ops on macOS Terminal.app and GNOME Terminal.
Global flags
Apply to every command:
| Flag | Default | Purpose |
|---|---|---|
--format text|json|markdown |
text |
Output format. Markdown deferred. |
--json |
off | Shortcut for --format json |
--budget <n> |
3000 |
Token budget hint sent to backend |
--workspace <id> |
from config | Override workspace |
--api-key <key> |
from env / config | Override auth |
--backend <url> |
from config | Override backend URL |
--no-color |
auto | Disable ANSI (auto-detected on non-tty) |
--quiet / -q |
off | Suppress logs |
--verbose / -v |
off | Print HTTP request/response trace to stderr |
--no-context |
off | Skip the local query-enrichment layer (privacy) |
--no-trace |
off | Don't append to the local trace log |
--session |
off | Attach the last few Q/A turns from the same cwd as conversation history |
--no-stream |
off | Force single-shot response (disable SSE streaming) |
--version, --help |
— | Standard |
Config
Precedence (high → low): CLI flag > env var > user config > repo config > built-in default.
User config (path varies by platform):
- POSIX:
$XDG_CONFIG_HOME/scopedocs/config.toml, default~/.config/scopedocs/config.toml - Windows:
%APPDATA%/scopedocs/config.toml
[default]
workspace = "ws_xxx"
api_key = "sk-sd_xxx"
budget = 3000
[backend]
url = "https://api.scopedocs.ai" # default — override only for self-hosted / staging
Repo override: .scopedocs/config.toml at the repo root (commit this for team-wide defaults). Currently honors workspace, repo_alias, and privacy.deny.
Environment variables: SCOPEDOCS_API_KEY, SCOPEDOCS_WORKSPACE, SCOPEDOCS_BACKEND_URL, SCOPEDOCS_BUDGET, SCOPEDOCS_NO_TRACE.
Exit codes
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Auth required / invalid key, or generic backend error |
2 |
Usage error (handled by Typer) |
3 |
Backend unreachable (network / timeout) |
4 |
Not found (404 — endpoint or target missing) |
All error paths print a clean one-line message; no Python tracebacks reach the user.
Query enrichment layer
Before every /api/v1/chat call, the CLI attaches a small query_context payload that the backend cannot otherwise see. This is query refinement only — it is not the DSPy context distillation, which lives in the backend.
| Provider | Collects |
|---|---|
env |
cwd, CLI version, terminal, IDE hint |
git |
branch, head sha (12 chars), uncommitted dirty files (cap 20) |
ide_selection |
file, line range, highlighted text (cap 1200 chars) |
workspace_config |
.scopedocs/config.toml workspace, repo alias, privacy denylist |
Total payload is capped at ~2000 chars (≈500 tokens). Eviction order when over: workspace_config → ide_selection.text → git.dirty_files[5:] → drop entire provider. env always survives.
Deliberately not collected: recent commits, PR descriptions, file content beyond uncommitted changes — those already exist in Layer 2 via the GitHub integration.
Disable with --no-context (one-shot) or remove the relevant provider via .scopedocs/config.toml.
Trace log
Every invocation appends one JSONL line to a per-user state file:
- POSIX:
$XDG_STATE_HOME/scopedocs/traces.jsonl, default~/.local/state/scopedocs/traces.jsonl - Windows:
%LOCALAPPDATA%/scopedocs/traces.jsonl
{"trace_id": "...", "ts": "...", "command": "ask", "question": "...", "query_context": {...}, "answer_summary": "...", "source_refs": [...], "tokens_used": 0, "backend_request_id": "..."}
Perms 0600. Auto-rotates at 5000 lines. The feedback command reads the most recent entry to wire the rating back to the original query.
Disable with --no-trace or SCOPEDOCS_NO_TRACE=1.
JSON output
Every command supports --json for agent consumption. Stable schemas — see scopedocs_cli/renderers/json.py. Example:
scopedocs ask "who owns billing?" --json | jq '.sources[].url'
ask shape:
{
"command": "ask",
"question": "string",
"summary": "string with [1] [2] citations",
"evidence": [{"source": "...", "system": "github|slack|linear|notion|...", "signal": "...", "ref": "1"}],
"recommendation": "string",
"sources": [{"ref": "1", "url": "...", "type": "pr|slack_thread|notion_page|adr|incident", "title": "..."}],
"tokens_used": 0,
"tokens_budget": 3000
}
Schemas for impact and why are documented inline in scopedocs_cli/renderers/json.py.
Verbose mode
--verbose enables Warp-style per-request tracing on stderr:
→ POST https://api.scopedocs.ai/api/v1/chat
← 200 https://api.scopedocs.ai/api/v1/chat in 412ms
Useful when debugging auth/backend issues without enabling Python logging.
Structure
cli/
├── pyproject.toml
├── README.md
└── scopedocs_cli/
├── main.py # Typer entry, global flags, lazy-imported subcommands
├── client.py # httpx wrapper (4 exception types, streaming SSE)
├── config.py # XDG config loader, save/clear creds
├── theme.py # Terminal Cartography palette
├── tui.py # Textual chat TUI
├── ui.py # Rich helpers (shared TUI + one-shot)
├── commands/ # ask · impact · why · feedback · auth
├── orchestrator/ # query enrichment layer + budget + trace
│ ├── budget.py
│ ├── trace.py
│ └── providers/ # env · git · ide_selection · workspace_config
└── renderers/ # tui.py + json.py
Tests
cd cli && python -m pytest tests/ -v
73 tests covering providers, budget, trace, client, config, ask command, auth status / me plumbing, and update (version compare, channel filtering, install-method detection). Mocked with httpx.MockTransport; no live network. CI runs the matrix on Python 3.11/3.12/3.13 across Ubuntu, macOS, and Windows — see .github/workflows/cli-tests.yml.
Releasing
Releases are automatic. Merge a PR that bumps the version in cli/pyproject.toml (and the matching cli/scopedocs_cli/__init__.py) to main, and .github/workflows/cli-release.yml will:
- Read the version from
cli/pyproject.toml. - Verify
__init__.pymatches (catch desync mistakes). - Skip cleanly if that version already exists on PyPI (idempotent).
- Run the test suite, build sdist + wheel, validate with
twine check --strict. - Publish to PyPI via Trusted Publishing (OIDC — no API token in secrets).
- Tag the commit
cli-v<version>and create a GitHub Release with the artifacts attached.
To force a re-publish (rare — only if you yanked and want to re-upload), use the workflow's workflow_dispatch trigger with force=true.
One-time setup (already done if you can see releases): on PyPI go to project → Settings → Publishing → "Add a new pending publisher" with owner=scopedocs, repo=scopedocs-ai, workflow=cli-release.yml, environment=pypi-cli-release-d9421f10. Then create the pypi-cli-release-d9421f10 environment in GitHub repo settings (no secrets needed; restrict deployment branches to main).
See CHANGELOG.md for release history.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file scopedocs_cli-0.1.3.tar.gz.
File metadata
- Download URL: scopedocs_cli-0.1.3.tar.gz
- Upload date:
- Size: 46.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9b4d8f23b8562e9ee2b2239116eacab5ea68e155e5ec656064c9e15b8fc4ede4
|
|
| MD5 |
ae405418a632a984fa8fa0ee98512c68
|
|
| BLAKE2b-256 |
2dd2dd4e2df76de83a70ad256bd9034942148243e0b2194a583f02c9db7eecbb
|
Provenance
The following attestation bundles were made for scopedocs_cli-0.1.3.tar.gz:
Publisher:
cli-release.yml on scopedocs/scopedocs-ai
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
scopedocs_cli-0.1.3.tar.gz -
Subject digest:
9b4d8f23b8562e9ee2b2239116eacab5ea68e155e5ec656064c9e15b8fc4ede4 - Sigstore transparency entry: 1566468519
- Sigstore integration time:
-
Permalink:
scopedocs/scopedocs-ai@fc859a49b6144d061d02cb7ed42e8bafba027243 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/scopedocs
-
Access:
internal
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
cli-release.yml@fc859a49b6144d061d02cb7ed42e8bafba027243 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file scopedocs_cli-0.1.3-py3-none-any.whl.
File metadata
- Download URL: scopedocs_cli-0.1.3-py3-none-any.whl
- Upload date:
- Size: 58.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df40d1bab5bacd968d6377fdecc64b7a02aa9f5be110c0fa50e2ec11a96eb61e
|
|
| MD5 |
e8e426ac397b7ddbf17dcc1317810af7
|
|
| BLAKE2b-256 |
02cd929be97d98de2a5709a026f6f7eeccd011cb9ead17481cf350dc49db3a67
|
Provenance
The following attestation bundles were made for scopedocs_cli-0.1.3-py3-none-any.whl:
Publisher:
cli-release.yml on scopedocs/scopedocs-ai
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
scopedocs_cli-0.1.3-py3-none-any.whl -
Subject digest:
df40d1bab5bacd968d6377fdecc64b7a02aa9f5be110c0fa50e2ec11a96eb61e - Sigstore transparency entry: 1566468560
- Sigstore integration time:
-
Permalink:
scopedocs/scopedocs-ai@fc859a49b6144d061d02cb7ed42e8bafba027243 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/scopedocs
-
Access:
internal
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
cli-release.yml@fc859a49b6144d061d02cb7ed42e8bafba027243 -
Trigger Event:
workflow_dispatch
-
Statement type: