feat: source Pi skills from agent catalog
This commit is contained in:
parent
087cab63de
commit
7aa6e5b0b2
5 changed files with 267 additions and 14 deletions
215
docs/plans/retire-oibot-agent.md
Normal file
215
docs/plans/retire-oibot-agent.md
Normal file
|
|
@ -0,0 +1,215 @@
|
||||||
|
# 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/<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.
|
||||||
23
flake.lock
generated
23
flake.lock
generated
|
|
@ -1,19 +1,20 @@
|
||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"anthropic-skills": {
|
"agent-skills": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1784256457,
|
"lastModified": 1784899453,
|
||||||
"narHash": "sha256-QZ+zJkyLd/42rxgtJEZSUOz9R75Tse6UXW7G0nOkFS8=",
|
"narHash": "sha256-/tMA9LQkVClOOXREW4oeXhq9PzyEUK9RIo3GrfLl2SI=",
|
||||||
"owner": "anthropics",
|
"ref": "agent/tobserver-personal-agit",
|
||||||
"repo": "skills",
|
"rev": "ce0f775ccb125ea34b604e282496da18cea7c061",
|
||||||
"rev": "fa0fa64bdc967915dc8399e803be67759e1e62b8",
|
"revCount": 3,
|
||||||
"type": "github"
|
"type": "git",
|
||||||
|
"url": "https://codeberg.org/oibot/agent-skills.git"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "anthropics",
|
"ref": "agent/tobserver-personal-agit",
|
||||||
"repo": "skills",
|
"type": "git",
|
||||||
"type": "github"
|
"url": "https://codeberg.org/oibot/agent-skills.git"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bun2nix": {
|
"bun2nix": {
|
||||||
|
|
@ -309,7 +310,7 @@
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"anthropic-skills": "anthropic-skills",
|
"agent-skills": "agent-skills",
|
||||||
"darwin": "darwin",
|
"darwin": "darwin",
|
||||||
"emacsConfig": "emacsConfig",
|
"emacsConfig": "emacsConfig",
|
||||||
"hermes-agent": "hermes-agent",
|
"hermes-agent": "hermes-agent",
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@
|
||||||
|
|
||||||
hermes-agent.url = "github:NousResearch/hermes-agent";
|
hermes-agent.url = "github:NousResearch/hermes-agent";
|
||||||
|
|
||||||
anthropic-skills = {
|
agent-skills = {
|
||||||
url = "github:anthropics/skills";
|
url = "git+https://codeberg.org/oibot/agent-skills.git?ref=agent/tobserver-personal-agit";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
let
|
let
|
||||||
piFirecrawl = pkgs.callPackage ../pkgs/pi-firecrawl.nix { };
|
piFirecrawl = pkgs.callPackage ../pkgs/pi-firecrawl.nix { };
|
||||||
|
tobserverAgent = pkgs.callPackage ../pkgs/tobserver-agent.nix {
|
||||||
|
script = inputs.agent-skills + "/tobserver-change/scripts/tobserver-agent";
|
||||||
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
home.file.".clojure/deps.edn".source = ../config/clojure/deps.edn;
|
home.file.".clojure/deps.edn".source = ../config/clojure/deps.edn;
|
||||||
|
|
@ -59,6 +62,7 @@ in
|
||||||
sops
|
sops
|
||||||
tree
|
tree
|
||||||
typescript
|
typescript
|
||||||
|
tobserverAgent
|
||||||
wget
|
wget
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -102,7 +106,8 @@ in
|
||||||
pi.coding-agent = {
|
pi.coding-agent = {
|
||||||
enable = true;
|
enable = true;
|
||||||
skills = [
|
skills = [
|
||||||
(inputs.anthropic-skills + "/skills/skill-creator")
|
(inputs.agent-skills + "/create-skill")
|
||||||
|
(inputs.agent-skills + "/tobserver-change")
|
||||||
];
|
];
|
||||||
environment = {
|
environment = {
|
||||||
FIRECRAWL_API_KEY.file = config.sops.secrets.firecrawl_api_key.path;
|
FIRECRAWL_API_KEY.file = config.sops.secrets.firecrawl_api_key.path;
|
||||||
|
|
|
||||||
32
pkgs/tobserver-agent.nix
Normal file
32
pkgs/tobserver-agent.nix
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
{ script
|
||||||
|
, coreutils
|
||||||
|
, curl
|
||||||
|
, findutils
|
||||||
|
, git
|
||||||
|
, gitleaks
|
||||||
|
, gnused
|
||||||
|
, jq
|
||||||
|
, nix
|
||||||
|
, nixpkgs-fmt
|
||||||
|
, openssh
|
||||||
|
, writeShellApplication
|
||||||
|
}:
|
||||||
|
|
||||||
|
writeShellApplication {
|
||||||
|
name = "tobserver-agent";
|
||||||
|
|
||||||
|
runtimeInputs = [
|
||||||
|
coreutils
|
||||||
|
curl
|
||||||
|
findutils
|
||||||
|
git
|
||||||
|
gitleaks
|
||||||
|
gnused
|
||||||
|
jq
|
||||||
|
nix
|
||||||
|
nixpkgs-fmt
|
||||||
|
openssh
|
||||||
|
];
|
||||||
|
|
||||||
|
text = builtins.readFile script;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue