# Agent integration: the machine carries its own manual for AI hands Approved direction (2026-08-25 interview): three Claude-Code skills, delivery approach A (per-skill symlinks under a real `~/.claude/skills`), a ledger-backed `panama test --safe`, and `panama contracts `. Factual content only — Gabriel's personal preferences stay in his own CLAUDE.md and are out of scope. Everything the skills claim is contract-pinned, because an agent believes the manual verbatim. ## Decisions log | Decision | Choice | |---|---| | Audience | Claude Code skills; no AGENTS.md (YAGNI until another tool is in use) | | Skill count | Three: `panama` (develop), `panama-desktop` (operate), `panama-sudo` (privilege) | | Gating | Shipped to every machine, un-gated; personal content stays gated as today | | Dev-skill home | In-repo `.claude/skills/panama/` (project-level, auto-discovered in the checkout) | | Global delivery | Approach A: real `~/.claude/skills` dir + per-skill symlinks; new `linkdir` manifest kind for personal skills | | CLI expansion | Moderate: `panama contracts ` + `panama test --safe`; `doctor` already speaks JSON | | Test safety | `tests/desktop-hijacking` ledger + `--safe` flag + honesty contract | | Coverage lookup | Heuristic grep, tier-marked from the ledger, honest when empty | | Skill claims | Pinned by a new `skills-contract` | ## The three skills House format per `user/agents/skills/writing-for-agents/`: frontmatter is `name` + `description` only, H1 matches the name, ~100-column wrap, sibling files via relative links. The rule for all three: **point, don't duplicate**. A skill orients and warns; the facts live in the documents and commands the repo already maintains, so the rot surface is the pointer, not the prose. Skills are written by the orchestrator (not fanned out) — they are the heart of the feature and draw on session knowledge. ### `.claude/skills/panama/` — developing Panama (project-level) Discovered automatically for any session inside the checkout; needs no delivery machinery and works in forks. Description triggers on working in the Panama repo. Contents: 1. **Orientation** — one paragraph on what Panama is; pointers: `README.md` (layout, the `panama` command), `config/dot/hypr/README.md` (Lua-not-hyprlang, the one thing to know first), `config/dot/quickshell/modules/settings/README.md` (adding a setting, ownership, "things that will bite you", where state lives), `docs/settings.md` (generated reference). 2. **The live-desktop covenant** — the distilled never-list, each item one line with its source pointer: every save of `config/dot/quickshell/**` hot-reloads the live shell, so every save must leave valid QML; check the journal for errors AND "Unable to assign" after each batch (command form included); components in `modules/*` require same-save qmldir registration; never `qs kill` from a copied configuration; never `hyprctl keyword` — and `eval` exits 0 on error, so read back with `getoption`; no duplicate IPC targets; annotate every IPC parameter and return type; no continuously-repainting animations; batch compositor reloads and announce them; `readAs` describes the answer, not the setting; don't touch the hyprlang configs that never moved to Lua; no new notification daemon; scripts carry no `.sh` extension except `migrations/*.sh`; no secrets under `user/`. 3. **The contract discipline** — contracts live under `tests/`, run via `panama test [pattern]` or directly; run the covering contracts for what you touched (`panama contracts ` names them); during a desktop session run `panama test --safe` — the `tests/desktop-hijacking` ledger is the list of what it skips and why; regenerate `docs/settings.md` and the settings commands after schema/route changes (`panama-settings-docs`, `panama-settings-commands`, both `--check`-able); the README pins the contract count and subcommand list. 4. **Seams for testing** — fixture env vars (`PANAMA_*_HELPER`, `PANAMA_*_FIXTURE`, `PANAMA_*_STATIC_ONLY`), the harness discipline (distinct semantic entry file, `qs -p`, PID from `qs list --all`, kill only that PID), hermetic-by-construction helpers (validated inputs, JSON out, stdin-only secrets). 5. **Safety idioms** — ConfirmAction/ErrorRow/NotMeasuredRow/SettingsNote exist; destructive actions are two-stage; stored actions are data resolved through whitelists, never commands (`settings-idiom-contract`, `keybind-rebind-contract` pin these). ### `skills/panama-desktop/` — operating the desktop (global) For an agent doing *any* task on a Panama machine: how to drive the desktop honestly. Description triggers on desktop interaction (opening settings, checking system health, screenshots, notifications, audio/network/display questions) on a Panama machine. Contents: 1. `panama doctor` — JSON by default (`schemaVersion` 1), `--summary`, `check `, `--repair `; the 30 check ids by group. 2. `panama-action ` as the stable boundary for desktop actions (the verb list), and `qs ipc call ` beneath it for what `panama-action` doesn't cover — pointer to `shell.qml` for the target table rather than duplicating it. 3. Settings: open pages via `panama-action settings-page `; change values through the Settings UI or IPC, not by editing `~/.config/panama/settings.json` (the shell's in-memory model wins for keys it has touched); where state lives (the state-paths table pointer). 4. `panama-launch --class` for focus-or-launch; `panama test --safe` if asked to verify the desktop; `panama update` for keeping the machine current. 5. Privilege: one line — load `panama-sudo` before anything needing root. ### `skills/panama-sudo/` — privilege etiquette (global) Small. Description triggers on any need for root/sudo/pkexec on a Panama machine. Contents: never bare `sudo`/`pkexec`; use `panama-sudo --reason "why" -- cmd args`; `--reason` must be first; the reason appears beside (never instead of) polkitd's own action text; degrades to plain pkexec with no shell running; migrations already follow this rule (`bin/panama-migrate`). Include the one-line trust model so agents phrase reasons honestly: state what the command does, not why it is safe. ## Delivery: approach A ### New root `skills/` `skills/panama-desktop/SKILL.md`, `skills/panama-sudo/SKILL.md` (+ sibling files if needed). Repo-root `README.md` layout table gains the row (readme-contract pins the layout block). ### New stage `setup/scripts/link-skills` Un-gated. Behavior: 1. If `~/.claude/skills` is a symlink (today: → `user/agents/skills`), remove it (symlink removal never displaces to `config/old`, matching `link-user`'s rule) and `mkdir -p` a real directory. 2. For each child of `$PANAMA_PATH/skills/`, displace any existing real entry at `~/.claude/skills/` to `config/old/` (house `displace` semantics; symlinks just removed) and link `~/.claude/skills/` → `$PANAMA_PATH/skills/`. 3. Report `Agent skills: N linked.` `install` STAGES gains `link-skills` **after `link-dotfiles`, before `link-user`** (personal must win name collisions by linking last, mirroring Claude Code's personal-over-project precedence), in both the full list and `upgrade_stages`. `tests/setup/update-command-contract` pins STAGE_NAMES — its list gets the new entry as part of this work. ### `linkdir` manifest kind (link-user) `user/manifest` line `link agents/skills ~/.claude/skills` becomes `linkdir agents/skills ~/.claude/skills`: for each child of the source, displace and link it as a direct child of the destination (creating the destination as a real directory if needed). Whole-dir `link` entries (`~/.agents/skills`, CLAUDE.md, rules) are untouched. `user/README.md` documents the new kind. Known behavior, recorded not fixed: a personal skill named like a shipped one shadows it (deliberate — personal wins); a *new* personal skill needs a re-link (`panama update` or `setup/scripts/link-user`) to appear, where the old whole-dir link showed it instantly. ## CLI additions (`bin/panama`) House three-touchpoint rule: header comment, `usage()`, `main()` — plus the README subcommand list (readme-contract cross-checks it). ### `panama contracts ` Heuristic: resolve the argument to a repo-relative path; scan `tests/` (excluding `fixtures/`, `__pycache__`) for contracts whose text contains the path, any parent-trimmed suffix of it, or the basename. Output one line per hit: `tests/ [safe|desktop]`, tier read from the ledger. No hits → `No contract mentions — coverage may be indirect (a harness or a generated artifact); nothing verified.` and exit 1. No options. ### `panama test --safe [pattern]` `--safe` (position-independent, before or after the pattern): filter out every contract listed in `tests/desktop-hijacking`, run the rest exactly as today, and end the summary with `Skipped N desktop-hijacking contract(s) (tests/desktop-hijacking).` Plain `panama test` is unchanged. ## The ledger: `tests/desktop-hijacking` Package-list style: one repo-relative contract path per line, `#` comments; each entry's comment says what it does to the session (restarts the shell; latches caffeine; opens live overlays; writes every schema key against the real compositor; touches real xdg-mime defaults; …). Seeded from the tier-3 inventory in the exploration (focus-session-restart, focus-session-expiry, settings-window, overview-live-actions, switcher, welcome, cheatsheet, status-events, activity-*, accessibility, calendar-agenda, screen-intelligence, panama-action-ipc, panama-commands, panama-doctor, polkit-reason, signal-glass, settings-write-sweep, settings-system, default-apps-*, gnome-handoff — verified individually during the build, not copied blind). ## New contracts ### `tests/setup/skills-contract` 1. The two shipped skills and `.claude/skills/panama` exist with valid frontmatter (`name` matches the directory, non-empty `description`, nothing else required). 2. Claim pinning: every `` `panama ` `` subcommand a skill names exists in `bin/panama`'s dispatcher; every `` `panama-` `` exists in `bin/` or the quickshell scripts dir; every backticked repo path exists; every `PANAMA_*` env var it names appears somewhere in the tree; every `panama-action` verb it names is in `panama-action`'s dispatch. (Convention this imposes on skill prose: commands, paths and variables are always backticked and exact — which is how they should be written anyway.) 3. `link-skills` exists, is in STAGES and `upgrade_stages` ordered after `link-dotfiles` and before `link-user`; the manifest uses `linkdir` for `agents/skills`; `link-user` implements `linkdir`. ### `tests/setup/desktop-hijacking-contract` 1. Every ledger entry names an existing contract. 2. Honesty sweep: every contract under `tests/` that drives the live shell — matches `qs ipc call` without booting its own `qs -p` harness, or restarts `panama-quickshell.service`, or calls `qs kill` — must be listed; the sweep's heuristics live in this contract so a new hijacking contract cannot stay unlisted. 3. `cmd_test` honors the ledger: static check that `--safe` reads the file. README test count: +2 (the "N of them" line — orchestrator's, updated at the end). ## Build plan and ownership - **Orchestrator**: this spec; the three skills' content; final seam audit; README count. - **Agent A**: `bin/panama` (`cmd_contracts`, `--safe`), `tests/desktop-hijacking` (verifying each seeded entry by reading the contract), `tests/setup/desktop-hijacking-contract`, README subcommand-list rows. - **Agent B**: `setup/scripts/link-skills`, `linkdir` in `setup/scripts/link-user`, `user/manifest`, `user/README.md`, `install` STAGES + `upgrade_stages`, `tests/setup/skills-contract`, updates to `tests/setup/update-command-contract` and `tests/setup/user-content-contract` where their pins move, README layout row. Disjoint by construction; the skills (orchestrator) reference what A and B build, so the skills land last and `skills-contract` runs after both. ## Out of scope (recorded) Generic `AGENTS.md`; a Claude Code plugin; `panama map`/`agent` namespace; JSON output for `panama test`; shipping any of Gabriel's personal preferences; per-contract header annotations (the ledger supersedes); auto-relink on personal-skill creation.