Identities for entities did.bot
agent llm did
didbot plan cli.md
7.7 kB
Markdown
at main


id: cli title: One didbot command, and a binary for each place the code runs status: shipped crates: [didbot-cli, didbot-dispatch, didbot-operator, didbot-agentd] dependsOn: [] exitCriterion: > didbot <verb> runs the verb's binary from PATH with argv and no credential inherited from the shell; a first-party verb whose binary is absent names what to install; didbot --list shows every installed didbot-* with the version it reports; and the verb binaries parse, exit and render errors by didbot-cli's conventions. #

cli #

A person types didbot. What runs is one binary per place the code runs, each versioned and installed on its own:

Ships Runs where Verbs
didbot-pds the server, in the image its own flags; no verb reaches it
didbot operator laptop, agent host dispatcher only: --list, --version, help <verb>
didbot-operator operator laptop didbot operate <name> [<operator>] [--server <hostname>] [--kind K] [--oidc <issuer> <claim>=<value>...] [--fingerprint SHA256:...] [--creates [K...]] [--creates-beneath [K...]], didbot operate --check <name>, didbot login, didbot estop, didbot announce
didbot-oauth agent host didbot oauth pending, didbot oauth show, didbot oauth approve, didbot oauth decline, each with --token-file <path> or --token-stdin
didbot-register the machine that will be the account didbot register <kind> <name> [--under <parent>] [--token-file <path> | --token-stdin] [--server <hostname>] [--timeout <seconds>], the server from --server or DIDBOT_PDS
didbot-agentd agent host, a service none; a daemon the unit starts

Three install sets follow from the table. An operator installs didbot and didbot-operator. An agent host installs didbot and didbot-agentd, which ships didbot-oauth and didbot-register beside the daemon. A developer builds the workspace and reaches everything through scripts/.

This epic is about the entry point, not what the verbs do. Each verb has its own epic; this one says how a person reaches it.

Four rules #

The dispatcher passes argv and nothing else. didbot <verb> … execs the verb's binary with the remaining arguments. It adds nothing to the environment and, before the exec, removes every variable in didbot_cli::env::CREDENTIALS. Each verb authenticates for itself: didbot-operator with its own session files, didbot-oauth over the daemon's socket. A program on PATH that a typo on didbot- can reach therefore inherits no credential from the shell, and neither does a first-party verb — which is why didbot-oauth's daemonless mode, the one the environment configures, is reached by running that binary by name.

Each binary is independently versioned and self-describing. Every didbot-* answers --version with <name> <version> and --help on stdout. didbot --list scans PATH for didbot-*, asks each, and prints name, version and path; a binary that does not answer is listed with ?. Skew is visible and never fatal. didbot help <verb> runs the verb's own --help.

Shared conventions live in one library crate, didbot-cli. clap parsing through didbot_cli::parse, the --server <HOSTNAME> and --json flags, the exit statuses — 0 did it, 1 refused or failed, 2 did not understand — and didbot_cli::finish, the one line a refusal is written as. First-party verbs use it so they look like one tool.

First-party verb names are known to the dispatcher even when their code is absent. didbot carries a table, didbot_dispatch::verbs::FIRST_PARTY: operate, login, estop and announce run didbot-operator <verb>; oauth runs didbot-oauth and register runs didbot-register, each with what followed. Every row names the crate that ships its binary, so a first-party verb whose binary is not on PATH answers "install didbot-operator" or "install didbot-agentd" and exits 1. Any other word is external dispatch: didbot foo runs didbot-foo from PATH with argv passed through, and when there is none answers "unknown command foo; didbot --list shows what is installed" and exits 2. The table is the mechanism; there are no links between binaries.

Two credentials in one binary, kept apart #

didbot-operator holds two sign-ins. operate is the claim: it authenticates to the operator's own atproto account through jacquard-oauth and writes bot.did.operator into their own repository, keeping that session in didbot-authstore's file. login starts the deployment's own sign-in and keeps the session the deployment minted, which estop, account and announce present. For a name beneath a server, operate writes the record with the first and presents the second to the server's create. One is checked by the operator's PDS, the other by the deployment.

didbot register and the daemon hold a third thing that is not a credential at all: a key that never leaves the machine. The server sees its public half, and tokens it signs.

Done #