Command line
for operators
psd serve [--config psd.json]
psd keygen [--keys psd-keys.json] [--rotate] [--prune-days N]
psd person add --name "Alice" [--config psd.json] [--ttl 900]
psd person list [--config psd.json]
psd invite --person ID [--config psd.json] [--ttl 900]
psd agents list [--config psd.json]
psd agents revoke ISS SUB [--config psd.json]
psd pending list [--config psd.json]
psd pending approve ID [--person ID] [--config psd.json]
psd pending deny ID [--config psd.json]
psd example-config > psd.json
psd version
Every command except keygen, example-config and version loads the
config (--config, default psd.json, plus the environment overrides) and
opens the database. Relative storage.path and keys_file resolve against
the current directory, so run these from where serve runs, or use
absolute paths. The CLI refuses a :memory: database, since there would be
nothing to operate on.
serve
Runs the server on listen until SIGINT/SIGTERM. Prints a startup
summary to stderr — issuer, storage, whether passkeys are available
(they are not on an IP-address issuer), whether templates are overridden,
the tracked drafts, and a warning if insecure_dev_mode is on. Housekeeping
(expired sessions, enrolments and pending requests; retention purges) runs
inline and on a ten-minute tick.
keygen
Creates the keys file (mode 0600) with one active Ed25519 signing key and
the pairwise secret. On an existing file:
--rotateadds a new key and makes it active. Old keys stay in the file and their public halves stay in the JWKS, so tokens signed before rotation (they live at most an hour) keep verifying. Restartserveafterwards.--prune-days Nremoves keys older than N days from the file (and thus from the JWKS). Prune well after rotation, never the active key.- a file without a
pairwise_secretgets one. An existing secret is never changed by anything — it is what keeps every directedsubstable.
Key ids are ps- followed by a random suffix.
person add, person list, invite
person add --name NAME creates a person and prints a one-time enrolment
link on stdout (the explanation goes to stderr): opening it registers the
person’s first passkey. --ttl sets its validity in seconds (default 900).
It warns when the issuer host is an IP address, because the link will not
be able to create a passkey there.
invite --person ID mints another link for an existing person — someone
who lost every device, or who was created before passkeys were possible.
Each link is single-use and expires.
person list prints one line per person: id, display name, passkey count,
created at.
agents list, agents revoke
agents list prints every agent binding — agent iss and sub, the person
it is bound to, status, and when it was bound or revoked.
agents revoke ISS SUB does what the dashboard’s Revoke button does,
attributed to the CLI in the audit record: marks the binding revoked (the
agent cannot obtain new tokens; it must be approved by the person again to
come back), revokes the consents recorded for it, marks its live auth tokens
revoked, and POSTs a signed revocation to every service that received one.
Already-revoked bindings are reported as such and left alone.
pending list, pending approve, pending deny
For headless operation — a Person Server nobody is watching in a browser.
pending list prints every request waiting for a decision: id, kind
(person, auth, mission, mission_completion), agent, resource, who it
is for (or unbound for a new agent), and when it expires.
pending approve ID records the decision exactly as the person’s browser
would — binds the agent, records consent, mints the token, resolves the
pending request so the agent’s next poll returns it. Which person decides:
--person ID if given; otherwise the person the request is already claimed
by; otherwise, when exactly one person exists, that one (with several, the
command asks you to say). An agent actively bound to someone else is
refused — revoke that binding first. Missions are approved with the
configured default lifetime.
pending deny ID tells the agent no; nothing is issued or remembered.
Both are audited with "via": "cli" so the record distinguishes an
operator’s decision from the person’s own.
example-config, version
example-config prints the annotated starting config.
version prints the version and the draft revisions this build tracks:
psd 0.1.0 (tracking AAuth Internet-Drafts: draft-hardt-oauth-aauth-protocol-11, draft-hardt-httpbis-signature-key-08)