12. The CLI as a Test Harness
Use the typed fichero CLI to prove backend behavior before blaming SwiftUI. The CLI mirrors the FastAPI surface and exercises the same OpenAPI contract, auth headers, library-path header, and response schemas the app relies on.
Rule of thumb: if a feature fails in SwiftUI, reproduce the same operation with the CLI against the running engine.
- CLI fails the same way → the backend or contract owns the bug.
- CLI succeeds → inspect the Swift store/service/view wiring.
- Endpoint not reachable from the CLI → an API-surface gap to track in the endpoint coverage matrix.
Setup
The CLI module is fichero_cli, and the venv is the repo .venv (chapter 10). With it activated, the installed fichero entry point works directly; the module form is equivalent:
# Start the engine
bash fichero-server/scripts/start_backend.sh
# In another shell — prefer JSON output for bug reports and comparisons
PYTHONPATH=fichero-server/src:fichero-cli/src .venv/bin/python -m fichero_cli --json health
Remember the feature-tier trap from chapter 3: a hand-started engine at the default release tier 404s the workflow/KG surface. start_backend.sh defaults to dev tier, which is what you want for CLI exploration.
Authentication
PYTHONPATH=fichero-server/src:fichero-cli/src .venv/bin/python -m fichero_cli auth login
PYTHONPATH=fichero-server/src:fichero-cli/src .venv/bin/python -m fichero_cli auth whoami
PYTHONPATH=fichero-server/src:fichero-cli/src .venv/bin/python -m fichero_cli auth logout
Credential resolution order:
FICHERO_SESSION_TOKEN~/Library/Application Support/Fichero/cli-session.jsonFICHERO_API_KEY~/Library/Application Support/Fichero/.api-key
auth login writes cli-session.json with mode 0600; the session token is preferred over the bootstrap/shared-secret fallback so normal CLI use does not quietly keep running as the bootstrap owner after a real user logs in. A 401 means the token is missing or expired (auth login); a 403 means the user is authenticated but lacks access to the selected library — re-check --library / FICHERO_LIBRARY_PATH and the ACL.
For library-scoped endpoints, pass the same library the app is using with the --library flag:
PYTHONPATH=fichero-server/src:fichero-cli/src .venv/bin/python -m fichero_cli \
--library "$HOME/Documents/My Library.fichero" \
--json search "sample query"
Importers need the engine
import-manifest and import-iiif are thin HTTP clients over the backend routes — they do not write the library directly. Start the engine first; pass --api only when targeting a non-default engine URL; let the importer reuse the CLI auth/session resolution unless you explicitly pass --token-file.
bash fichero-server/scripts/start_backend.sh
PYTHONPATH=fichero-server/src:fichero-cli/src .venv/bin/python -m fichero_cli auth login
PYTHONPATH=fichero-server/src:fichero-cli/src .venv/bin/python -m fichero_cli import-manifest \
--manifest /path/to/manifest.jsonl \
--library "$HOME/Documents/My Library.fichero"
Debug loop
- Reproduce the action in the UI; note the endpoint, document id, library, and visible failure.
- Run the equivalent CLI command with
--jsonand the same--library. - Compare status, payload shape, and returned ids against UI state.
- If the backend route changed, run
./fichero-server/scripts/sync_openapi_schema.shbefore committing. - Add a focused backend unit/integration test or CLI contract test for the failure before closing the issue.
Guardrails that keep the CLI and app from drifting from the contract, all part of verify_all.sh --fast:
python3 scripts/check_endpoint_usage.py
python3 scripts/check_endpoint_coverage_matrix.py
PYTHONPATH=fichero-server/src python fichero-server/scripts/validate_model_sync.py