# Plan: retire `oibot-agent` from the Tobserver change workflow ## Status Implementation is in progress. - 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. - The new configuration has not been activated, the Agent Skills PR has not been merged, 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`). ## 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/ \ -o 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.