The login is a browser-loopback OAuth that reuses your instance's existing OIDC session and stores the token 0600 at
~/.navigator.json (a single gcloud-style dotfile; set NAVIGATOR_CONFIG_DIR to use the legacy
<dir>/credentials.json location instead). The host is your deployment's — www.your-domain.example, a staging
host, or http://localhost:8080 for the KIND loop — so the same CLI drives whichever instance you point it at, each
keyed separately in the credential file. That is the whole reason --host is a flag and nothing about a domain is baked
in: this CLI is for your install, not ours. The crate is cli; the binary it builds is navigator.
Then log in and drive a matter end to end:
navigator login --host www.your-domain.example # opens the browser → ~8h token, stored 0600 (~/.navigator.json)
navigator whoami # "you@example.org (admin) — expires in 7h52m"
navigator projects list # GET /portal/projects.csv → table (or --json)
navigator project open --name "Estate of Doe" \
--client-name "Jane Doe" --client-email jane@example.org \
--scope "Flat-fee estate planning" # opens the matter; retainer parks at staff_review
navigator retainer approve <notation-id> # renders + parks the retainer PDF (no envelope yet)
navigator notation status <notation-id> # state + signature request id + document_ready
navigator retainer send <notation-id> # dispatches one real envelope (409 until document_ready)
navigator retainer send <notation-id> # idempotent — reuses the same envelope, no second send
navigator logout
Use that same sequence to verify a fresh install end to end — it is the smallest real exercise of the durable
pipeline. Point the client email at an inbox you control (never a third party — send transmits a binding engagement
letter), and walk the three assertions: retainer approve should leave the notation parked at
document_open__retainer_pdf; notation status should flip to document_ready:true once the worker has rendered and
persisted document.pdf (cross-check that the rendered object actually landed in your private documents bucket with
gcloud storage ls gs://your-project-id-documents/notations/<notation-id>/); and retainer send should report
sent_for_signature__pending with a signature request id, then reuse that same envelope on a second run. When you sign
or decline, the inbound webhook should log a HMAC-verified esignature webhook: signature event in the navigator-web
pod. Decline or void the test envelope afterward so no live engagement lingers against a real inbox.
After a single login, --host is optional — the one stored host is used — so the later commands stay short. Every
command is a thin client over a route web already serves, sent with Authorization: Bearer <token>: your instance
resolves that token back into your session and runs the same handler the browser does, so the staff_review gate, the
role check, and the authored_by provenance all hold unchanged. The send is a durable two-step: retainer approve
renders + parks the PDF on the worker, and the separate retainer send dispatches the envelope only after confirming
the PDF landed (document_ready:true), returning a 409 with a JSON reason — never an opaque 500 — until then. Sending
a retainer for signature stays a deliberate authenticated human command (retainer send) — it is never exposed as an
agent-routable tool. The full per-subcommand reference is the cli crate's README.md in the source tree.