# PRD 0053: User-defined agent provider plugins - **Status:** Active - **Author:** claude - **Created:** 2026-06-04 ## Summary The `get_provider()` registry in `bot_bottle/agent_provider.py` is a closed list — only `"claude"` and `"codex"` are valid templates, validated at manifest-load time and again at launch. Users who want to run a different agent (Gemini, Aider, a custom local model wrapper) cannot add a provider without forking the package. This PRD opens the registry to user-defined plugins. A plugin placed at `~/.bot-bottle/contrib//` is discovered and loaded at launch time. The manifest accepts any non-empty template string that names a built-in or resolves to a user plugin at that path. Alongside discovery, this PRD moves CA and git provisioning out of the Docker backend and into the `AgentProvider` ABC as overridable methods. The current standalone `provision/ca.py` and `provision/git.py` files in the Docker backend are deleted; their logic becomes the default implementations on the ABC. This lets exotic provider images (different base OS, different user, non-standard trust mechanism) override provisioning freely without the abstraction fighting them. The preceding commit on this PR moves `codex_auth.py` from `bot_bottle/` into `bot_bottle/contrib/codex/` — a clean-up that fits naturally here since this PR also clarifies that `contrib/` is the per-provider home. ## Problem Users building unconventional setups hit a hard wall: the template validation in `manifest_agent.AgentProvider.from_dict` rejects any string not in `PROVIDER_TEMPLATES`. There is no escape hatch short of editing bot-bottle's source. PRD 0050 moved provider logic into `contrib/` specifically so a third provider would be "cheap to add" — but "cheap" today still means a pull request against the bot-bottle repo, not a drop-in file in the user's home directory. The filesystem layout is already the right shape; the discovery step is missing. Beyond discovery, the Docker backend's `provision_ca` and `provision_git` functions bake in Debian-specific commands (`update-ca-certificates`) and a hardcoded container user (`node`). A user plugin that runs as a different user, or on a different base OS, silently gets the wrong provisioning with no way to correct it short of forking. ## Goals / Success Criteria 1. A user places `~/.bot-bottle/contrib//agent_provider.py` — a file that exports a class inheriting `AgentProvider` — sets `agent_provider.template: ` in a bottle's frontmatter, and launches a bottle using that provider with no changes to the bot-bottle source. 2. The plugin directory may also contain a `Dockerfile` at `~/.bot-bottle/contrib//Dockerfile`; the existing three-tier Dockerfile cascade (per-bottle override → manifest `dockerfile:` field → provider default) uses this path as the provider default for user plugins. 3. The manifest validator accepts any non-empty template string. Unknown templates that resolve to no user plugin still raise a clear error, but at launch (via `get_provider`) rather than at manifest-load time. 4. Built-in provider knobs (`auth_token` → claude only; `forward_host_credentials` → codex only) are guarded to built-in template names. Bottles using a user provider may set neither knob. 5. `get_provider(template)` checks `~/.bot-bottle/contrib/