dotfiles/docs/plans/retire-oibot-agent.md
2026-07-29 14:58:45 +07:00

222 lines
13 KiB
Markdown

# Superseded plan: retire `oibot-agent` from the Tobserver change workflow
## Status
Superseded on 2026-07-29 by the normal-clone workflow. Dotfiles no longer load
`tobserver-change` or package `tobserver-agent`; repository-owned instructions
and checks should govern future Tobserver work. The remaining document is kept
only as historical migration context and must not be followed as an active plan.
Before removing any legacy credentials or workspace, resolve the preserved
workspace recorded below explicitly.
- The standalone catalog skill is implemented on `agent/tobserver-personal-agit` at commit `ce0f775` and published as [oibot/agent-skills PR #1](https://codeberg.org/oibot/agent-skills/pulls/1).
- AGit creation and a second linear push were verified against the same pull request without a write API token.
- Dotfiles are prepared to pin that catalog revision, load `create-skill` and `tobserver-change` in Pi, and package the bundled helper as `tobserver-agent`; Nix evaluation and the Home Manager build pass.
- `~/.ssh/config` now selects `~/.ssh/id_ed25519` with `IdentitiesOnly yes` for normal Codeberg access and no longer auto-adds the bot key. Both aliases authenticate as their intended accounts.
- The new Nix configuration has not been activated, the Agent Skills PR has not been merged, the bot alias remains available for the active legacy workspace, and no bot credential has been revoked or deleted.
- Cutover is blocked until the user confirms Tobserver `main` protection in Codeberg and resolves or deliberately migrates the active legacy workspace at `/private/var/folders/5p/sj0yx8w92b51dzngrxn9gqz00000gn/T/tobserver-agent.d9wG9L` (`agent/add-bitcoin-pulse-module-wiring-20260723-130500-866d04`). Until then, resume it with `/nix/store/9fri785m3f5v0vy40n51ih55kcrywg4l-tobserver-agent/bin/tobserver-agent resume <workspace>` so a future profile switch cannot select the incompatible state-v2 helper.
## Goal
Use the personal Codeberg account `oibot` for Tobserver change branches while preserving a human-only merge boundary:
- `main` accepts changes only through pull requests;
- direct, force, and deletion pushes to `main` are denied, including for `oibot`;
- the agent can create and update pull requests without a write-capable Codeberg API token;
- a human merges through the Codeberg web UI;
- the agent never accesses or deploys to the live Tobserver machine.
The trade-off is accepted: Codeberg will attribute both agent-created pull requests and human merges to `oibot`, so there is no account-level distinction or independently enforceable approval by a second user.
## Repository and distribution decision
The personal-only workflow will be implemented as a self-contained skill in the separate Agent Skills catalog rather than maintained as local skill and script copies in dotfiles.
- The canonical skill directory will be `~/Code/agent-skills/tobserver-change/`.
- The directory will contain `SKILL.md`, the `tobserver-agent` helper under `scripts/`, routing and execution evals, focused helper tests, and every reference or asset required to install, operate, validate, and recover the workflow.
- The helper script will have one canonical source in the skill directory. Dotfiles may package or wrap that bundled script to expose `tobserver-agent` on `PATH`, but must not retain a second editable copy.
- The completed Agent Skills change will be pushed as an `oibot` branch and reviewed through a pull request in `oibot/agent-skills`; do not push directly to protected `main`.
- Dotfiles will add the Agent Skills repository as a pinned, non-flake input and configure Pi to load both `create-skill` and `tobserver-change` from that input.
- The local `config/pi/skills/tobserver-change` copy and the upstream `anthropic-skills`/`skill-creator` input will be removed after Pi successfully loads the catalog's `tobserver-change` and `create-skill` skills.
- `flake.lock` will pin the reviewed Agent Skills revision so a future catalog push cannot silently change Pi's active instructions or helper.
- Existing local helper and skill files remain available during migration and are removed only after the catalog-backed installation passes local and end-to-end validation.
The intended order is: build and evaluate the standalone catalog skill, publish and review it, pin it in dotfiles, verify Pi and the packaged helper, complete the personal-only AGit cutover, and only then revoke or remove `oibot-agent` credentials.
## Security invariants
1. Protect `main` before changing credentials or helper behavior.
2. Do not place `oibot` on a direct-push or branch-protection bypass list.
3. Do not expose an `oibot` API token capable of merging pull requests or changing repository settings to the helper or agent.
4. Keep the existing workspace, branch-prefix, validation, secret, no-force-push, no-merge, and no-deployment checks.
5. Keep the current bot credentials available for rollback until the personal-only workflow completes an end-to-end test.
6. Do not delete keys, tokens, open pull requests, or active workspaces automatically.
## Preconditions and decisions
- [x] Confirm that independent Codeberg attribution and approval are no longer requirements.
- [x] Confirm that human merging will happen only in the Codeberg web UI.
- [x] Inspect existing open `oibot-agent` pull requests; the public API returned none.
- [x] Check `tobserver-agent status` and preserve the active legacy workspace recorded above.
- [x] Establish an isolated Agent Skills branch and preserve existing dotfiles commits and owner work.
## Phase 1: enforce the server-side merge boundary
In `oibot/Tobserver` repository settings, configure an exact protection rule for `main`:
- [ ] deny direct pushes for everyone, including repository owners;
- [ ] deny force pushes;
- [ ] deny branch deletion;
- [ ] require changes to arrive through pull requests;
- [ ] retain applicable status-check and conversation-resolution requirements;
- [ ] ensure there is no `oibot` push or bypass exception.
Verify the saved rule in the Codeberg UI. Do not probe Tobserver by attempting a push that could succeed if the rule is wrong. If a push-level test is desired, reproduce the rule in a disposable repository first.
**Gate:** do not continue until the UI confirms that `oibot` cannot directly update `main`.
## Phase 2: prove a tokenless pull-request path
Use Forgejo AGit over SSH so pull requests can be created without an API write token:
```sh
git push origin HEAD:refs/for/main/<topic> \
-o title="<title>" \
-o description="<description>"
```
Before refactoring the helper:
- [ ] confirm `oibot` authenticates through `git@codeberg.org` with the personal SSH key;
- [ ] confirm the public Codeberg API exposes the pull-request metadata needed by `revise` without authentication;
- [ ] determine the exact AGit representation of the topic, head ref, and pull-request URL;
- [ ] determine a robust multiline Markdown description encoding supported by Codeberg;
- [ ] create a clearly labeled AGit test pull request from an empty commit so it has no tree changes;
- [ ] push a second linear empty commit with the same topic and verify that it updates the same pull request without force-pushing;
- [ ] close the test pull request manually in Codeberg.
Do not merge the test pull request.
**Gate:** if AGit creation, URL discovery, or linear revision cannot be made reliable without a write-capable personal API token, stop and reconsider the account-removal design.
## Phase 3: refactor `tobserver-agent`
Target file: `~/Code/agent-skills/tobserver-change/scripts/tobserver-agent`
### Identity and credentials
- [ ] change the push URL from `git@codeberg-tobserver-agent:oibot/Tobserver.git` to the normal personal Codeberg SSH endpoint;
- [ ] retain an informational agent-specific commit author name;
- [ ] replace the bot noreply email with an agreed `oibot`-compatible address;
- [ ] remove bot Keychain account/service constants;
- [ ] remove write-token loading and temporary authorization-header handling;
- [ ] use unauthenticated HTTPS only for public read operations.
### Pull-request creation
- [ ] replace API `POST /pulls` creation with one AGit push;
- [ ] generate a unique, shell-safe AGit topic tied to the existing `agent/*` branch/workspace identity;
- [ ] pass the validated title and Markdown body without unsafe quoting, truncation, or accidental shell interpretation;
- [ ] capture and validate the returned pull-request URL under `https://codeberg.org/oibot/Tobserver/pulls/`;
- [ ] preserve the workspace when AGit submission or URL discovery fails.
### Pull-request revision
- [ ] replace the `oibot-agent` author assertion with checks appropriate to the new model: canonical repository, open state, `main` base, expected AGit topic/head, and helper-compatible history;
- [ ] fetch revision metadata without a write-capable token;
- [ ] push additional commits using the same AGit topic;
- [ ] preserve normal fast-forward/linear updates and continue to forbid force-push;
- [ ] verify that updating a pull request cannot create a duplicate PR silently.
### Existing safety checks
Retain and regression-test:
- [ ] helper-created temporary workspaces only;
- [ ] exact canonical fetch and push endpoints;
- [ ] `agent/*` local branch naming;
- [ ] refusal to work on `main`;
- [ ] no SOPS payload changes or plaintext secret access;
- [ ] Nix formatting, flake evaluation, derivation evaluation, Git whitespace, and Gitleaks checks;
- [ ] no merge, deployment, live-server access, force-push, remote branch deletion, or automatic failed-workspace cleanup.
## Phase 4: update the Tobserver skill and evaluations
Target files:
- `~/Code/agent-skills/tobserver-change/SKILL.md`
- `~/Code/agent-skills/tobserver-change/evals/evals.json`
Changes:
- [ ] remove the dedicated-bot compatibility requirement;
- [ ] replace the bot SSH alias with the normal Codeberg SSH endpoint;
- [ ] describe protected `main` plus human web merge as the approval boundary;
- [ ] state that the helper must not use a write-capable Codeberg API token;
- [ ] replace bot-owned PR revision checks with canonical AGit topic/head checks;
- [ ] retain the `agent/*`, no-force-push, no-merge, no-deploy, and recoverability constraints;
- [ ] update eval expectations that currently require `oibot-agent` ownership;
- [ ] add or revise an eval covering rejection of direct `main` pushes and API-based merge attempts.
## Phase 5: validate locally
- [x] run `bash -n tobserver-change/scripts/tobserver-agent` from the Agent Skills repository;
- [x] run focused helper tests for branch/topic restrictions, AGit metadata, push-option encoding, URL validation, and revision matching;
- [ ] test failure paths with mocked Git/HTTP commands so failed submission preserves the workspace;
- [ ] run the repository's Nix checks without deploying or building a Tobserver system closure;
- [x] inspect the Agent Skills diff for credentials, token remnants, unrelated edits, and stale bot assumptions;
- [ ] rerun the `tobserver-change` routing and representative workflow evaluations.
## Phase 6: end-to-end cutover test
With bot credentials still intact for rollback:
1. [ ] create a fresh helper workspace;
2. [ ] make an empty or harmless non-system test commit;
3. [ ] run all helper checks;
4. [ ] submit through AGit as `oibot`;
5. [ ] verify that one PR targets `main` and no direct `main` update occurred;
6. [ ] revise the same PR with one additional linear commit;
7. [ ] verify that no duplicate PR or force-push occurred;
8. [ ] close the test PR manually without merging;
9. [ ] verify failed and interrupted workspaces remain resumable.
**Gate:** retire the bot only after the complete create-and-revise workflow passes.
## Phase 7: retire bot credentials
Perform these as explicit human-approved cleanup steps:
- [ ] remove `codeberg-tobserver-agent` from `~/.ssh/config`;
- [ ] unload `~/.ssh/oibot-agent` from `ssh-agent`;
- [ ] revoke the bot API token in Codeberg;
- [ ] remove the bot token from macOS Keychain;
- [ ] remove the bot SSH key from Codeberg;
- [ ] remove `oibot-agent` repository access;
- [ ] archive or delete the bot account only after confirming it owns no required issues, PRs, repositories, or audit artifacts;
- [ ] delete local bot key files only with separate explicit confirmation and after any desired backup.
Do not rewrite historical commits or pull requests merely to remove the bot name.
## Rollback
Until Phase 7:
1. restore the previous helper push URL and bot token path;
2. restore the skill's bot-identity requirements;
3. use the preserved bot SSH alias and token;
4. resume preserved helper workspaces rather than recreating changes;
5. keep `main` protection in place throughout rollback.
After bot credentials are revoked, rollback requires issuing a new constrained credential or restoring the bot account deliberately; do not weaken `main` protection as a shortcut.
## Completion criteria
- `oibot` cannot directly, forcibly, or destructively update `main`.
- The helper creates and linearly updates a single PR through SSH/AGit.
- The helper and agent have no write-capable Codeberg API token.
- Only a human web action merges a PR.
- All existing local checks and secret boundaries still pass.
- No live Tobserver access or deployment occurred.
- Bot credentials and access are removed only after successful cutover and explicit approval.