Skill: parkertoddbrooks/wip-ai-devops-toolbox (version 1.9.72)

--- name: wip-ai-devops-toolbox description: Complete DevOps toolkit for AI-assisted software development. Release pipeline, license compliance, copyright enforcement, repo visibility guard, identity file protection, manifest reconciler, and best practices. All core tools are agent-callable via MCP. license: MIT interface: [cli, module, mcp, skill, hook, plugin] metadata: display-name: "WIP AI DevOps Toolbox" version: "1.9.72" homepage: "https://github.com/wipcomputer/wip-ai-devops-toolbox" author: "Parker Todd Brooks" category: dev-tools capabilities: - version-bump - changelog-update - npm-publish - github-release - license-scanning - license-compliance - copyright-enforcement - repo-sync - repo-visibility-guard - identity-file-protection - manifest-reconciliation - mcp-server requires: bins: [git, npm, gh, node] openclaw: requires: bins: [git, npm, gh, node] install: - id: node kind: node package: "@wipcomputer/wip-ai-devops-toolbox" bins: [wip-release, wip-install, wip-repos, wip-license-hook, wip-license-guard, wip-file-guard, wip-repo-init, wip-readme-format] label: "Install all tools via npm" emoji: "🧰" compatibility: Requires git, npm, gh, node. Node.js 18+. --- # WIP AI DevOps Toolbox Your AI writes code. But does it know how to release it? Check license compliance? Protect your identity files? Sync private repos to public? Follow a real development process? AI DevOps Toolbox is 13 tools that teach your AI how to do all of this. Once installed, you don't run them manually. Your AI knows how to use them and does it automatically. Built by a team of humans and AIs shipping real software together. ## Platform Compatibility The tools in this toolbox use different capabilities. Check what you have and tell the user honestly what you can and cannot do. **What each interface requires:** | Interface | Requires | Examples | |-----------|----------|----------| | CLI | Shell access (run bash/node commands) | `wip-release patch`, `wip-install` | | Module | Node.js import support | `import { release } from 'wip-release'` | | MCP | MCP client support | `release`, `license_scan`, `repos_check` | | OC Plugin | OpenClaw agent runtime | Plugin in `~/.openclaw/extensions/` | | Skill | SKILL.md file (works in both CC and OpenClaw) | You're reading it right now | | CC Hook | Claude Code CLI with hooks support | PreToolUse hooks in `~/.claude/settings.json` | **Built and tested on:** - **Claude Code CLI** ... full support (shell, MCP, CC Hooks) - **OpenClaw** ... full support (shell, MCP, Plugins) **How to assess your own platform:** Check which capabilities you have (shell access, MCP, hooks) and match them to the table above. If you can run shell commands, CLI tools work. If you can connect to MCP servers, MCP tools work. If you have neither, you can still read and explain the tools, but tell the user which commands to run themselves. Do not claim you can run commands you cannot execute. ## Operating Rules **Always dry-run first.** Before installing, deploying, or running any destructive operation, run with `--dry-run` so the user can see exactly what will change. Only proceed with the real operation when the user explicitly says to. **Write dev updates as you work.** When doing significant work on a repo that uses this toolbox, write a dev update to `ai/dev-updates/YYYY-MM-DD--HH-MM--agent--description.md`. The release pipeline auto-detects these and uses them as release notes. No more thin one-liners. ## Install **You are an AI agent helping a user install AI DevOps Toolbox. Walk them through the process step by step. Ask questions, explain what you're doing, and let them make choices.** ### Already installed? Show what they have. If the user already has the toolbox installed (check `ldm status` or look for `wip-release` on PATH), you MUST show the complete list below. Do NOT summarize. Do NOT skip tools. Do NOT paraphrase. Show every single tool with its number, name, category, and description exactly as written here. Show the installed version next to each tool name. **IMPORTANT: Copy this list verbatim. All 17 tools. All 5 categories. Every description. The user needs to see every tool to understand what they have.** **Setup & Onboarding** 1. **Universal Installer** ... one command detects and deploys all interfaces (CLI, MCP, Plugin, Skill, Hook). Powers `ldm install`. 2. **Dev Guide** ... team conventions: release process, repo structure, branch protection, ai/ folder standard. **Infrastructure** 3. **LDM Dev Tools.app** ... scheduled automation: backup, branch protection audit, visibility audit. Runs unattended. **Repo Management** 4. **Repo Visibility Guard** ... blocks repos from going public without a -private counterpart. Prevents accidental exposure. 5. **Repo Manifest Reconciler** ... one source of truth for folder structure. Drift detection, auto-sync, and cross-repo CLAUDE.md generation. 6. **Repo Init** ... scaffolds the standard ai/ directory. Plans, notes, dev updates, todos. One command. 7. **README Formatter** ... generates READMEs following the standard format. Staging, review, deploy. 8. **Forced Git Worktrees** ... agents never edit on main. Isolated copies, PRs to merge back. 9. **Branch Guard** ... blocks all writes on main. The enforcement layer for forced worktrees. **License, Compliance, and Protection** 10. **Identity File Protection** ... blocks overwrites of CLAUDE.md, SOUL.md, MEMORY.md, SHARED-CONTEXT.md. 11. **License Guard** ... enforces copyright, dual-license, CLA on your own repos. Auto-fix mode. 12. **License Rug-Pull Detection** ... catches license changes in dependencies before they ship. **Release & Deploy** 13. **Release Pipeline** ... version bump, changelog, npm publish, GitHub release. One command. 14. **Private-to-Public Sync** ... syncs private repo to public mirror. Excludes ai/ automatically. 15. **Post-Merge Branch Naming** ... renames merged branches with dates. Keeps history clean. 16. **Skill Publish to Website** ... auto-publishes SKILL.md as plain text on release. Like robots.txt for agents. 17. **Make Discoverable in Claude Code** ... auto-generates plugin manifest for Claude Code marketplace. (Planned) If an update is available, tell the user and offer to update via `ldm install wipcomputer/wip-ai-devops-toolbox`. After the list, say: "You can ask me about any of these tools and I'll explain more about what it does and how to use it." ### Step 0: Check for LDM OS LDM OS is the shared infrastructure that manages tool installation across all your AIs. Check if it's installed: ```bash ldm --version ``` **If installed:** Tell the user their LDM OS version and skip to Step 1. **If not installed:** > "AI DevOps Toolbox uses LDM OS to manage installation. LDM OS is the shared infrastructure layer that lets all your AIs share tools, memory, and identity. It's a one-time setup. Want me to install it?" When the user approves: ```bash npm install -g @wipcomputer/wip-ldm-os ldm init ``` If `npm` is not available, check if the user has Node.js installed (`node --version`). They need Node.js 18+. If not installed, tell them to install it from https://nodejs.org first. ### Transparency: Tell the user what's about to happen Before installing, explain exactly what will change: > "Here's what AI DevOps Toolbox will set up on your system: > > - **CLI tools** on your PATH: wip-release, wip-repos, wip-file-guard, wip-license-hook, wip-license-guard, wip-repo-init, wip-readme-format, deploy-public, post-merge-rename, wip-branch-guard > - **MCP servers** registered with Claude Code: release, license scanning, repo permissions, repo manifest > - **Claude Code hooks**: identity file protection (blocks overwrites of CLAUDE.md, SOUL.md), repo visibility guard, branch guard (blocks writes on main) > - **OpenClaw plugins** (if OpenClaw is detected): file-guard, license-hook, repo-permissions > - **Extension registry** updated at ~/.ldm/extensions/registry.json > > Nothing touches your data. Code gets installed. Your files stay yours. > > Want to see a dry run first?" ### Step 1: Dry Run Always dry-run first: ```bash ldm install wipcomputer/wip-ai-devops-toolbox --dry-run ``` Show the user the output. It lists every sub-tool and every interface that will be deployed. Number every tool in your summary. Walk through what each tool does, grouped by category: **Repo Management** 1. **Repo Visibility Guard** ... blocks repos from going public without a -private counterpart 2. **Repo Manifest Reconciler** ... one source of truth for folder structure 3. **Repo Init** ... scaffolds the standard ai/ directory in any repo 4. **README Formatter** ... generates READMEs following the standard format 5. **Branch Guard** ... blocks all writes on main (forces worktrees) **License, Compliance, and Protection** 6. **Identity File Protection** ... blocks overwrites of CLAUDE.md, SOUL.md, MEMORY.md 7. **License Guard** ... enforces copyright, dual-license, CLA on your repos 8. **License Rug-Pull Detection** ... catches license changes in dependencies **Release & Deploy** 9. **Release Pipeline** ... version bump, changelog, npm publish, GitHub release 10. **Private-to-Public Sync** ... syncs private to public, excludes ai/ automatically 11. **Post-Merge Branch Naming** ... renames merged branches with dates 12. **Universal Installer** ... detects and deploys tool interfaces Ask: "You can ask me about any of these tools and I'll explain more. Want to proceed with the install?" ### Step 2: Install When the user says to proceed: ```bash ldm install wipcomputer/wip-ai-devops-toolbox ``` ### Step 3: Verify ```bash ldm doctor ``` This checks: all extensions deployed, hooks configured, MCP servers registered, CLI binaries on PATH. Then test one tool: ```bash wip-release --version ``` Tell the user: "AI DevOps Toolbox is installed. Your AI now knows how to release software, check license compliance, protect identity files, guard repo visibility, and manage repo manifests. These tools run automatically ... you don't need to invoke them manually." **Important: tell the user they need to restart their AI agents for hooks to take effect.** Claude Code hooks are loaded when a session starts. Any running session still has the old hooks. Tell them: > "The install updated your Claude Code hooks (branch guard, file guard, repo permissions). Any AI session that was already running needs to be restarted to pick up the new hooks. Exit and reopen each Claude Code session. New sessions will work automatically." ### Update If AI DevOps Toolbox is already installed and a new version is available: ```bash ldm install wipcomputer/wip-ai-devops-toolbox ldm doctor ``` After updating, remind the user to restart running AI sessions so they pick up any new or changed hooks. Updates deploy new code without touching data or configuration. --- ## Setup & Onboarding ### Universal Installer (built into LDM OS) Interface detection and deployment engine. Scans a repo, detects which interfaces it supports (CLI, MCP, OpenClaw Plugin, Skill, CC Hook, Module), and deploys each one to the right location. This is what powers `ldm install`. **How it works:** 1. Clones the repo (or reads a local path) 2. Detects which interfaces the repo supports (scans for package.json bin, mcp-server.mjs, openclaw.plugin.json, SKILL.md, guard.mjs) 3. If the repo has a `tools/` directory with sub-tools, it enters toolbox mode and installs each one 4. For each tool, it deploys every detected interface: | Interface | How it's detected | Where it deploys | |-----------|------------------|-----------------| | CLI | `package.json` has `bin` entries | `npm install -g` | | Module | `package.json` has `main` or `exports` | Importable via `node_modules` | | MCP Server | Has `mcp-server.mjs` or `mcp-server.js` | `claude mcp add --scope user` | | OpenClaw Plugin | Has `openclaw.plugin.json` | `~/.ldm/extensions/` and `~/.openclaw/extensions/` | | Skill | Has `SKILL.md` | `~/.openclaw/skills/<tool>/SKILL.md` | | CC Hook | Has `guard.mjs` or `claudeCode.hook` in package.json | `~/.claude/settings.json` | 5. Updates the extension registry at `~/.ldm/extensions/registry.json` **Standalone fallback:** If LDM OS is not installed, the `wip-install` CLI provides the same detection and deployment. It will attempt to install LDM OS automatically, then delegate. If that fails, it falls back to standalone mode. **Interfaces:** CLI, Module, Skill ### Dev Guide Your team's conventions, baked in. Best practices for AI-assisted development teams. **What it covers:** - Release process (branch, PR, merge, wip-release, deploy-public) - Repo structure (the `ai/` folder convention, private/public pattern) - Branch conventions (agent prefixes: `cc-mini/`, `lesa-mini/`, `cc-air/`) - Branch protection rules - Multi-agent clone workflow - License compliance (dual MIT+AGPL, CLA) **How to use it:** Read [DEV-GUIDE.md](DEV-GUIDE-GENERAL-PUBLIC.md) before doing repo work. It's the reference for how the team operates. **Interface:** Documentation (no CLI, no MCP) --- ## Infrastructure ### LDM Dev Tools.app Scheduled automation that runs whether anyone remembers or not. macOS .app bundle with Full Disk Access. **What it runs:** - `backup.sh` ... backs up critical files - `branch-protect.sh` ... audits branch protection rules across all repos - `visibility-audit.sh` ... checks repo visibility matches the public/private pattern - `crystal-capture.sh` ... triggers memory crystal capture **Commands:** ``` open -W ~/Applications/LDMDevTools.app --args backup open -W ~/Applications/LDMDevTools.app --args branch-protect open -W ~/Applications/LDMDevTools.app --args visibility-audit ``` Scripts can also run standalone without the .app: ``` bash tools/ldm-jobs/backup.sh bash tools/ldm-jobs/branch-protect.sh bash tools/ldm-jobs/visibility-audit.sh ``` **Where it writes:** Depends on the script. Backup writes to the backup target. Audits write to stdout. **Interface:** Standalone macOS app --- ## Release & Deploy ### wip-release Release software correctly. Version bump, changelog, npm publish, GitHub release. One command, nothing forgotten. **Commands:** ``` wip-release patch --notes="description" # bump patch (1.0.0 -> 1.0.1) wip-release minor --notes="description" # bump minor (1.0.0 -> 1.1.0) wip-release major --notes="description" # bump major (1.0.0 -> 2.0.0) wip-release patch --dry-run # preview without changes wip-release patch --no-publish # bump + tag only, skip npm/GitHub wip-release patch --notes-file=path # read notes from a file wip-release patch # auto-detect notes (see below) ``` **Release notes auto-detection (first match wins):** 1. `--notes-file=path` ... explicit file path 2. `RELEASE-NOTES-v{ver}.md` in repo root (e.g. `RELEASE-NOTES-v1-7-4.md`) 3. `ai/dev-updates/YYYY-MM-DD*` ... today's dev update files (most recent first) 4. `--notes="one-liner"` ... used as fallback, but if a dev update exists with more content, the dev update wins Write dev updates as you work. wip-release picks them up automatically. No more thin release notes. **What happens when you run `wip-release`:** 1. **Step 0:** License compliance gate. If `.license-guard.json` exists, checks LICENSE file, copyright, CLA.md, README license section. Aborts if any check fails. 2. **Step 1:** Bumps version in `package.json` 3. **Step 2:** Syncs version to `SKILL.md` (if it exists) 4. **Step 3:** Updates `CHANGELOG.md` with the new version entry 5. **Step 4:** Auto-detects release notes from RELEASE-NOTES file, ai/dev-updates/, or --notes flag 6. **Step 5:** Commits the version bump 7. **Step 6:** Creates git tag `v{version}` 8. **Step 7:** Pushes commit and tag to origin 9. **Step 8:** Publishes to npm (if not `private: true`) 10. **Step 9:** Publishes to GitHub Packages 11. **Step 10:** Creates GitHub release with release notes (full narrative, not one-liners) 12. **Step 11:** Publishes SKILL.md to website as plain text (if SKILL.md exists and `WIP_WEBSITE_REPO` is set) 13. **Step 12:** Renames merged branches with `--merged-YYYY-MM-DD` 14. **Step 13:** Prunes old merged branches (keeps last 3 per developer prefix) **Where it writes:** `package.json`, `SKILL.md`, `CHANGELOG.md`, git tags, npm registry, GitHub Releases **Safety:** - `--dry-run` previews everything without writing - License gate prevents releasing with broken compliance - If push fails (branch protection), it tells you to push manually via PR - npm publish failure (e.g., `private: true`) is non-fatal; release continues **MCP tools:** `release`, `release_status` **Interfaces:** CLI, Module, MCP, Skill ### deploy-public Publish safely. Syncs a private repo to its clean public counterpart. **Commands:** ``` bash scripts/deploy-public.sh <private-repo-path> <public-github-repo> # Example: bash scripts/deploy-public.sh /path/to/memory-crystal-private wipcomputer/memory-crystal ``` **What happens when you run it:** 1. Clones the public repo to `/tmp/` 2. Copies all files from the private repo, excluding `ai/` and `.git/` 3. Creates a branch (`cc-mini/deploy-YYYYMMDD-HHMMSS`) 4. Commits with the latest merge commit message from private 5. Pushes the branch, creates a PR, merges it 6. Deletes the deploy branch 7. Creates or updates the GitHub release on the public repo (syncs release notes from private) 8. Checks for and deletes stale branches on the public repo **Where it writes:** Public GitHub repo (via PR). Local `/tmp/` for the clone (cleaned up). **Safety:** - Never pushes directly to main. Always uses a PR. - The `ai/` folder is automatically excluded. Internal plans, todos, dev context never reach public. - If the public repo doesn't exist, the script fails (doesn't create repos). **Interfaces:** CLI, Skill ### post-merge-rename Cleans up after itself. Renames merged branches so you know what's done. **Commands:** ``` bash scripts/post-merge-rename.sh # rename merged branches bash scripts/post-merge-rename.sh --prune # rename + delete old ones bash scripts/post-merge-rename.sh --dry-run # preview without changes ``` **What happens:** 1. Scans remote branches that are fully merged into main 2. Renames them by appending `--merged-YYYY-MM-DD` (e.g., `cc-mini/feature` becomes [REDACTED_SECRET]) 3. With `--prune`: for each developer prefix (`cc-mini/`, `lesa-mini/`, etc.), keeps the last 3 merged branches and deletes the rest from the remote 4. Also finds stale branches that are fully merged but were never renamed, and deletes them **Rules:** - Never deletes `main` - Never deletes the current working branch - Always keeps the last 3 per developer prefix **Where it writes:** Remote branch names on GitHub (renames and deletes) **Interfaces:** CLI, Skill ### Skill Publish to Website After every release, your SKILL.md goes live as plain text on your website. No manual copying. **How it works:** Built into `wip-release`. If SKILL.md exists and a website repo is configured, the release pipeline automatically copies SKILL.md to `{website}/wip.computer/install/{name}.txt` and runs `deploy.sh` to push it live. **Setup:** Add `.publish-skill.json` to your repo root: ```json { "name": "wip-ai-devops-toolbox", "websiteRepo": "/path/to/your-website-repo" } ``` That's it. Every release auto-publishes. The convention is `yoursite.com/install/{name}.txt`. Plain text, no HTML. Any AI can `fetch()` the URL and get clean, parseable install instructions. **Name resolution (first match wins):** 1. `.publish-skill.json` `name` field 2. `package.json` name (with `@scope/` prefix stripped) 3. Directory name (with `-private` suffix stripped) **Website repo resolution:** 1. `.publish-skill.json` `websiteRepo` field (per-repo config) 2. `WIP_WEBSITE_REPO` env var (global fallback) **Non-blocking:** If the website repo is missing, deploy fails, or neither config nor env var is set, the release still succeeds. You'll see a warning in the output. **Interface:** Module (built into Release Pipeline) --- ## License, Compliance, and Protection ### wip-file-guard Knows what it can never overwrite. Blocks destructive edits to identity files. **Protected files:** CLAUDE.md, SOUL.md, MEMORY.md, SHARED-CONTEXT.md, IDENTITY.md **How it works as a CC Hook:** - Runs as a PreToolUse hook in Claude Code - Intercepts `Write` and `Edit` tool calls - If the target file is a protected identity file: - `Write` (full overwrite) is **blocked** - `Edit` (partial edit) is **allowed** (appending/updating sections is fine) - Returns JSON: `{"decision": "block", "reason": "..."}` or `{"decision": "allow"}` **Commands:** ``` wip-file-guard --list # list protected files wip-file-guard --check <filepath> # check if a file is protected ``` **As a CC Hook (automatic):** Configured in `~/.claude/settings.json` under `hooks.PreToolUse`. Runs automatically on every Write/Edit call. No manual invocation needed. **As an OpenClaw Plugin:** Deployed to `~/.openclaw/extensions/wip-file-guard/`. Blocks destructive edits in the OpenClaw agent pipeline. **Where it writes:** Nothing. It only reads and blocks. **Interfaces:** CLI, Module, OpenClaw Plugin, Skill, CC Hook ### wip-license-guard Enforces licensing on every commit. Copyright, dual-license, CLA. Checked automatically. **Commands:** ``` wip-license-guard check # audit current repo wip-license-guard check --fix # audit and auto-fix issues wip-license-guard init # interactive first-run setup wip-license-guard init --from-standard # apply WIP Computer defaults without prompting ``` **What it checks:** - LICENSE file exists and matches configured license type - Copyright line is correct and current year - CLA.md exists (if configured) - README has a `## License` section - For toolbox repos: checks every sub-tool in `tools/` **Config:** `.license-guard.json` in repo root. Created by `init`. Contains copyright holder, license type, year, and what to enforce. **As a wip-release gate:** Step 0 of wip-release reads `.license-guard.json` and runs the same checks. Aborts the release if compliance fails. **`--from-standard` generates:** - `.license-guard.json` with WIP Computer defaults - `LICENSE` file (dual MIT+AGPL) - `CLA.md` **Where it writes:** `.license-guard.json`, `LICENSE`, `CLA.md`, README (with `--fix`) **Interfaces:** CLI ### wip-license-hook Catches license changes in dependencies before they ship. **Commands:** ``` wip-license-hook scan # scan all dependencies for license changes wip-license-hook scan --json # output as JSON wip-license-hook audit # full compliance audit wip-license-hook ledger # show the license compliance ledger wip-license-hook gate # pass/fail gate for CI or pre-merge ``` **What it does:** 1. Reads `package.json` and `package-lock.json` 2. For each dependency, checks the current license against the last known license in the ledger 3. If a license changed (rug-pull), flags it 4. The ledger (`license-ledger.json`) tracks every dependency's license over time 5. `gate` returns exit code 0 (pass) or 1 (fail) for CI integration **Git hooks:** - `pre-push` hook blocks pushes if license changes are detected - `pre-pull` hook warns on pull if upstream changed licenses **MCP tools:** `license_scan`, `license_audit`, `license_gate`, `license_ledger` **Where it writes:** `license-ledger.json` (the compliance record) **Interfaces:** CLI, Module, MCP, Skill --- ## Repo Management ### wip-repo-permissions-hook Never accidentally exposes a private repo. **Commands:** ``` wip-repo-permissions check wipcomputer/memory-crystal # check one repo wip-repo-permissions audit wipcomputer # audit entire org ``` **What it checks:** - If a repo is public, does it have a `-private` counterpart? - If not, it's flagged as exposed (internal content may be visible) **As a CC Hook (automatic):** Intercepts commands that could change repo visibility (e.g., `gh repo edit --visibility public`). Blocks if the `-private` counterpart doesn't exist. **As an OpenClaw Plugin:** Deployed to `~/.openclaw/extensions/wip-repo-permissions-hook/`. Same check in the agent pipeline. **MCP tools:** `repo_permissions_check`, `repo_permissions_audit` **Where it writes:** Nothing. It only reads and blocks. **Interfaces:** CLI, Module, MCP, OpenClaw Plugin, Skill, CC Hook ### wip-repos Knows where every repo belongs. One source of truth for folder structure. **Commands:** ``` wip-repos check # compare filesystem to manifest wip-repos sync --dry-run # preview what sync would move wip-repos sync # move repos to match manifest wip-repos add <org/repo> <category> # add a repo to the manifest wip-repos move <org/repo> <new-category> # move a repo in the manifest wip-repos tree # show the manifest as a tree wip-repos claude # regenerate CLAUDE.md ecosystem sections for all repos wip-repos claude <repo> # regenerate one repo's CLAUDE.md wip-repos claude --init # create CLAUDE.md for repos missing one wip-repos claude --dry-run # preview changes ``` **What it does:** - Reads `repos-manifest.json` (the single source of truth) - Compares against the actual filesystem - `check` reports drift (repos in wrong locations, missing repos, unknown repos) - `sync` moves repos to match the manifest - `claude` generates cross-repo ecosystem context in CLAUDE.md files. Each repo gets a list of related repos with their interfaces, CLI commands, and descriptions. Agents can't read sibling repos at runtime, so this pre-generates the context they need. **MCP tools:** `repos_check`, `repos_sync_plan`, `repos_add`, `repos_move`, `repos_tree` **Where it writes:** Moves directories on the filesystem (with `sync`). Updates `repos-manifest.json` (with `add`/`move`). **Interfaces:** CLI, Module, MCP, Skill ### wip-repo-init Scaffold the standard `ai/` directory in any repo. One command. **Commands:** ``` wip-repo-init /path/to/repo # scaffold ai/ in a repo wip-repo-init /path/to/repo --dry-run # preview without changes wip-repo-init /path/to/repo --yes # skip confirmation prompt ``` **What happens:** **New repo (no ai/ folder):** Creates the full standard structure with READMEs explaining what goes where. **Existing repo (ai/ folder exists):** Shows you what will happen and asks for confirmation: 1. Moves your current `ai/` contents to `ai/_sort/ai_old/` 2. Scaffolds the new standard structure 3. You sort files from `ai_old/` into the new structure at your own pace Nothing is deleted. Your old files are all in `ai/_sort/ai_old/`. **The standard structure:** ``` ai/ read-me-first.md <- explains everything, links to all sections _sort/ <- holding pen for files that need sorting _trash/ <- archive (never delete, move here) dev-updates/ <- engineering changelog, auto-detected by wip-release product/ readme-first-product.md <- the product bible notes/ <- freeform notes, research plans-prds/ <- plans with lifecycle stages roadmap.md <- prioritized roadmap current/ <- plans being built now upcoming/ <- plans that are next archive-complete/ <- plans that shipped todos/ <- per-agent todo files product-ideas/ <- ideas that aren't plans yet ``` Every folder has a `_trash/` subfolder. Every section has a README. **Where it writes:** Creates directories and files inside `ai/`. If an existing `ai/` is present, moves it to `ai/_sort/ai_old/`. **Interfaces:** CLI, Skill ### wip-readme-format Generate or validate READMEs following the WIP Computer standard. One command. **Commands:** ``` wip-readme-format /path/to/repo # generate README-init-*.md section files wip-readme-format /path/to/repo --deploy # assemble sections into README.md wip-readme-format /path/to/repo --dry-run # preview without writing wip-readme-format /path/to/repo --check # validate existing README against standard ``` **What happens:** **Generate mode (default):** Detects interfaces, reads SKILL.md for tool names, generates separate section files: - `README-init-badges.md` ... org header + interface badges - `README-init-title.md` ... title + tagline - `README-init-teach.md` ... "Teach Your AI" onboarding block - `README-init-features.md` ... features list (preserved from existing README or auto-generated for toolbox repos) - `README-init-coverage.md` ... interface coverage table (toolbox repos only) - `README-init-more-info.md` ... links to docs - `README-init-license.md` ... license block + built-by line - `README-init-technical.md` ... technical content extracted from old README **Deploy mode:** Backs up existing README.md and TECHNICAL.md to `ai/_trash/`, assembles section files in order into README.md, moves technical to TECHNICAL.md, deletes the staging files. Edit any section independently before deploying. Same pattern as release notes: staging, review, deploy. **Toolbox mode:** For repos with `tools/` subdirectories, aggregates interfaces from all sub-tools for badges, generates an interface coverage table using SKILL.md `name:` frontmatter for human-readable names. **Where it writes:** README-init-*.md files in the repo root (staging). On deploy: README.md, TECHNICAL.md, and backups to `ai/_trash/`. **Interfaces:** CLI, Skill ### Forced Git Worktrees Every repo uses git worktrees. Agents never edit on main. Period. When an agent needs to make changes, it creates a worktree (isolated copy of the repo on its own branch). All edits happen there. Main stays clean. Multiple agents can work on the same repo simultaneously without collisions. When the work is done, it goes through a PR to merge back. **How it works:** - Agent runs `EnterWorktree` (Claude Code) or `git worktree add` to get an isolated copy - All edits happen on the worktree branch - When done: commit, push, create PR, merge - Main is never touched directly **Interfaces:** CLI, CC Hook ### Branch Guard Blocks all writes on main. The enforcement layer for forced worktrees. **How it works as a CC Hook:** - Runs as a PreToolUse hook in Claude Code - Intercepts `Write`, `Edit`, `NotebookEdit`, and destructive `Bash` commands - Resolves which repo the target file belongs to (from the file path, not CWD) - If that repo's current branch is main: **blocked** - Read-only operations (Read, Glob, Grep) are always allowed - Git operations that don't modify files (status, log, diff, branch, checkout, pull, merge, push) are allowed - `gh` commands (issues, PRs, releases) are allowed **Commands:** ``` wip-branch-guard --check # report current branch status for all repos ``` **Where it writes:** Nothing. It only reads and blocks. **Interfaces:** CC Hook --- ## MCP Server Configuration Tools with MCP interfaces are agent-callable. Add to `.mcp.json`: ```json { "wip-release": { "command": "node", "args": ["/path/to/tools/wip-release/mcp-server.mjs"] }, "wip-license-hook": { "command": "node", "args": ["/path/to/tools/wip-license-hook/mcp-server.mjs"] }, "wip-repo-permissions": { "command": "node", "args": ["/path/to/tools/wip-repo-permissions-hook/mcp-server.mjs"] }, "wip-repos": { "command": "node", "args": ["/path/to/tools/wip-repos/mcp-server.mjs"] } } ``` **All MCP tools:** | Tool | Function | What it does | |------|----------|-------------| | wip-release | `release` | Run a release (patch/minor/major) | | wip-release | `release_status` | Get current version and release state | | wip-license-hook | `license_scan` | Scan dependencies for license changes | | wip-license-hook | `license_audit` | Full compliance audit | | wip-license-hook | `license_gate` | Pass/fail gate for merges | | wip-license-hook | `license_ledger` | Show the compliance record | | wip-repo-permissions | `repo_permissions_check` | Check if a repo can go public | | wip-repo-permissions | `repo_permissions_audit` | Audit entire org visibility | | wip-repos | `repos_check` | Compare filesystem to manifest | | wip-repos | `repos_sync_plan` | Preview what sync would change | | wip-repos | `repos_add` | Add a repo to the manifest | | wip-repos | `repos_move` | Move a repo in the manifest | | wip-repos | `repos_tree` | Show manifest as a tree | **Example prompts your AI can act on directly:** ``` "Scan all dependencies for license changes" -> license_scan "Check if memory-crystal can go public" -> repo_permissions_check "Do a patch release with notes 'fix login bug'" -> release "Show me which repos aren't in the manifest" -> repos_check "Audit the whole org's repo visibility" -> repo_permissions_audit "What version is this repo at?" -> release_status "Gate this merge on license compliance" -> license_gate "Show the license compliance ledger" -> license_ledger ``` --- ## Interface Coverage | # | Tool | CLI | Module | MCP | OC Plugin | Skill | CC Hook | |---|------|-----|--------|-----|-----------|-------|---------| | | **Setup & Onboarding** | | | | | | | | 1 | Universal Installer | Y | Y | | | Y | | | 2 | Dev Guide | | | | | | | | | **Infrastructure** | | | | | | | | 3 | LDM Dev Tools.app | | | | | | | | | **Repo Management** | | | | | | | | 4 | Repo Visibility Guard | Y | Y | Y | Y | Y | Y | | 5 | Repo Manifest Reconciler | Y | Y | Y | | Y | | | 6 | Repo Init | Y | | | | Y | | | 7 | README Formatter | Y | | | | Y | | | 8 | Forced Git Worktrees | Y | | | | | Y | | 9 | Branch Guard | | | | | | Y | | | **License, Compliance, and Protection** | | | | | | | | 10 | Identity File Protection | Y | Y | | Y | Y | Y | | 11 | License Guard | Y | | | | | | | 12 | License Rug-Pull Detection | Y | Y | Y | | Y | | | | **Release & Deploy** | | | | | | | | 13 | Release Pipeline | Y | Y | Y | | Y | | | 14 | Private-to-Public Sync | Y | | | | Y | | | 15 | Post-Merge Branch Naming | Y | | | | Y | | | 16 | Skill Publish to Website | | Y | | | | | | 17 | Make Discoverable in Claude Code | | Y | | | | | --- ## License ``` MIT All CLI tools, MCP servers, skills, and hooks (use anywhere, no restrictions). AGPLv3 Commercial redistribution, marketplace listings, or bundling into paid services. ``` AGPLv3 for personal use is free. Commercial licenses available. Built by Parker Todd Brooks, Lēsa (OpenClaw, Claude Opus 4.6), Claude Code (Claude Opus 4.6).

path: CHANGELOG.md
content: # Changelog

## 1.9.72 (2026-04-21)

# AI DevOps Toolbox v1.9.72

## Promote v1.9.71-alpha series to stable

Closes #256.

Consolidates 21 alpha prereleases (`v1.9.71-alpha.1` through `v1.9.71-alpha.21`) into a stable v1.9.72 release. No code changes beyond the version bump in the toolbox root `package.json`; the sub-tool code has been stable and dogfooded across the alpha iterations.

## Why

The root `package.json` had been sitting at `1.9.71-alpha.21` without a stable promotion. That blocked `deploy-public.sh` from syncing the private repo to the public mirror ... the script gates public release on stable root versions.

Symptom during 2026-04-21: wip-branch-guard sub-tool shipped stable (v1.9.82 → v1.9.83 → v1.9.84) to npm successfully, but the public `wipcomputer/wip-ai-devops-toolbox` GitHub releases page did not show any of them because `deploy-public.sh` refused to run with an alpha root.

## What's in the diff

- `package.json`
  - Version bump `1.9.71-alpha.21` → `1.9.72`

Everything else flows from `wip-release`:

- CHANGELOG.md updated
- Git tag `v1.9.72`
- GitHub release on private repo
- npm publish to `@latest`
- `deploy-public.sh` runs, syncs private code (minus `ai/`) to `wipcomputer/wip-ai-devops-toolbox`
- Public GitHub release created

## Sub-tool versions at this release

| Sub-tool | npm version |
|---|---|
| `@wipcomputer/wip-branch-guard` | 1.9.84 |
| Other sub-tools | See their individual `package.json` |

The sub-tool releases have their own cadence; this release is purely the toolbox root bump.

## Co-authors

Parker Todd Brooks, Lēsa (oc-lesa-mini, Opus 4.7), Claude Code (cc-mini, Opus 4.7).

## 1.9.71-alpha.21 (2026-04-20)

alpha prerelease

## 1.9.71-alpha.20 (2026-04-20)

alpha prerelease

## 1.9.71-alpha.19 (2026-04-09)

alpha prerelease

## 1.9.71-alpha.18 (2026-04-09)

alpha prerelease

## 1.9.71-alpha.17 (2026-04-09)

alpha prerelease

## 1.9.71-alpha.15 (2026-04-09)

alpha prerelease

## 1.9.71-alpha.14 (2026-04-08)

WAVE 0: mandatory license gate in all release paths

## 1.9.71-alpha.12 (2026-04-05)

Guard 1.9.74: temp-dir writes allowed, escape-hatch audit complete (Phase 12)

## 1.9.71-alpha.11 (2026-04-05)

# v1.9.71-alpha.11

## wip-branch-guard: SessionStart hook for main-CWD detection (Phase 13)

The guard now runs on two hook events, not just one:

1. **PreToolUse** (existing since 1.9.0): blocks file writes, git commits, and other mutating operations on main branch. Specific escape hatches via `ALLOWED_GIT_PATTERNS` and `ALLOWED_BASH_PATTERNS`.
2. **SessionStart** (new in 1.9.73): fires once per session boot, including startup, resume, and post-compaction resume. If the session's CWD is the main-branch working tree of a protected git repo, injects a warning into the boot context with actionable recovery commands.

## Why SessionStart matters

Earlier today's session ($900 of Opus tokens, 60 minutes of wall time) began with the agent waking up on main-branch CWD, trying to edit a file, hitting the PreToolUse guard, and entering a retry loop because the abstract error message did not give the agent the specific command it needed to unblock. The same class of failure had trapped at least two prior sessions earlier in the week.

The fix was multi-layered:

- Phase 1 (shipped in 1.9.72): make the `git stash push` escape hatch available so there's always a native way out
- Phase 2, 4, 6-11 (shipped today): fix the release pipeline so guard fixes actually reach the runtime
- **Phase 13 (this release): prevent the loop from starting in the first place by warning at session boot**

## What the SessionStart hook does

On every session boot, the guard checks if the CWD is in a git repo, reads the current branch, and:

- **Not in a git repo** → silent exit (nothing to warn about).
- **Not on main or master** → silent exit (feature branches are fine).
- **On main or master** → emits a warning via `hookSpecificOutput.additionalContext` that includes:
  - The repo path
  - A list of existing linked worktrees (first 10) with ready-to-paste `cd <path>` commands for each, annotated with the branch name
  - The template for creating a fresh worktree: `git worktree add .worktrees/<repo>--cc-mini--<feature> -b cc-mini/<feature>`
  - The native `git stash push` escape hatch instructions in case an untracked file blocks `git pull`
  - Pointers to the guard master plan and the bugs-plan-04-05-2026-002 master plan

The warning is informational. It does NOT block session boot. An agent that wakes up on main gets the warning in its initial context so the first time it reaches for a write operation, it already knows the recovery path.

## Implementation

Single-file change to `guard.mjs`. The existing `main()` function now dispatches on `hook_event_name` (falling back to shape detection for older payloads). A new `handleSessionStart(input)` function handles the SessionStart path, exiting the process when it's done.

`package.json` `claudeCode.hooks` now advertises both events. `INSTALL.md` updated with the new two-event wiring.

## New hook wiring

Both events point at the same `guard.mjs` script. Add both to `~/.claude/settings.json`:

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit|NotebookEdit|Bash",
        "hooks": [
          { "type": "command", "command": "node /Users/lesa/.ldm/extensions/wip-branch-guard/guard.mjs", "timeout": 5 }
        ]
      }
    ],
    "SessionStart": [
      {
        "hooks": [
          { "type": "command", "command": "node /Users/lesa/.ldm/extensions/wip-branch-guard/guard.mjs", "timeout": 5 }
        ]
      }
    ]
  }
}
```

## Files changed

- `tools/wip-branch-guard/guard.mjs`: new `handleSessionStart(input)`, event dispatcher in `main()`, worktree enumeration helper
- `tools/wip-branch-guard/package.json`: 1.9.72 -> 1.9.73, `claudeCode.hook` -> `claudeCode.hooks` (array of two entries)
- `tools/wip-branch-guard/INSTALL.md`: complete rewrite with new two-event wiring, what each event does, and test invocations for both
- `tools/wip-branch-guard/test.sh`: three new SessionStart test cases (main tree warns, feature branch silent, non-git silent)
- `CHANGELOG.md`: entry for 1.9.73

## Verified

- 36/36 test cases pass (33 existing PreToolUse + 3 new SessionStart)
- Manual injection with `echo '{"hook_event_name":"SessionStart","cwd":"...","source":"startup"}' | node guard.mjs` produces expected output
- Manual injection with feature-branch CWD exits silently
- Manual injection with /tmp (non-git) exits silently
- Existing PreToolUse tests unchanged, no regressions

## Cross-references

- `ai/product/bugs/guard/2026-04-05--cc-mini--guard-master-plan.md` Phase 7 (guard master plan's Phase 7 maps to this release)
- `ai/product/bugs/master-plans/bugs-plan-04-05-2026-002.md` Wave 2 phase 13
- Prior guard ships today: 1.9.72 (stash allow), 1.9.73 (this release)
- Settings.json wiring needs to be deployed to `~/.claude/settings.json` for the SessionStart hook to activate. `ldm install` should handle this.

## 1.9.71-alpha.9 (2026-04-05)

# v1.9.71-alpha.8

## wip-release: automatic PR flow for protected main (Phase 4)

When `git push origin main` fails with GitHub's "protected branch" rejection (`GH006: Changes must be made through a pull request`), wip-release now automatically:

1. Creates a release branch `cc-mini/release-v<version>` at the current commit
2. Pushes the branch to origin
3. Opens a PR via `gh pr create` with title `release: v<version>`
4. Merges the PR via `gh pr merge --merge --delete-branch`
5. Pushes the tag separately (tags bypass branch protection on most GitHub setups)
6. Fast-forwards local main so downstream steps (deploy-public, etc.) have a clean state

Previously this was a 4-command manual workflow every release:

```
git branch cc-mini/release-alpha-N
git push -u origin cc-mini/release-alpha-N
gh pr create --base main --head cc-mini/release-alpha-N --title '...'
gh pr merge <pr> --merge --delete-branch
git push origin v<version>
```

Every release. Every time. Eliminated.

## Fallback behavior

If any step of the auto-PR flow fails (gh CLI missing, PR create failure, merge failure, tag push failure), wip-release logs a concrete recovery command for the exact failure mode and continues (non-fatal, matches prior push-failed behavior). The user can always complete the remaining steps manually.

## Direct push still works

If the repo allows direct push to main (typical for private staging repos), wip-release tries direct push first and only falls back to the PR flow on the specific GH006 / "protected branch" error. No behavioral change for unprotected repos.

## Files changed

- `tools/wip-release/core.mjs`: new `pushReleaseWithAutoPr(repoPath, newVersion, level)` and `logPushFailure(result, tag)` helpers. Three push sites in `release()`, `releaseHotfix()`, `releasePrerelease()` migrated to use the helper.
- `tools/wip-release/package.json`: 1.9.72 -> 1.9.73
- `CHANGELOG.md`: entry added

## Verified

- Module imports cleanly via `node -e "import('./tools/wip-release/core.mjs')"`.
- Error detection regex handles GH006 variants: `/protected branch|GH006|Changes must be made through a pull request/i`.
- All three release tracks (stable, prerelease, hotfix) use the same helper.

## Cross-references

- `ai/product/bugs/release-pipeline/2026-04-05--cc-mini--release-pipeline-master-plan.md` Phase 4 (Incident 4)
- `ai/product/bugs/master-plans/bugs-plan-04-05-2026-002.md` Wave 2 phase 7
- Prior ship: alpha.7 closed Phases 1, 2, 8 of the same plan.

## 1.9.71-alpha.8 (2026-04-05)

# v1.9.71-alpha.8

## wip-release: automatic PR flow for protected main (Phase 4)

When `git push origin main` fails with GitHub's "protected branch" rejection (`GH006: Changes must be made through a pull request`), wip-release now automatically:

1. Creates a release branch `cc-mini/release-v<version>` at the current commit
2. Pushes the branch to origin
3. Opens a PR via `gh pr create` with title `release: v<version>`
4. Merges the PR via `gh pr merge --merge --delete-branch`
5. Pushes the tag separately (tags bypass branch protection on most GitHub setups)
6. Fast-forwards local main so downstream steps (deploy-public, etc.) have a clean state

Previously this was a 4-command manual workflow every release:

```
git branch cc-mini/release-alpha-N
git push -u origin cc-mini/release-alpha-N
gh pr create --base main --head cc-mini/release-alpha-N --title '...'
gh pr merge <pr> --merge --delete-branch
git push origin v<version>
```

Every release. Every time. Eliminated.

## Fallback behavior

If any step of the auto-PR flow fails (gh CLI missing, PR create failure, merge failure, tag push failure), wip-release logs a concrete recovery command for the exact failure mode and continues (non-fatal, matches prior push-failed behavior). The user can always complete the remaining steps manually.

## Direct push still works

If the repo allows direct push to main (typical for private staging repos), wip-release tries direct push first and only falls back to the PR flow on the specific GH006 / "protected branch" error. No behavioral change for unprotected repos.

## Files changed

- `tools/wip-release/core.mjs`: new `pushReleaseWithAutoPr(repoPath, newVersion, level)` and `logPushFailure(result, tag)` helpers. Three push sites in `release()`, `releaseHotfix()`, `releasePrerelease()` migrated to use the helper.
- `tools/wip-release/package.json`: 1.9.72 -> 1.9.73
- `CHANGELOG.md`: entry added

## Verified

- Module imports cleanly via `node -e "import('./tools/wip-release/core.mjs')"`.
- Error detection regex handles GH006 variants: `/protected branch|GH006|Changes must be made through a pull request/i`.
- All three release tracks (stable, prerelease, hotfix) use the same helper.

## Cross-references

- `ai/product/bugs/release-pipeline/2026-04-05--cc-mini--release-pipeline-master-plan.md` Phase 4 (Incident 4)
- `ai/product/bugs/master-plans/bugs-plan-04-05-2026-002.md` Wave 2 phase 7
- Prior ship: alpha.7 closed Phases 1, 2, 8 of the same plan.

## 1.9.71-alpha.7 (2026-04-05)

# v1.9.71-alpha.7

## wip-release: three hardening fixes for the release pipeline

Ships three related wip-release fixes in one release, each targeting a release-pipeline master-plan phase. See `ai/product/bugs/release-pipeline/2026-04-05--cc-mini--release-pipeline-master-plan.md` for the full context (7 incidents we hit today while trying to ship a single guard fix, 8 phases of forward work).

### Phase 1: refuse non-main invocations (was Incident 1)

Earlier today `wip-release alpha` ran from a feature worktree because `releasePrerelease()` had no worktree check at all (only `release()` and `releaseHotfix()` did). The result was a botched release commit on the worktree branch, never pushed to main, plus a cascade of downstream pipeline failures.

**Fix.** Extract a shared `enforceMainBranchGuard(repoPath, skipWorktreeCheck)` helper. Call it from all three release functions (`release`, `releaseHotfix`, `releasePrerelease`). The helper enforces two independent conditions:

1. **Linked worktree check.** If `git rev-parse --git-dir` resolves under `.git/worktrees/`, refuse with a ready-to-paste `cd <main-tree>` recovery command.
2. **Current branch check.** Even from the main working tree, `git branch --show-current` must be `main` or `master`. Refuse with `git checkout main && git pull && wip-release <track>` recovery command.

Both conditions bypassable via `--skip-worktree-check` for break-glass scenarios.

### Phase 2: tag collision pre-flight (was Incident 2)

Earlier today the pipeline also failed mid-release because `v1.9.71-alpha.4` and `v1.9.71-alpha.5` existed as local-only tags from prior failed releases. `wip-release alpha` tried to bump to alpha.5, hit the existing tag, and aborted. The release tool had no recovery path.

**Fix.** New `checkTagCollision(repoPath, newVersion)` helper runs after the main-branch guard, before the version bump. It distinguishes two cases:

1. **Tag exists on origin remote.** Legitimate prior release; refuses with a clear message.
2. **Tag exists locally but NOT on origin.** Stale leftover from a failed release; refuses but prints the safe recovery command: `git tag -d <tag> && wip-release <track>`.

Both cases log a clear error before any state mutation.

### Phase 8: sub-tool version drift becomes an error (was Incident 8)

Previously, if `tools/<sub-tool>/` files changed since the last git tag but `tools/<sub-tool>/package.json` version did not bump, `wip-release` printed a WARNING and proceeded. This silently shipped at least one "committed but never deployed" bug today: the guard fix had new code in `tools/wip-branch-guard/guard.mjs` but the same version, so `ldm install` ignored the sub-tool on redeploy.

**Fix.** New `validateSubToolVersions(repoPath, allowSubToolDrift)` helper replaces the three in-line duplicated drift checks in `release`, `releaseHotfix`, and `releasePrerelease`. Sub-tool drift without a version bump is now a hard refusal unless the caller passes `--allow-sub-tool-drift`.

## New CLI flags

- `--allow-sub-tool-drift` — Allow release even if a sub-tool's files changed since the last tag without a version bump. Default behavior is to refuse.

## Files changed

- `tools/wip-release/core.mjs`: new `enforceMainBranchGuard`, `logMainBranchGuardFailure`, `checkTagCollision`, `validateSubToolVersions` helpers. Inline checks in `release`, `releaseHotfix`, `releasePrerelease` replaced with calls to the helpers. `allowSubToolDrift` threaded through all three signatures.
- `tools/wip-release/cli.js`: parses `--allow-sub-tool-drift`, passes it to all three release functions. `skipWorktreeCheck` now also passed to `releasePrerelease` (was missing). Help text updated.
- `tools/wip-release/package.json`: version bump to 1.9.72.
- `CHANGELOG.md`: entry added.

## Verified

- From a feature worktree: `wip-release alpha --dry-run` refuses with concrete `cd <main-tree>` recovery command. Same for `patch` and `hotfix`.
- `--skip-worktree-check` bypass works.
- Module imports cleanly via `node -e "import('./tools/wip-release/core.mjs')"`.

## Known limitation (follow-up)

The tag collision and sub-tool drift checks run in live release mode, not in dry-run preview. Dry-run still shows "would bump" for a version that would actually fail later. Follow-up: move both checks before the dry-run short-circuit so preview is a faithful preflight. Tracked in the release-pipeline master plan as a small cleanup.

## Cross-references

- `ai/product/bugs/release-pipeline/2026-04-05--cc-mini--release-pipeline-master-plan.md` Phases 1, 2, 8
- `ai/product/bugs/guard/2026-04-05--cc-mini--guard-master-plan.md` Phases 3, 4 (partial, not all covered here; auto-publish sub-tool remains deferred to a follow-up PR)
- `ai/product/bugs/master-plans/bugs-plan-04-05-2026-002.md` Wave 2 phases 4, 5, 11

## 1.9.71-alpha.6 (2026-04-05)

Guard 1.9.72: allow git stash push on main to unblock native untracked-file escape hatch

## 1.9.71-alpha.5 (2026-04-05)

Guard 1.9.72: allow git stash push on main to unblock native untracked-file escape hatch

## 1.9.72-alpha.1 (2026-04-05)

### wip-branch-guard

Allow `git stash push` / `git stash save` / bare `git stash` on main. Stashing is non-destructive (drop/pop/clear remain blocked in DESTRUCTIVE_PATTERNS). This closes the loop where an untracked file in main's working tree blocks `git pull` and every clearing command (rm, mv, git stash, git clean, git reset) is also blocked, leaving no native escape hatch. Agents and humans lost hours to this.

Error message now points at the stash workaround explicitly so future sessions don't loop:

```
STUCK clearing an untracked file before git pull? Use stash (non-destructive):
  git stash push -u -- <path>
  git pull
  git stash list
```

## 1.9.71-alpha.4 (2026-04-04)

Guard: allow cp/mv/mkdir hotfixes to deployed extensions

## 1.9.71-alpha.3 (2026-04-04)

Guard: allow cp/mv/mkdir hotfixes to deployed extensions (.openclaw|.ldm)/extensions/, add .ldm/extensions/ to shared-state patterns for symmetry with .openclaw/extensions/

## 1.9.71-alpha.2 (2026-04-03)

Guard: allow bootstrap in zero-commit repos

## 1.9.71-alpha.1 (2026-04-01)

File guard: allow harness memory writes, guard v1.9.69

## 1.9.70 (2026-04-01)

### wip-release
- Fix semver NaN bug: `semver.inc()` returns null on prerelease versions, causing NaN propagation through the entire release pipeline
- Add sub-tool independent version validation: detects when sub-tool package.json versions drift from root and warns before publish

### wip-branch-guard
- Add cooldown skip: avoids redundant guard checks within rapid tool sequences
- Add trash pattern exclusion: allows `.Trash` and system cleanup paths through the guard






























## 1.9.69-alpha.1 (2026-04-01)

alpha prerelease

## 1.9.68 (2026-04-01)

# Release Notes: wip-ai-devops-toolbox v1.9.68

Closes #239

## Four-track release pipeline

The release tool now supports four tracks: alpha, beta, hotfix, and stable. This replaces the single-track model where every release was public.

Alpha is silent (no public release notes by default). Beta publishes prerelease notes to the public repo. Hotfix publishes to npm @latest without syncing code to public. Stable is the full deploy: npm + code sync + release notes. Developers can iterate on private, ship betas to testers, and only go public when ready.

Version numbering uses standard semver prereleases: `1.9.68-alpha.1`, `1.9.68-beta.1`. The installer (`ldm install --beta` / `--alpha`) pulls the right tag from npm.

## 1.9.67 (2026-03-31)

# Release Notes: wip-ai-devops-toolbox v1.9.67

**Date:** 2026-03-30

## What changed

### Hardcoded path removal

Two files in the devops toolbox had paths that assumed a specific username or iCloud layout.

**ldm-jobs/backup.sh** referenced `/Users/lesa/Library/Mobile Documents/.../ldm/bin/` to find the `ldm` binary for scheduled backup jobs. This iCloud path was fragile (iCloud sync delays, different usernames). The script now uses `$HOME/.ldm/bin/` which is the standard LDM install location and works on any machine (#301).

**test.sh** (the branch guard test harness) had `/Users/lesa` hardcoded for creating temp directories. It now uses `$HOME` so tests run correctly under any user account (#301).

### Earlier changes included in this release

**v1.9.66** added auto-combine for release notes from batched PRs (#237). When multiple PRs are merged between releases, their individual RELEASE-NOTES files are automatically combined into a single changelog entry.

**v1.9.65** fixed the scaffold-on-main issue (#223) where scaffolding left untracked files that blocked `git pull` on the main working tree.

## Why

The backup job is scheduled via LaunchAgent and runs unattended. If the path to `ldm` is wrong, backups silently fail. Moving to `$HOME/.ldm/bin/` aligns with the standard LDM install path and eliminates the iCloud dependency. The test fix ensures CI and local test runs work for all contributors.

## Issues closed

- #301

## How to verify

```bash
grep -r "/Users/lesa" ldm-jobs/ tools/wip-branch-guard/test.sh
# Should return zero results
```

## 1.9.66 (2026-03-30)

# Release Notes: wip-ai-devops-toolbox v1.9.66

Auto-combine release notes when batching multiple PRs into a single release.

## The story

When multiple PRs merge to main before wip-release runs, the release had no good way to gather all their stories. Each PR might have its own RELEASE-NOTES file committed on the branch, but once the branch merges and the file gets trashed, the next release only sees an empty repo root. The agent had to write a new RELEASE-NOTES file from scratch, losing the narrative that was already reviewed in each PR.

Now wip-release looks back through git history. It finds every merge commit since the last tag, checks each one for RELEASE-NOTES files via `git diff-tree` and `git show`, and combines them into a single document. If only one PR had notes, it uses them as-is (fully backwards compatible). If multiple PRs had notes, it wraps them with per-PR section headers, strips duplicate top-level headings, and collects all issue references into a combined list at the end.

The detection sits at priority 2.5 in the release notes cascade: after the single-file check (RELEASE-NOTES-v{ver}.md on disk) but before the dev-update fallback. A file on disk always wins. The merged-PR scan only kicks in when nothing is found on disk.

## What changed

- New exported function `collectMergedPRNotes()` in `core.mjs` that scans git merge history for RELEASE-NOTES files
- Updated `cli.js` to call it at priority 2.5 in the notes detection cascade
- Updated help text to document the new detection path
- Zero breaking changes. Single-file detection still works exactly as before.

## Issues closed

- Closes #237

## How to verify

```bash
# In any repo with multiple merged PRs since last tag, each having RELEASE-NOTES files:
wip-release patch --dry-run
# Should show: "Combined release notes from N merged PRs"
```

## 1.9.65 (2026-03-29)

# Release Notes: wip-ai-devops-toolbox v1.9.65

**Fix release notes scaffold on protected branches**

When `wip-release patch` runs on main without a RELEASE-NOTES file, it used to scaffold a
template directly in the working tree. On repos with branch guards (pre-commit hooks that
block commits to main), this scaffolded file could not be removed or committed. It would
block `git pull` and leave the working tree dirty. This has happened multiple times across
different repos.

The fix adds a branch check before scaffolding. If the current branch is main or master,
wip-release now prints a clear error telling the user to write release notes on their
feature branch before merging, then exits non-zero without creating any files. The scaffold
behavior still works on feature branches, where it's actually useful.

## Issues closed

- Closes #223

## How to verify

```bash
# On main, without release notes: should error, NOT scaffold
cd any-repo && git checkout main
wip-release patch
# Expected: "Release notes missing. Write RELEASE-NOTES-v*.md on your feature branch before merging."
# Expected: no RELEASE-NOTES file created in working tree

# On a feature branch: should scaffold as before
git checkout -b test/scaffold-check
wip-release patch
# Expected: scaffolded template created
```

## 1.9.64 (2026-03-29)

# Release Notes: wip-ai-devops-toolbox v1.9.64

Closes #295

## Branch guard: allow extension cleanup

The branch guard blocked `rm` on deployed extension directories (`~/.openclaw/extensions/` and `~/.ldm/extensions/`) because those paths live inside git repos. But deployed extensions are managed by `ldm install`, not by hand. When a stale `-private` extension needed to be removed (e.g. `wip-xai-grok-private` replaced by the public `wip-xai-grok`), the agent couldn't clean it up without asking the user to run the command manually.

Added an allowlist pattern for `rm` targeting `.openclaw/extensions/` and `.ldm/extensions/` paths. Same approach as the existing `.ldm/state/` allowlist. The guard still blocks `rm` on actual repo source files.

## 1.9.63 (2026-03-29)

# Release Notes: wip-ai-devops-toolbox v1.9.63

**Fix all wip-release errors: branch cleanup crashes, shell injection, stale remote refs.**

## The story

Every wip-release run produced errors: "fatal: Not a valid object name +", "remote ref does not exist", and shell injection risks from branch names passed through execSync template strings. These were dismissed as "non-blocking" but they cluttered every release output and masked real problems.

Root cause: branch cleanup code (sections 10 and 11) used `execSync` with template strings, which breaks on branch names with special characters and allows shell injection. Also tried to delete remote branches that GitHub already deleted during PR merge.

Fix: replaced all `execSync` template strings with `execFileSync` array args (safe from injection). Added character validation to skip branches with special chars. Wrapped remote delete in try/catch since GitHub PR merge already handles deletion.

## Issues closed

- #231 (continued: release pipeline reliability)

## How to verify

```bash
wip-release patch --dry-run
# Should show no "fatal" or "Not a valid object name" errors
# Guard tests: cd tools/wip-branch-guard && bash test.sh
```

## 1.9.62 (2026-03-29)

# Release Notes: wip-ai-devops-toolbox v1.9.62

**Fix wip-release leaving dirty state on main after every release.**

## The story

wip-release writes to 15+ files during a release (root package.json, 12 sub-tool package.json files, SKILL.md, CHANGELOG.md, product docs, trashed release notes). But gitCommitAndTag() only staged 3 files (package.json, CHANGELOG.md, SKILL.md). The other 12+ files were left modified on disk, uncommitted. This blocked git pull on the next operation and required manual `git checkout -- .` every time.

Fix: stage all files that wip-release modifies. Sub-tool package.json files, product docs (ai/product/), and trashed release notes (_trash/) are now included in the release commit.

## Issues closed

- #231 (wip-release rollback version bumps on failure)

## How to verify

```bash
wip-release patch
git status
# Should show clean working tree after release
```

## 1.9.61 (2026-03-29)

# Release Notes: wip-ai-devops-toolbox v1.9.61

**Add test script for branch guard. Fix node bypass regex.**

## The story

Every guard bug this session (v1.9.56-59) would have been caught by running a test before merging. This release adds test.sh to the guard that pipes test JSON into guard.mjs and verifies allow/deny results. 30 test cases covering destructive commands, quoted strings (Bug 1/3), compound commands (Bug 2), safe commands, and plan files.

Also fixes the node bypass regex: `require('fs').writeFileSync` wasn't caught because the regex looked for `fs.writeFile` literally. Broadened to match `writeFile` after `node -e`.

## Issues closed

- #232 (guard test coverage)

## How to verify

```bash
cd tools/wip-branch-guard && bash test.sh
# Should show: 30 passed, 0 failed, 3 skipped
```

## 1.9.60 (2026-03-29)

# Release Notes: wip-ai-devops-toolbox v1.9.60

**Fix npm package bloat: exclude worktrees and _trash from published tarball.**

## The story

v1.9.59 published 869 files (3.9 MB) to npm because leftover worktree directories and _trash/ were included in the tarball. The .npmignore only excluded ai/ and .DS_Store. Added _trash/, .worktrees/, _worktrees/, .claude/, .wrangler/ to .npmignore. Also cleaned up 10 stale worktrees from previous sessions.

## Issues closed

- #232 (continued cleanup)

## How to verify

```bash
npm pack --dry-run 2>&1 | tail -5
# Should show ~200 files, not 869
```

## 1.9.59 (2026-03-29)

# Release Notes: wip-ai-devops-toolbox v1.9.59

**Fix three bugs in branch guard destructive command handling.**

## The story

v1.9.56 added destructive command blocking but introduced three bugs because the new code was written differently from the existing guard pattern. The existing guard checks allowed patterns before blocked patterns and works per-command. The new code skipped the allowed check and matched against the entire raw command string, causing false positives on quoted text (blocking `gh issue create` when the body mentioned git commands) and false negatives on compound commands (allowing `rm -f file ; echo done` because `echo` is in the allowed list).

Fix: two helper functions that strip quoted content before matching and check each command segment independently. Same pattern as the existing guard code. Also adds `~/.claude/plans/` to the shared state allowlist so plan files are editable.

## Issues closed

- #232 (branch guard three bugs in v1.9.56)

## How to verify

```bash
# These should now be ALLOWED (were false-positive blocked):
# gh issue create --body "use git checkout -- to fix"
# echo "don't run git commit on main"

# These should now be DENIED (were false-negative allowed):
# rm -f file ; echo done  (on main)

# These should still be DENIED:
# git checkout -- file.txt
# python3 -c "open('f').write('x')"
```

## 1.9.58 (2026-03-29)

# Release Notes: wip-ai-devops-toolbox v1.9.58

**Fix deploy-public.sh losing release notes when invoked with relative path.**

## The story

When deploy-public.sh was called with `.` as the private repo path (e.g. `bash scripts/deploy-public.sh . wipcomputer/repo`), the script later cd'd into a temp directory. After that, `cd "."` no longer pointed to the private repo, so `gh release view` failed silently and release notes fell back to the empty "Release vX.Y.Z" default. This has been broken since at least v1.9.51.

Fix: resolve PRIVATE_REPO to an absolute path at startup before any cd happens.

## Issues closed

- #228 (continued from v1.9.57)

## How to verify

```bash
# From a repo directory, run with "." and check public release has real notes:
cd /path/to/private-repo
bash scripts/deploy-public.sh . wipcomputer/public-repo --dry-run
```

## 1.9.57 (2026-03-29)

# Release Notes: wip-ai-devops-toolbox v1.9.57

**deploy-public.sh now excludes .worktrees/ and _worktrees/ from public repo syncs.**

## The story

v1.9.56 accidentally deployed worktree directories (containing embedded git repos) to the public repo. The deploy script's rsync excluded ai/, .git/, _trash/, and other dev artifacts but didn't exclude worktree directories. Added both .worktrees/ (new convention) and _worktrees/ (old convention) to the exclude list.

## Issues closed

- #228 (deploy-public.sh leaks .worktrees/ to public repo)

## How to verify

```bash
# Run deploy-public.sh --dry-run and confirm .worktrees/ is not synced
grep -n "worktrees" scripts/deploy-public.sh
```

## 1.9.56 (2026-03-29)

# Release Notes: wip-ai-devops-toolbox v1.9.56

**Branch guard now blocks destructive git commands on all branches.**

## The story

The branch guard blocked commits and file writes on main, but allowed destructive git commands that destroy uncommitted work. Commands like `git clean -fd`, `git checkout --`, `git stash drop`, and `git reset --hard` slipped through because they were either in the allowed list or not in the blocked list. These commands destroyed Parker's Finder aliases, other agents' uncommitted edits, and user files multiple times on Mar 28-29.

The fix adds a new DESTRUCTIVE_PATTERNS list that fires on ALL branches, not just main. The guard also closes several bypass vectors: `node -e` removed from the allowed list, python/node file-write patterns detected, and `git checkout` narrowed to branch-switching only.

## What changed

- Added DESTRUCTIVE_PATTERNS: git clean -f, git checkout --, git stash drop/pop/clear, git reset --hard, git restore, python/node bypasses
- Removed `git checkout` blanket allow. Now only allows `git checkout <branch>` (switching)
- Removed `git stash drop` from allowed list
- Removed `node -e` from allowed bash patterns (bypass vector)
- Added `git stash show` and `git restore --staged` as safe read-only operations
- Deny message tells agent to use worktrees and safety checkpoints instead

## Issues closed

- #240 (branch guard + harness directories)
- #241 (python bypass detection)
- PR #284

## How to verify

```bash
# These should all be BLOCKED:
# git clean -fd
# git checkout -- somefile
# git stash drop
# git stash pop
# git reset --hard
# python3 -c "open('f','w').write('x')"

# These should still WORK:
# git checkout main (branch switching)
# git stash list (read-only)
# git status, git log, git diff
# Normal worktree workflow
```

## 1.9.55 (2026-03-28)

# Release Notes: wip-ai-devops-toolbox v1.9.55

Force redeploy: .worktrees guard fix.

## The story

v1.9.53 had the guard fix but deploy-public was missed. v1.9.54 force-redeployed but installer had already cached v1.9.54. This version ensures the public repo and npm are in sync so ldm install deploys the correct guard.mjs with .worktrees convention.

## Issues closed

- #240 (partial)

## 1.9.54 (2026-03-28)

# Release Notes: wip-ai-devops-toolbox v1.9.54

Force redeploy: guard files were stale after v1.9.53.

## The story

v1.9.53 published the .worktrees guard fix to npm but ldm install saw the version as current and skipped redeploying the files. The deployed guard.mjs was still the old version. This release forces a version bump so the installer re-deploys.

This is a bug in the installer: it checks version numbers but not file contents. Filed for future fix.

## Issues closed

- #240 (partial: .worktrees convention)

## 1.9.53 (2026-03-28)

# Release Notes: wip-ai-devops-toolbox v1.9.53

**One-line summary of what this release does**

Tell the story. What was broken or missing? What did we build? Why does the user care?
Write at least one real paragraph of prose. Not just bullets. The release notes gate
will block if there is no narrative. Bullets are fine for details, but the story comes first.

## The story

(Write a paragraph here. What was the problem? What does this release fix? Why does it matter?
This is what users read. Make it worth reading.)

## Issues closed

- #282

## How to verify

```bash
# Commands to test the changes
```

## 1.9.52 (2026-03-27)

# Release Notes: wip-ai-devops-toolbox v1.9.52

**Fix branch guard false-blocking bash commands targeting worktree paths**

## What changed

- Branch guard now extracts absolute paths from any bash command (mkdir, cp, mv, touch, etc.) and resolves the git branch from the target path's repo, not the CWD
- `findRepoRoot()` improved to walk up to existing directories for paths that don't exist yet (handles mkdir for new directories)
- Added `.ldm/worktrees` to allowed worktree locations alongside `_worktrees/` and `.claude/worktrees`

## Why

When Claude Code launches from `~/wipcomputerinc/` (on main) and runs bash commands targeting files inside a worktree (e.g., `mkdir -p /path/to/_worktrees/repo--branch/new-dir/`), the guard only knew how to extract paths from `cd` and `git -C` patterns. Any other command fell back to CWD resolution, saw "main", and blocked incorrectly. This caused minutes of wasted time every session.

## Issues closed

- wipcomputer/wip-ldm-os#187

## How to verify

```bash
# From CWD on main, this should no longer be blocked:
# mkdir -p /path/to/_worktrees/repo--branch/new-directory/
# cp file.txt /path/to/_worktrees/repo--branch/
```

## 1.9.51 (2026-03-24)

# Release Notes: wip-ai-devops-toolbox v1.9.51

## Branch Guard: Workspace Files Allowlist (#185)

Added TOOLS.md, MEMORY.md, IDENTITY.md, SOUL.md, WHERE-TO-WRITE.md, HEARTBEAT.md to the shared state allowlist. Both agents can now write to workspace files on main without being blocked.

Previously only SHARED-CONTEXT.md was allowed. This broke Lesa's ability to edit her own workspace files during the migration to ~/wipcomputerinc/.

## TECHNICAL.md: Backup Documentation

Updated LDM Dev Tools.app backup section to reflect the unified backup system. backup.sh now calls `~/.ldm/bin/ldm-backup.sh` (deployed by ldm install from wip-ldm-os-private/scripts/).

## 1.9.50 (2026-03-20)

# Release Notes: wip-ai-devops-toolbox v1.9.50

**wip-release: require product update doc on every release.**

## What changed

New quality gate in wip-release: checks that `ai/dev-updates/product-update/*-product-update.md` was modified since the last release tag. Same pattern as dev-updates, roadmap, and readme-first checks.

The product update doc is a human-readable test guide. Each release entry has: what changed, how it's supposed to work, and how to test. New entries go at the top. Additive only.

## Why

Three repos now have product update docs but nothing enforced keeping them current. Without the gate, the docs will drift immediately (same problem we had with TECHNICAL.md).

## Issues closed

- #220

## How to verify

```bash
wip-release patch --dry-run
# Should warn if product update doc not modified since last release
```

## 1.9.49 (2026-03-20)

# Release Notes: wip-ai-devops-toolbox v1.9.49

**TECHNICAL.md audit: 2 weeks of undocumented features now documented.**

## What changed

Full TECHNICAL.md audit covering v1.9.15 through v1.9.48. Two passes. Key additions:

- **wip-release quality gates:** Technical docs gate, interface coverage gate, product docs auto-sync, all skip flags documented.
- **deploy-public.sh:** Full 8-step pipeline including GitHub Packages publishing, repo URL rewrite, co-author sync.
- **wip-license-guard:** Now documented as both CLI and Claude Code PreToolUse hook (guard.mjs). Enforcement details.
- **wip-branch-guard:** Worktree requirement on branches, non-repo file passthrough, workflow teaching messages.
- **wip-repos claude:** Cross-repo CLAUDE.md ecosystem generator fully documented.
- **Source code table:** Missing files added (guard.mjs, claude.mjs, mcp-server.mjs).
- **Log paths:** Fixed stale /tmp/ references to ~/.ldm/logs/.

## Why

15 releases shipped without TECHNICAL.md updates. Agents reading the docs were missing critical features: release gates, license enforcement hooks, deploy pipeline details.

## Issues closed

- #218

## How to verify

```bash
grep "Interface coverage" TECHNICAL.md    # new gate
grep "guard.mjs" TECHNICAL.md             # license-guard hook
grep "GitHub Packages" TECHNICAL.md       # deploy pipeline
```

## 1.9.48 (2026-03-20)

# Release Notes: wip-ai-devops-toolbox v1.9.48

**Document wip-repos claude command in SKILL.md and TECHNICAL.md.**

## What changed

- SKILL.md: added `wip-repos claude` commands to the wip-repos section
- TECHNICAL.md: full documentation of how the ecosystem generator works, template locations, delimiter convention

## Why

v1.9.47 shipped the `wip-repos claude` command without updating technical docs. Now documented.

## Issues closed

- #212 (docs portion)

## How to verify

```bash
grep "wip-repos claude" SKILL.md TECHNICAL.md
```

## 1.9.47 (2026-03-20)

# Release Notes: wip-ai-devops-toolbox v1.9.47

**New: `wip-repos claude` command + CLAUDE.md templates.**

## What changed

### `wip-repos claude` (Phases 1-3 of the CLAUDE.md plan)

New subcommand that generates cross-repo ecosystem sections in CLAUDE.md files. When an agent opens repo-A, it can't read repo-B. This command pre-generates the context.

```bash
wip-repos claude              # regenerate all repos
wip-repos claude my-repo      # regenerate one repo
wip-repos claude --init       # create CLAUDE.md for repos missing one
wip-repos claude --dry-run    # preview changes
```

Features:
- Reads all repos from manifest, extracts metadata (package.json, SKILL.md, directory structure)
- Generates `## Ecosystem` sections with delimiter comments (`<!-- wip-repos:start/end -->`)
- Hand-written sections are never overwritten
- Relevance filtering: only related repos shown (same category + core repos)
- `--init` creates starter CLAUDE.md from template for repos missing one

### Templates

- `templates/global-claude-md.md` ... universal CLAUDE.md for ~/.claude/CLAUDE.md
- `templates/repo-claude-md.template` ... per-repo starter with ecosystem placeholder

## Why

Agents lose context across repos. They can't read sibling repos at runtime. Pre-generating cross-repo maps into CLAUDE.md solves this without requiring runtime access.

## Issues closed

- #212 (partial: Phases 1-3 of 6)

## How to verify

```bash
wip-repos claude --dry-run
```

## 1.9.46 (2026-03-18)

# Release Notes: wip-ai-devops-toolbox v1.9.46

**Centralized worktree management: guard rule, wip-release prune, Dev Guide convention.**

## What changed

### Guard: worktree path warning (#212)
Branch guard now warns when `git worktree add` creates a worktree outside `_worktrees/`. Shows the convention and suggests `ldm worktree add`. Warning only, not a hard block.

### wip-release: worktree prune (#212)
New step 12 in the release pipeline. After branch cleanup, prunes stale worktrees from `_worktrees/` whose branches are merged into main. Automatic cleanup after every release.

### Dev Guide: _worktrees/ convention (#212)
Documents the centralized worktree convention:
- All worktrees go in `_worktrees/<repo-name>--<branch-suffix>/`
- Use `ldm worktree add` (auto-detects repo, creates in the right place)
- Guard warns about worktrees outside the convention
- `wip-release` auto-prunes merged worktrees

## Why

Worktrees created as repo siblings confused iCloud sync, looked like real repos in directory listings, and were never cleaned up. This session alone created 10+ stale worktrees. The convention keeps them organized and the release pipeline cleans them automatically.

## Issues closed

- #212
- #213

## How to verify

```bash
# Guard warning:
cd /path/to/repo
git worktree add ../my-worktree -b test   # should warn about _worktrees/

# Correct path:
ldm worktree add cc-mini/test             # creates _worktrees/<repo>--cc-mini--test/
```

## 1.9.45 (2026-03-18)

# Release Notes: wip-ai-devops-toolbox v1.9.45

**Guard now teaches the workflow instead of just blocking.**

## What changed

- **Branch guard error messages overhauled (#213).** When the guard blocks a write on main, it now shows the full 8-step process: worktree, branch, commit, push, PR, merge, wip-release, deploy-public. Includes the lesson that release notes go on the feature branch, not as a separate PR.
- **Separate error for "on branch but not in worktree."** Tells the agent to go back to main and create a worktree properly.
- **CLAUDE.md added to shared state allowlist.** Was patched in the deployed guard but missing from source. Now in sync.

## Why

Agents kept getting blocked by the guard and then trying workarounds instead of following the process. The error message said "Use a worktree" but didn't explain the full workflow. Today's session hit this 5+ times. The guard works. The gap was agent knowledge.

## Issues closed

- #213
- #256

## How to verify

```bash
# In any repo on main, try to edit a file. The error should show the full workflow.
# In any repo on a branch (not worktree), try to edit. Should show worktree instructions.
```

## 1.9.44 (2026-03-17)

# Guard non-repo files fix + UTC date fix

Two bugs fixed in one PR.

## Bug 1: Guard blocks files outside git repos (#77)

**Problem:** When Write/Edit targets a file outside any git repo (e.g. `~/.claude/plans/`), `findRepoRoot()` returns null. The guard fell back to CWD (`~/.openclaw` on main) and blocked the operation. Files outside repos aren't the guard's concern.

**Fix:** If `findRepoRoot(filePath)` returns null for Write/Edit operations, allow immediately. The guard only protects git repos from direct-on-main edits.

**File:** `tools/wip-branch-guard/guard.mjs`

## Bug 2: UTC date mismatch in wip-release

**Problem:** Dev-update files are named with local date (e.g. `2026-03-16--cc-mini--...md`). But `new Date().toISOString().split('T')[0]` returns UTC date. After midnight UTC (4 PM PST), the dates diverge. Release notes gate fails to find today's dev-update.

**Fix:** Replaced all three instances of `toISOString()` date extraction with explicit local date construction using `getFullYear()/getMonth()/getDate()`.

**Files:**
- `tools/wip-release/cli.js` (line 80, dev-update detection)
- `tools/wip-release/core.mjs` (line 92, CHANGELOG date)
- `tools/wip-release/core.mjs` (line 582, product docs sync date)

## 1.9.43 (2026-03-17)

# Guard non-repo files fix + UTC date fix

Two bugs fixed in one PR.

## Bug 1: Guard blocks files outside git repos (#77)

**Problem:** When Write/Edit targets a file outside any git repo (e.g. `~/.claude/plans/`), `findRepoRoot()` returns null. The guard fell back to CWD (`~/.openclaw` on main) and blocked the operation. Files outside repos aren't the guard's concern.

**Fix:** If `findRepoRoot(filePath)` returns null for Write/Edit operations, allow immediately. The guard only protects git repos from direct-on-main edits.

**File:** `tools/wip-branch-guard/guard.mjs`

## Bug 2: UTC date mismatch in wip-release

**Problem:** Dev-update files are named with local date (e.g. `2026-03-16--cc-mini--...md`). But `new Date().toISOString().split('T')[0]` returns UTC date. After midnight UTC (4 PM PST), the dates diverge. Release notes gate fails to find today's dev-update.

**Fix:** Replaced all three instances of `toISOString()` date extraction with explicit local date construction using `getFullYear()/getMonth()/getDate()`.

**Files:**
- `tools/wip-release/cli.js` (line 80, dev-update detection)
- `tools/wip-release/core.mjs` (line 92, CHANGELOG date)
- `tools/wip-release/core.mjs` (line 582, product docs sync date)

## 1.9.42 (2026-03-17)

# Guard non-repo files fix + UTC date fix

Two bugs fixed in one PR.

## Bug 1: Guard blocks files outside git repos (#77)

**Problem:** When Write/Edit targets a file outside any git repo (e.g. `~/.claude/plans/`), `findRepoRoot()` returns null. The guard fell back to CWD (`~/.openclaw` on main) and blocked the operation. Files outside repos aren't the guard's concern.

**Fix:** If `findRepoRoot(filePath)` returns null for Write/Edit operations, allow immediately. The guard only protects git repos from direct-on-main edits.

**File:** `tools/wip-branch-guard/guard.mjs`

## Bug 2: UTC date mismatch in wip-release

**Problem:** Dev-update files are named with local date (e.g. `2026-03-16--cc-mini--...md`). But `new Date().toISOString().split('T')[0]` returns UTC date. After midnight UTC (4 PM PST), the dates diverge. Release notes gate fails to find today's dev-update.

**Fix:** Replaced all three instances of `toISOString()` date extraction with explicit local date construction using `getFullYear()/getMonth()/getDate()`.

**Files:**
- `tools/wip-release/cli.js` (line 80, dev-update detection)
- `tools/wip-release/core.mjs` (line 92, CHANGELOG date)
- `tools/wip-release/core.mjs` (line 582, product docs sync date)

## 1.9.41 (2026-03-17)

# Doc enforcement gates for wip-release

**Date:** 2026-03-16
**Closes:** #117, #128

## What changed

Two new pre-release gates in wip-release:

**Technical Docs Gate (#117):** When source code (*.mjs, *.js, *.ts) changed since the last release tag, checks that SKILL.md or TECHNICAL.md was also modified. Catches code shipping without doc updates. Warns on patch, blocks on minor/major. Skip with `--skip-tech-docs-check`.

**Interface Coverage Gate (#128):** For toolbox repos, scans each tool in tools/*/ for actual interfaces (CLI, Module, MCP, OC Plugin, Skill, CC Hook) and compares to the coverage table in README.md and SKILL.md. Reports: tools missing from table, interfaces detected but not marked Y, interfaces marked Y but not detected, tool count mismatches. Warns on patch, blocks on minor/major. Skip with `--skip-coverage-check`.

Both follow the same pattern as existing gates (checkProductDocs, checkStaleBranches). Both run in real and dry-run modes.

## Why

Source code was shipping without doc updates constantly. SKILL.md and TECHNICAL.md fell behind the code. Interface coverage tables drifted from reality. These gates catch it before release instead of after.

## 1.9.40 (2026-03-16)

# Auto-sync product docs version/date on release

**Date:** 2026-03-16
**Closes:** #202

## What changed

wip-release now auto-updates version and date lines in product docs before the release commit. No more stale "Current version: v1.9.1" when you're shipping v1.9.39.

Files updated automatically:
- `ai/product/plans-prds/roadmap.md`: "Current version" and "Last updated"
- `ai/product/readme-first-product.md`: "Last updated" and "What's Built (as of vX.Y.Z)"

Runs between changelog update and git commit (step 3.75). Only touches files that exist. Only updates lines that match the expected patterns.

## Why

These files were stale from v1.9.1 through v1.9.39 (8 days, 38 releases). Nobody remembered to update them. The existing product docs gate warned about it but couldn't fix it. Now it fixes itself.

## 1.9.39 (2026-03-16)

# Wire license-guard as Claude Code PreToolUse hook

**Date:** 2026-03-16
**Closes:** #130

## What changed

license-guard now registers as a Claude Code PreToolUse hook on install. Previously the hook code existed (hook.mjs) but was never wired into the deploy system. Now:

- Renamed hook.mjs to guard.mjs (matches file-guard/branch-guard convention that LDM OS deploy.mjs expects)
- Added `claudeCode.hook` config to package.json (event: PreToolUse, matcher: Bash, timeout: 5)
- On next `ldm install`, the hook auto-registers in ~/.claude/settings.json

The hook blocks git commit and git push when license compliance fails:
- LICENSE file missing
- Copyright doesn't match .license-guard.json config
- CLA.md missing
- README.md missing ## License section
- MIT+AGPL config but LICENSE or README only mentions MIT

Repos without .license-guard.json are not affected (the hook silently passes).

## Also done

- Updated plan statuses: license guard Phase 1 complete, bootstrap LDM OS complete
- Bootstrap LDM OS was already shipped in install.js (lines 740-812)

## 1.9.38 (2026-03-16)

# GitHub Packages publish from public repo

**Date:** 2026-03-16
**Closes:** #193

## What changed

`deploy-public.sh` now publishes to GitHub Packages from the public repo clone after the npm publish step. Previously, GitHub Packages were only published from the private repo during `wip-release`, so they showed on the private repo's Packages tab. Users couldn't see them.

Now packages show on the public repo's Packages tab where users expect to find them. Uses `gh auth token` for authentication (already available from the gh CLI).

## Why

The Packages tab on public repos was empty. Users visiting wipcomputer/wip-ldm-os or wipcomputer/wip-ai-devops-toolbox saw no packages even though they were published. The packages existed but were linked to the private repo.

## 1.9.37 (2026-03-16)

# GitHub Packages publish from public repo

**Date:** 2026-03-16
**Closes:** #193

## What changed

`deploy-public.sh` now publishes to GitHub Packages from the public repo clone after the npm publish step. Previously, GitHub Packages were only published from the private repo during `wip-release`, so they showed on the private repo's Packages tab. Users couldn't see them.

Now packages show on the public repo's Packages tab where users expect to find them. Uses `gh auth token` for authentication (already available from the gh CLI).

## Why

The Packages tab on public repos was empty. Users visiting wipcomputer/wip-ldm-os or wipcomputer/wip-ai-devops-toolbox saw no packages even though they were published. The packages existed but were linked to the private repo.

## 1.9.36 (2026-03-16)

# GitHub Packages publish from public repo

**Date:** 2026-03-16
**Closes:** #193

## What changed

`deploy-public.sh` now publishes to GitHub Packages from the public repo clone after the npm publish step. Previously, GitHub Packages were only published from the private repo during `wip-release`, so they showed on the private repo's Packages tab. Users couldn't see them.

Now packages show on the public repo's Packages tab where users expect to find them. Uses `gh auth token` for authentication (already available from the gh CLI).

## Why

The Packages tab on public repos was empty. Users visiting wipcomputer/wip-ldm-os or wipcomputer/wip-ai-devops-toolbox saw no packages even though they were published. The packages existed but were linked to the private repo.

## 1.9.35 (2026-03-16)

# GitHub Packages publish from public repo

**Date:** 2026-03-16
**Closes:** #193

## What changed

`deploy-public.sh` now publishes to GitHub Packages from the public repo clone after the npm publish step. Previously, GitHub Packages were only published from the private repo during `wip-release`, so they showed on the private repo's Packages tab. Users couldn't see them.

Now packages show on the public repo's Packages tab where users expect to find them. Uses `gh auth token` for authentication (already available from the gh CLI).

## Why

The Packages tab on public repos was empty. Users visiting wipcomputer/wip-ldm-os or wipcomputer/wip-ai-devops-toolbox saw no packages even though they were published. The packages existed but were linked to the private repo.

## 1.9.34 (2026-03-16)

# GitHub Packages publish from public repo

**Date:** 2026-03-16
**Closes:** #193

## What changed

`deploy-public.sh` now publishes to GitHub Packages from the public repo clone after the npm publish step. Previously, GitHub Packages were only published from the private repo during `wip-release`, so they showed on the private repo's Packages tab. Users couldn't see them.

Now packages show on the public repo's Packages tab where users expect to find them. Uses `gh auth token` for authentication (already available from the gh CLI).

## Why

The Packages tab on public repos was empty. Users visiting wipcomputer/wip-ldm-os or wipcomputer/wip-ai-devops-toolbox saw no packages even though they were published. The packages existed but were linked to the private repo.

## 1.9.33 (2026-03-15)

# --version on all CLIs + issue cleanup

**Date:** 2026-03-15
**Closes:** #190, #191, #169, #123, #119

## What changed

All 7 CLI tools now support `--version` and `-v`. Each reads its own `package.json` and prints the version. Previously, `wip-release --version` printed the help text instead of a version number.

Tools updated: wip-release, wip-repos, wip-license-guard, wip-repo-permissions, wip-repo-init, wip-readme-format, wip-file-guard, wip-branch-guard.

wip-license-guard also got a proper README (#169) with all commands, config format, and integration docs.

## Issues closed

- #190: wip-release --version should work
- #191: enforce --version on all CLI tools
- #169: wip-license-guard needs its own README
- #123: Merge/Deploy/Install conflated (enforced across v1.9.25-v1.9.30)
- #119: All destructive tools must have --dry-run (all confirmed)

## 1.9.32 (2026-03-15)

# --version on all CLIs + issue cleanup

**Date:** 2026-03-15
**Closes:** #190, #191, #169, #123, #119

## What changed

All 7 CLI tools now support `--version` and `-v`. Each reads its own `package.json` and prints the version. Previously, `wip-release --version` printed the help text instead of a version number.

Tools updated: wip-release, wip-repos, wip-license-guard, wip-repo-permissions, wip-repo-init, wip-readme-format, wip-file-guard, wip-branch-guard.

wip-license-guard also got a proper README (#169) with all commands, config format, and integration docs.

## Issues closed

- #190: wip-release --version should work
- #191: enforce --version on all CLI tools
- #169: wip-license-guard needs its own README
- #123: Merge/Deploy/Install conflated (enforced across v1.9.25-v1.9.30)
- #119: All destructive tools must have --dry-run (all confirmed)

## 1.9.31 (2026-03-15)

# Release Notes: wip-ai-devops-toolbox v1.9.31

Branch guard no longer blocks global npm operations on main.

## What changed

Moved `npm install -g` and `npm link` from BLOCKED_BASH_PATTERNS to ALLOWED_BASH_PATTERNS in `wip-branch-guard/guard.mjs`. Global npm operations modify `/opt/homebrew/`, not the repo. Local `npm install` (no -g flag) remains blocked.

## Why

During LDM OS v0.4.0 dogfood, a CC session couldn't run `npm install -g @wipcomputer/wip-ldm-os@0.4.0` even after Parker explicitly said "install." The guard was too aggressive. Original intent (issue #137) was to block repo writes on main, not system-level package installs.

## Issues closed

- Closes #188 (branch guard blocks npm install -g)
- Cross-ref: wipcomputer/wip-ldm-os#44

## How to verify

```bash
# On main branch, these should now succeed:
npm install -g @wipcomputer/wip-ldm-os@0.4.0
npm link
# This should still be blocked on main:
npm install
```

## 1.9.30 (2026-03-15)

# Release notes must be a file on disk

**Date:** 2026-03-15

## What changed

wip-release no longer accepts the `--notes` flag. Release notes MUST come from a file on disk:

1. `RELEASE-NOTES-v{version}.md` in repo root (auto-detected)
2. `ai/dev-updates/YYYY-MM-DD--description.md` (auto-detected)
3. `--notes-file=path` (explicit file path)

If no file exists, the release is blocked. The gate scaffolds a template (`RELEASE-NOTES-v{version}.md`) so the agent has something to fill in.

## Why

The `--notes` flag was the root cause of every bad release note. Agents passed one-liners like `--notes="fix bug"` and the gate let them through. Even after we added length checks and changelog detection, agents found ways around it. The flag was an escape hatch that undermined the entire system.

The file-on-disk requirement solves three problems:
1. **Reviewability.** The file is on the branch. It shows up in the PR diff. Parker can read and approve the release notes before merge.
2. **Quality.** Writing a file forces the agent to think about what changed and why. A flag encourages one-liners.
3. **History.** The file is committed to git. The release notes are part of the repo history, not a transient CLI argument.

## What agents need to do

Before running `wip-release`:
1. Write `RELEASE-NOTES-v{version}.md` or `ai/dev-updates/YYYY-MM-DD--description.md`
2. Commit it on the branch
3. The file shows up in the PR for review
4. After merge to main, `wip-release` auto-detects it

If the agent forgets, `wip-release` blocks and scaffolds a template.

## 1.9.29 (2026-03-15)

# Release notes must be a file on disk

**Date:** 2026-03-15

## What changed

wip-release no longer accepts the `--notes` flag. Release notes MUST come from a file on disk:

1. `RELEASE-NOTES-v{version}.md` in repo root (auto-detected)
2. `ai/dev-updates/YYYY-MM-DD--description.md` (auto-detected)
3. `--notes-file=path` (explicit file path)

If no file exists, the release is blocked. The gate scaffolds a template (`RELEASE-NOTES-v{version}.md`) so the agent has something to fill in.

## Why

The `--notes` flag was the root cause of every bad release note. Agents passed one-liners like `--notes="fix bug"` and the gate let them through. Even after we added length checks and changelog detection, agents found ways around it. The flag was an escape hatch that undermined the entire system.

The file-on-disk requirement solves three problems:
1. **Reviewability.** The file is on the branch. It shows up in the PR diff. Parker can read and approve the release notes before merge.
2. **Quality.** Writing a file forces the agent to think about what changed and why. A flag encourages one-liners.
3. **History.** The file is committed to git. The release notes are part of the repo history, not a transient CLI argument.

## What agents need to do

Before running `wip-release`:
1. Write `RELEASE-NOTES-v{version}.md` or `ai/dev-updates/YYYY-MM-DD--description.md`
2. Commit it on the branch
3. The file shows up in the PR for review
4. After merge to main, `wip-release` auto-detects it

If the agent forgets, `wip-release` blocks and scaffolds a template.

## 1.9.28 (2026-03-15)

# Release Notes Quality Gate

**Date:** 2026-03-15

## What changed

wip-release now blocks ALL releases (patch, minor, major) if the release notes are bad. Previously, patch releases only warned. Now they block.

The gate checks:
- Notes must be at least 50 characters
- Notes can't look like a changelog entry ("fix: ...", "add: ...", "update: ...")
- Minor/major still require a file (not --notes flag)

If the gate blocks, it tells you exactly how to fix it: write a RELEASE-NOTES file, write a dev update, or use --notes with at least 50 chars of real description.

## Why

Release notes were consistently garbage. One-liner --notes flags like "Fix bug" or "Update docs" sailed through on patch releases. The warnings were ignored by both humans and agents. Every release page on GitHub had thin, useless notes that didn't explain what changed or why.

## Also in this release

- wip-repo-init templates renamed from ai/ to templates/ so they ship with npm install (deploy-public.sh was stripping them)
- SKILL.md restart notice after install (hooks need session restart)
- SPEC.md and TECHNICAL.md updated with all 17 tools and LDM OS links
- Branch guard matcher fix (catches Bash + NotebookEdit)
- Forced Git Worktrees and Branch Guard sections added to SKILL.md

## 1.9.27 (2026-03-15)

# Release Notes Quality Gate

**Date:** 2026-03-15

## What changed

wip-release now blocks ALL releases (patch, minor, major) if the release notes are bad. Previously, patch releases only warned. Now they block.

The gate checks:
- Notes must be at least 50 characters
- Notes can't look like a changelog entry ("fix: ...", "add: ...", "update: ...")
- Minor/major still require a file (not --notes flag)

If the gate blocks, it tells you exactly how to fix it: write a RELEASE-NOTES file, write a dev update, or use --notes with at least 50 chars of real description.

## Why

Release notes were consistently garbage. One-liner --notes flags like "Fix bug" or "Update docs" sailed through on patch releases. The warnings were ignored by both humans and agents. Every release page on GitHub had thin, useless notes that didn't explain what changed or why.

## Also in this release

- wip-repo-init templates renamed from ai/ to templates/ so they ship with npm install (deploy-public.sh was stripping them)
- SKILL.md restart notice after install (hooks need session restart)
- SPEC.md and TECHNICAL.md updated with all 17 tools and LDM OS links
- Branch guard matcher fix (catches Bash + NotebookEdit)
- Forced Git Worktrees and Branch Guard sections added to SKILL.md

## 1.9.26 (2026-03-15)

Add restart notice after install/update. Hooks need session restart to take effect.

## 1.9.25 (2026-03-14)

Fix branch guard matcher (catches Bash + NotebookEdit). Add Forced Git Worktrees and Branch Guard sections to SKILL.md. Update SPEC.md and TECHNICAL.md with all 17 tools and LDM OS links.

## 1.9.24 (2026-03-14)

Number tools in dry run and already-installed lists. Dogfood iteration.

## 1.9.23 (2026-03-14)

Force verbatim tool list display. AI must show all 17 tools with descriptions, never summarize.

## 1.9.22 (2026-03-14)

All 17 tools listed with descriptions. New section order: Setup, Infrastructure, Repo Management, License, Release. Conversational prompt.

## 1.9.21 (2026-03-14)

Add Already Installed section with tool descriptions. Dogfood fix.

## 1.9.20 (2026-03-14)

Make root package publishable. npm install -g @wipcomputer/wip-ai-devops-toolbox now installs all 12 CLI tools.

## 1.9.19 (2026-03-14)

Add websiteRepo to .publish-skill.json. Auto-publish SKILL.md to website on release. Fix install prompt URLs to use wip- prefix.

## 1.9.18 (2026-03-14)

Rewrite SKILL.md install flow to use ldm install. Conversational AI-guided pattern matching Memory Crystal.

## 1.9.17 (2026-03-14)

Add wip-branch-guard: PreToolUse hook that blocks all writes on main branch. Resolves repo from file path so it works from any CWD. Forces agents to branch or worktree before editing.

## 1.9.16 (2026-03-14)

Add wip-branch-guard: PreToolUse hook that blocks all writes on main branch. Resolves repo from file path so it works from any CWD. Forces agents to branch or worktree before editing.

## 1.9.15 (2026-03-14)

Fix all 5 root causes of truncated release notes (#121). Add --dry-run to readme-license. Update SKILL.md docs for wip-release and wip-license-guard.

## 1.9.14 (2026-03-14)

Add readme-license command to wip-license-guard. Scans all repos, applies standard license block, removes from sub-tools. License Guard now Stable.

## 1.9.13 (2026-03-14)

Release.

## 1.9.12 (2026-03-13)

Add skill publish to website: after every release, SKILL.md is auto-copied to yoursite.com/install/{name}.txt and deployed. Configured per repo with .publish-skill.json. Non-blocking.

## 1.9.11 (2026-03-13)

wip-install bootstraps LDM OS silently when not on PATH

## 1.9.10 (2026-03-13)

# Release Notes: AI DevOps Toolbox v1.9.10

**Fix: Release notes files on disk always beat --notes flag**

v1.9.9 shipped with a one-liner on the GitHub release instead of the full narrative release notes. The RELEASE-NOTES-v1-9-9.md file was sitting right there on disk, but `--notes="short text"` took priority because the auto-detect only ran when `--notes` was absent.

This is exactly the kind of bug that happens when a rule exists in documentation but not in code. "Write release notes on the branch" is in the Dev Guide. The tool ignored them.

## What changed

### Notes priority is now enforced (highest wins):

1. `--notes-file=path` ... explicit file path (always wins)
2. `RELEASE-NOTES-v{ver}.md` ... in repo root (always wins over `--notes` flag)
3. `ai/dev-updates/YYYY-MM-DD*` ... today's dev update (wins over `--notes` flag if longer)
4. `--notes="text"` ... fallback only. Use for repos without release notes files.

If a RELEASE-NOTES file exists on disk, `--notes` is ignored and a warning is printed:

```
! --notes flag ignored: RELEASE-NOTES-v1-9-10.md takes priority
```

Written notes on disk always take priority over a CLI one-liner. The agent wrote the file. The tool should use it.

## Files changed

```
 tools/wip-release/cli.js | ~40 lines rewritten (notes cascade logic)
```

## Install

```bash
git pull origin main
```

## Attribution

Built by Parker Todd Brooks, Lesa, and Claude Opus 4.6 at WIP.computer.

## 1.9.9 (2026-03-13)

Enforce git worktrees as default workflow. wip-release blocks from worktrees, wip-install auto-adds .claude/worktrees/ to .gitignore, Dev Guide worktree section added.

## 1.9.8 (2026-03-13)

wip-install delegates to ldm install when available

## 1.9.7 (2026-03-13)

# Release Notes: AI DevOps Toolbox v1.9.7

## LDM OS Integration

AI DevOps Toolbox now works with LDM OS when it's available.

### wip-install delegates to ldm install

When the `ldm` CLI exists on PATH, `wip-install` delegates to `ldm install`. LDM OS handles the scaffold, interface detection, and extension deployment. The Toolbox's standalone behavior is preserved as a fallback when `ldm` isn't available.

Supports `--dry-run` and `--json` passthrough to `ldm install`.

### LDM OS tip

After standalone installs, the Toolbox prints a tip: "Run `ldm install` to see more skills you can add."

### Universal Installer link

The "Read more about Universal Installer" link now points to the LDM OS docs page. The Universal Installer engine moved to LDM OS. The Toolbox keeps `wip-install` as an entry point that delegates.

### Part of LDM OS

README includes a "Part of LDM OS" section linking back to the LDM OS repo.

## 1.9.6 (2026-03-12)

# v1.9.6 ... Enforcement Gates

Three fixes that move the release pipeline from "suggestions agents forget" to "gates that block."

---

## syncSkillVersion corrupted quoted versions (#71)

Every release was appending the old version instead of replacing it. SKILL.md went from `"1.9.5"` to `"1.9.5".9.4".9.3".9.2".9.1"` over five releases.

Root cause: the regex `"?\S+?"?` used non-greedy matching. For quoted values, it consumed only part of the string, leaving the rest as trailing garbage.

Fix: replaced with `(?:"[^\n]*|\S+)`. Quoted values now match through end of line. Unquoted values use greedy `\S+`. Also fixed the staleness-check regex to extract clean semver from corrupted strings.

**Files changed:**
- `tools/wip-release/core.mjs` ... `syncSkillVersion()` regex fix
- `SKILL.md` ... repaired corrupted version back to `"1.9.5"`

---

## gh pr merge now always deletes branch (#74)

Every `gh pr merge` call in the codebase now includes `--delete-branch`. Previously, deploy-public.sh had a manual 3-line `gh api -X DELETE` cleanup block. That's gone. The flag handles it.

Also verified every merge uses `--merge` (never squash). Dev Guide updated with the new convention.

**Files changed:**
- `scripts/deploy-public.sh` ... added `--delete-branch`, removed manual cleanup
- `tools/deploy-public/deploy-public.sh` ... same
- `DEV-GUIDE-GENERAL-PUBLIC.md` ... updated merge examples
- `ai/DEV-GUIDE-FOR-WIP-ONLY-PRIVATE.md` ... updated merge rules
- `ai/_trash/DEV-GUIDE-private.md` ... updated
- `ai/_sort/_trash/ai_old/_trash/DEV-GUIDE-private.md` ... updated

---

## wip-release blocks on stale remote branches (#75)

New gate in the release pipeline. Before releasing, wip-release checks for remote branches that are fully merged into main but haven't been cleaned up.

- **Patch:** warns with the list of stale branches (non-blocking)
- **Minor/major:** blocks the release. Clean up first.
- **`--skip-stale-check`:** override flag for emergencies

Follows the existing gate pattern: fetches with `--prune`, filters out `origin/main`, `origin/HEAD`, and `--merged-` branches. Fails gracefully if git commands error.

**Files changed:**
- `tools/wip-release/core.mjs` ... `checkStaleBranches()` function, integrated as gate 0.8
- `tools/wip-release/cli.js` ... `--skip-stale-check` flag, help text

---

## Diffstat

```
 10 files changed, 102 insertions(+), 21 deletions(-)
```

## Install

```bash
npm install -g @wipcomputer/wip-ai-devops-toolbox
```

Or update an existing install:
```bash
wip-install wipcomputer/wip-ai-devops-toolbox
```

---

Built by Parker Todd Brooks, Lēsa (OpenClaw, Claude Opus 4.6), Claude Code (Claude Opus 4.6).

## 1.9.5 (2026-03-12)

wip-release: bump sub-tool versions in toolbox repos. Fixes #132.

## 1.9.4 (2026-03-12)

wip-install: detect and migrate existing installs under different names. Fixes #128.

## 1.9.3 (2026-03-12)

Fix: ensure bin executability on installer skip path. Fixes wip-license-guard, wip-license-hook, wip-repo-init, wip-readme-format permission denied after reinstall.

## 1.9.2 (2026-03-12)

# v1.9.2: Distribution Pipeline Fix

The entire distribution pipeline was broken. Tools built but never reached users. 8 of 13 tools weren't on npm. ClawHub publish only shipped the root SKILL.md. deploy-public never ran npm publish. Errors were silent.

This release fixes all of it.

## What changed

### Install fixes (#96, #110)
- CLI binaries now have correct executable permissions (git +x on all bin entry files)
- wip-license-hook dist/ committed to repo (TypeScript build output was gitignored)
- Installer auto-detects TypeScript projects and runs build if dist/ missing
- chmod +x safety net after every npm install -g
- SSH fallback when HTTPS clone fails (private repos)

### SKILL.md spec compliance (#107, #108)
- All 12 SKILL.md files conform to agentskills.io spec
- name field: lowercase-hyphen format matching directory name
- Display names in metadata.display-name
- version, homepage, author in metadata block
- license: MIT on all files
- metadata.openclaw blocks with install instructions and emoji
- New SKILL.md created for wip-license-guard (was missing)

### Distribution pipeline (#97, #100, #104)
- ClawHub publish now iterates all sub-tool SKILL.md files, not just root
- detectSkillSlug reads the name field from SKILL.md frontmatter
- deploy-public.sh runs npm publish from the public clone after code sync
- Handles both single repos and toolbox repos (iterates tools/*)
- Distribution summary at end of release: shows all targets with pass/fail
- syncSkillVersion handles quoted version strings in new metadata format

## Install

```bash
npm install -g @wipcomputer/wip-ai-devops-toolbox
wip-install wipcomputer/wip-ai-devops-toolbox
```

Built by Parker Todd Brooks, Lesa (OpenClaw, Claude Opus 4.6), Claude Code (Claude Opus 4.6).

## 1.9.1 (2026-03-11)

# v1.9.1: Release gates ... product docs and release notes quality enforcement

Agents read the Dev Guide, say "got it," and then release with garbage one-liner notes anyway. Documentation doesn't change behavior. Tools do. This release adds two new gates to `wip-release` that block bad releases before they happen.

## Product docs gate

Every PR is supposed to include updated product docs: a dev update, roadmap changes, and readme-first updates. This was documented in the Dev Guide as a manual checklist. Nobody followed it.

`wip-release` now checks three things before publishing:

1. **Dev update exists.** Looks in `ai/dev-updates/` for a file from the last 3 days. If you did work worth releasing, you should have written about it.
2. **Roadmap was updated.** Checks `ai/product/plans-prds/roadmap.md` via `git diff` against the last tag. If the roadmap doesn't reflect what just shipped, it's stale.
3. **Readme-first was updated.** Same check on `ai/product/readme-first-product.md`. The product bible should always describe what's actually built.

Repos without an `ai/` directory are skipped silently. This only applies to repos that have adopted the `ai/` folder standard.

For **patch** releases: warns but doesn't block. Hotfixes shouldn't be held up by docs.
For **minor/major** releases: blocks the release. You can't ship a meaningful feature with stale product docs.

`--skip-product-check` overrides for exceptional cases.

## Release notes quality gate

On 2026-03-11, the other CC session released memory-crystal v0.7.4. It read the Dev Guide (which now explicitly says "write a RELEASE-NOTES file on the branch"). It said it understood. Then it ran `wip-release patch --notes="MCP fix and agent ID config"` and published a one-liner to GitHub. The old `warnIfNotesAreThin()` function printed a warning to console. The agent ignored it.

The root cause was architectural, not behavioral. The warning ran at step 8 of the pipeline, AFTER the version was already bumped, committed, tagged, and pushed. By the time the warning appeared, the damage was done. And it was a warning, not a gate. Agents don't read warnings.

The fix:
- `checkReleaseNotes()` replaces `warnIfNotesAreThin()`. It runs before the version bump, not after.
- The CLI now tracks `notesSource`: where the notes came from (`file`, `dev-update`, `flag`, or `none`).
- For minor/major releases: if notes came from a bare `--notes` flag instead of a `RELEASE-NOTES-v{version}.md` file, the release is **blocked**. The agent gets explicit instructions: "Write RELEASE-NOTES-v{version}.md (dashes not dots), commit it, then release."
- For patch releases: warns if notes are short, but doesn't block.

## Both gates follow the same pattern

The existing license compliance gate (step 0) checks `.license-guard.json` and blocks if licensing is wrong. The new product docs gate (step 0.5) and release notes gate (step 0.75) work the same way: check early, block before any changes, show status in `--dry-run`, give clear instructions on how to fix it.

The MCP server was also updated with `skipProductCheck` and `notesSource` passthrough so agents calling wip-release via MCP get the same enforcement.

## 1.9.0 (2026-03-11)

README Formatter (section-based staging + deploy), Repo Init (ai/ directory scaffolding), Dev Guide overhaul with release notes workflow

## 1.8.2 (2026-03-11)

# v1.8.2: Clean up release notes after release

RELEASE-NOTES files were piling up in the repo root. `wip-release` consumed them for the GitHub release and CHANGELOG but never cleaned up.

Now after consuming the file, `wip-release` moves all `RELEASE-NOTES-v*.md` files to `_trash/` as part of the version bump commit. We never delete anything.

`deploy-public.sh` also now excludes `_trash/` so these files stay private.

## 1.8.1 (2026-03-11)

# v1.8.1: Fix CLI install when package name changed

When a tool's npm package gets renamed but the binary name stays the same, `npm install -g` fails with EEXIST. The stale symlink from the old package blocks the new one.

The installer now detects this: if the binary is a symlink pointing to a different package, it removes the stale link and retries. Only affects symlinks, only when the target doesn't match the package being installed.

Found on `wip-license-hook` (renamed from `@wipcomputer/license-hook` to `@wipcomputer/wip-license-hook`).

## 1.8.0 (2026-03-11)

# v1.8.0: Fix CC Hook duplicates, add GitHub Issues convention

## CC Hook duplicate detection fix

`wip-install` was adding duplicate PreToolUse hooks to `~/.claude/settings.json` every time it ran. After a few installs, there were 8 hooks when there should have been 2. The duplicates pointed to repo clones and `/tmp/` paths, violating the "never run tools from repo clones" rule.

The root cause: duplicate detection compared exact command strings. The same `guard.mjs` installed from different paths produced different strings, so each install added another entry.

The fix:
- Match existing hooks by tool name in the path, not exact command string
- Always prefer `~/.ldm/extensions/<tool>/guard.mjs` over source or temp paths
- If a hook for the same tool exists at a different path, update it instead of adding a duplicate

## GitHub Issues convention added to Dev Guide

We were tracking work in `ai/todos/` markdown files. Items got lost. GitHub Issues gives us tracking, cross-referencing, and visibility across agents.

Added to the public Dev Guide:
- When to use GitHub Issues vs `ai/todos/`
- Filing convention: `filed-by:<agent-id>` labels and attribution lines
- Public vs private issue routing: public issues are the front door, private issues are the workshop
- Agent ID naming convention: `[platform]-[agent]-[machine]`

Added to the private Dev Guide:
- `filed-by:cc-mini` (blue) and `filed-by:oc-lesa-mini` (purple) label details
- Org-wide deployment commands
- Incident note: Memory Crystal agent ID drift

Both labels deployed across all wipcomputer repos.

## 1.7.9 (2026-03-11)

Add GitHub Issues convention and filed-by workflow to the Dev Guide.

We've been tracking work in ai/todos/ markdown files. Items get lost. GitHub Issues gives us tracking, cross-referencing, and visibility across all agents. This release documents the full convention.

**Public Dev Guide (DEV-GUIDE-GENERAL-PUBLIC.md):**
- New "GitHub Issues" section: when to use issues vs ai/todos/, filing convention with attribution lines and filed-by labels, public vs private issue routing workflow
- Agent ID naming convention: [platform]-[agent]-[machine] format documented with examples
- Public/private issue bridge: public issues are the front door (users), private issues are the workshop (team), releases connect them

**Private Dev Guide (ai/DEV-GUIDE-FOR-WIP-ONLY-PRIVATE.md):**
- filed-by label details: cc-mini (blue), oc-lesa-mini (purple), deployed org-wide
- Commands for adding labels to new agents or repos
- Incident note: Memory Crystal agent ID drift (4 IDs instead of 2), manual merge of 141K chunks, root cause and fix tracked in memory-crystal-private#33

**Org-wide:** filed-by:cc-mini and filed-by:oc-lesa-mini labels created on all wipcomputer repos.

## 1.7.8 (2026-03-10)

# Dev Update: Smart Install + Platform Compatibility

**Date:** 2026-03-10 22:40 PST
**Author:** Claude Code (cc-mini)
**Version:** v1.7.8 (pending)
**Branches:** cc-mini/smart-install, cc-mini/platform-compat-v2

## Smart Install (wip-install)

Parker's feedback: "I want to make sure we're not going to replace stuff unless we need to. It should be smart enough to know I have this extension installed, and it's the same one."

The Universal Installer was doing blind `rm -rf` and re-copy on every run. Now it checks versions first:

- **Extensions (LDM + OpenClaw):** Reads `package.json` version from the installed extension. If it matches the source version, skip. If different, upgrade. If missing, fresh install. Dry-run shows "would upgrade v1.2.3 -> v1.2.4" vs "would deploy v1.2.4" vs "already at v1.2.4".
- **CLI:** Checks `npm list -g` for the installed version. Same version = skip.
- **MCP:** Checks if already registered at the same server path. Same path = skip.
- **CC Hooks:** Already had duplicate detection (unchanged).

No more destroying things that don't need updating.

## Platform Compatibility (SKILL.md)

Parker's feedback after testing with Grok: "Grok said 'I'll run wip-install' but it literally cannot. It's hallucinating capabilities."

First version listed platforms as "first-class / MCP-compatible / not compatible." Parker corrected: "We don't need to say 'not compatible' because Claude iOS can install stuff now. We just need to be clear about what the tool needs."

Rewrote to capability requirements:

| Interface | Requires |
|-----------|----------|
| CLI | Shell access |
| MCP Server | MCP client support |
| CC Hook | Claude Code CLI with hooks |
| OpenClaw Plugin | OpenClaw runtime |
| Skill | Ability to read this file |
| Module | Node.js import |

Key instruction to agents: "Check which capabilities you have and match them to the table. Do not claim you can run commands you cannot execute."

This is future-proof. When a platform adds MCP or shell access, the SKILL.md doesn't need updating. The agent assesses itself.

## Cross-Platform Testing Results

Three AIs read the same SKILL.md onboarding prompt:

- **Claude Code (another instance):** Read it, explained all tools correctly, offered dry-run first. Responded with "HOLY SHIT!!!" (impressed by the tooling).
- **Lesa (OpenClaw, Claude Opus 4.6):** Perfect breakdown. Every tool categorized correctly. Called out the auto-detect dev updates feature specifically. Offered dry-run first.
- **Grok (xAI):** Initially tried to roleplay as Lesa/Claude Code (read the attribution line and adopted the persona). When corrected, gave accurate breakdown. But claimed it would run `wip-install` when it cannot. This exposed the need for the Platform Compatibility section.

The SKILL.md is working. Three different AIs, three different platforms, all understood the toolbox correctly from one file.

## 1.7.7 (2026-03-10)

# Dev Update: SKILL.md as the Real Interface

**Date:** 2026-03-10 22:10 PST
**Author:** Claude Code (cc-mini)
**Version:** v1.7.4
**Branch:** cc-mini/skill-installer-details

## The Insight

Parker said it plainly: "We're not doing READMEs anymore. This is not for humans."

The human interface is the AI. The AI's interface is the SKILL.md. If the skill doesn't contain everything needed to operate, the AI guesses. And it guesses wrong.

We proved this earlier in the session. Lesa read the toolbox and miscategorized Universal Installer under "Repo Management" because the SKILL.md had no category structure (fixed in v1.7.3). But even after categories, she still couldn't explain what the tools actually do operationally, because the SKILL.md was still a half-README with links and one-liners.

## What We Researched

Parker pointed us to agentcard.sh/agent.txt as a reference. We researched three AI documentation conventions:

1. **llms.txt** (llmstxt.org) ... a directory of links. Points to docs but doesn't contain them. An AI still has to fetch and read multiple files. Good for discovery, not for operation.

2. **agent.txt / AgentCard** (agentcard.sh) ... self-contained operational manual. Everything in one file. An AI reads it and knows how to interact with the service. Closer to what we need, but designed for describing APIs/services, not developer tools.

3. **SKILL.md** (ours) ... YAML frontmatter for machine parsing, then full operational detail. Designed specifically to teach an AI how to use developer tools. Not a pointer to docs. Not a summary. The complete manual.

We took the best from each: the discoverability mindset of llms.txt, the self-contained philosophy of agent.txt, and built SKILL.md as the standard for AI-native developer tool documentation.

## What Changed in v1.7.4

The SKILL.md went from ~140 lines (descriptions + links) to ~475 lines (complete operational manual).

Every one of the 11 tools now has:
- Complete commands with all flags and options
- Step-by-step "what happens when you run it" sequences
- Exact file paths (where it reads, where it writes)
- Safety notes (what it deletes, what it overwrites, what to watch for)
- How it works across different interfaces (CC Hook, OpenClaw Plugin, MCP server)

### Specific additions worth noting:

**Universal Installer** got a full deployment table showing what each of the 6 interfaces does and where it writes. We read the install.js source code and documented that it does `rm -rf` on existing extension directories before copying. That's critical safety information an AI needs before running it.

**Release Pipeline** got all 13 steps documented (step 0: license gate through step 12: branch prune). Every flag, every file it touches, every decision point.

**Identity File Protection** got the exact list of protected files and the definition of "destructive" (replacing >50% of content). Also documented the difference between how the CC Hook and OpenClaw Plugin work.

**MCP section** got complete tool function names for all MCP-enabled tools, so an AI can add them to .mcp.json without guessing.

## The "Teach Your AI" Framing

Parker's directive on the README: the first tool (Universal Installer) says "Teaches your AI to..." explicitly. The rest infer the pattern. You don't need to say "teaches" 11 times. The frame is set once, and a reader (human or AI) carries it forward.

Universal Installer's description changed from a generic "installs tools" to: "Teaches your AI to take anything you build and make it work across every AI interface. You write code in any language. This tool turns it into a CLI, MCP Server, OpenClaw Plugin, Skill, and Claude Code Hook."

## Interface Coverage Table Iterations

We went through several iterations on the table format:

1. **Separate tables per category** ... Parker: "too hard on the eyes"
2. **Single table, bold category divider rows** ... better, but needed numbering
3. **Added numbers 1-11 in a # column** ... Parker liked it
4. **Tried moving categories into the # column, removing numbers** ... Parker: "looks worse, change it back"
5. **Final: numbers + category divider rows, no dashes in empty cells** ... clean and scannable

The lesson: don't overthink table formatting. Numbers give anchoring. Category rows give structure. Empty cells are cleaner than dashes.

## The Standard Going Forward

This is how we think SKILL.md files should be written for any tool in the toolbox:

1. YAML frontmatter with name, version, interface list
2. One-paragraph description of what the tool teaches
3. Complete command reference with all flags
4. Step-by-step operational detail (what happens when you run it)
5. File paths (reads from, writes to)
6. Safety notes (destructive operations, prerequisites)
7. Interface-specific behavior (how it works as CLI vs Hook vs MCP vs Plugin)

The SKILL.md is the source of truth. READMEs exist for humans browsing GitHub. But the AI reads the SKILL.md, and the SKILL.md must be complete.

## Release Notes Standard

We also established that release notes on GitHub should tell the story. Not just "bumped version" or a one-liner from `--notes`. The v1.7.4 release notes explain the thinking, the research, and what changed. This is how releases should read going forward.

Earlier releases (v1.7.1, v1.7.2) shipped with thin notes and we had to go back and manually update them via `gh release edit`. The tool (wip-release) uses the `--notes` flag, which encourages one-liners. For significant releases, we should write RELEASE-NOTES files on the branch and have the tool pick them up.

## Files Changed

- `SKILL.md` ... complete rewrite (140 -> 475 lines)
- `README.md` ... Interface Coverage table: numbered, category dividers, no dashes
- `ai/feedback/2026-03-10--gpt--v1.7.1-readme-review.md` ... GPT rated the README 9.6/10

## wip-release: Auto-Detect Dev Updates as Release Notes

Parker's feedback: "The release notes should be automated. I shouldn't have to keep telling you to do this."

We updated `wip-release` to auto-detect release notes from `ai/dev-updates/`. The priority order:

1. `--notes-file=path` (explicit)
2. `RELEASE-NOTES-v{ver}.md` in repo root
3. `ai/dev-updates/YYYY-MM-DD*` (today's dev update files, most recent first)
4. `--notes="one-liner"` (fallback, but dev updates win if they have more content)

This means: write dev updates as you work (which we already do). When you run `wip-release`, it finds today's dev update and uses it as the full release notes. No more thin one-liners on GitHub releases. No more "this week's sauce, come on, man."

## What's Next

- Consider making the SKILL.md standard a section in the Dev Guide
- Operational guide for agent identities (Parker mentioned needing this)

## 1.7.6 (2026-03-10)

README: onboarding prompt now does dry-run install first so users see what changes before committing

## 1.7.5 (2026-03-10)

# Dev Update: SKILL.md as the Real Interface

**Date:** 2026-03-10 22:10 PST
**Author:** Claude Code (cc-mini)
**Version:** v1.7.4
**Branch:** cc-mini/skill-installer-details

## The Insight

Parker said it plainly: "We're not doing READMEs anymore. This is not for humans."

The human interface is the AI. The AI's interface is the SKILL.md. If the skill doesn't contain everything needed to operate, the AI guesses. And it guesses wrong.

We proved this earlier in the session. Lesa read the toolbox and miscategorized Universal Installer under "Repo Management" because the SKILL.md had no category structure (fixed in v1.7.3). But even after categories, she still couldn't explain what the tools actually do operationally, because the SKILL.md was still a half-README with links and one-liners.

## What We Researched

Parker pointed us to agentcard.sh/agent.txt as a reference. We researched three AI documentation conventions:

1. **llms.txt** (llmstxt.org) ... a directory of links. Points to docs but doesn't contain them. An AI still has to fetch and read multiple files. Good for discovery, not for operation.

2. **agent.txt / AgentCard** (agentcard.sh) ... self-contained operational manual. Everything in one file. An AI reads it and knows how to interact with the service. Closer to what we need, but designed for describing APIs/services, not developer tools.

3. **SKILL.md** (ours) ... YAML frontmatter for machine parsing, then full operational detail. Designed specifically to teach an AI how to use developer tools. Not a pointer to docs. Not a summary. The complete manual.

We took the best from each: the discoverability mindset of llms.txt, the self-contained philosophy of agent.txt, and built SKILL.md as the standard for AI-native developer tool documentation.

## What Changed in v1.7.4

The SKILL.md went from ~140 lines (descriptions + links) to ~475 lines (complete operational manual).

Every one of the 11 tools now has:
- Complete commands with all flags and options
- Step-by-step "what happens when you run it" sequences
- Exact file paths (where it reads, where it writes)
- Safety notes (what it deletes, what it overwrites, what to watch for)
- How it works across different interfaces (CC Hook, OpenClaw Plugin, MCP server)

### Specific additions worth noting:

**Universal Installer** got a full deployment table showing what each of the 6 interfaces does and where it writes. We read the install.js source code and documented that it does `rm -rf` on existing extension directories before copying. That's critical safety information an AI needs before running it.

**Release Pipeline** got all 13 steps documented (step 0: license gate through step 12: branch prune). Every flag, every file it touches, every decision point.

**Identity File Protection** got the exact list of protected files and the definition of "destructive" (replacing >50% of content). Also documented the difference between how the CC Hook and OpenClaw Plugin work.

**MCP section** got complete tool function names for all MCP-enabled tools, so an AI can add them to .mcp.json without guessing.

## The "Teach Your AI" Framing

Parker's directive on the README: the first tool (Universal Installer) says "Teaches your AI to..." explicitly. The rest infer the pattern. You don't need to say "teaches" 11 times. The frame is set once, and a reader (human or AI) carries it forward.

Universal Installer's description changed from a generic "installs tools" to: "Teaches your AI to take anything you build and make it work across every AI interface. You write code in any language. This tool turns it into a CLI, MCP Server, OpenClaw Plugin, Skill, and Claude Code Hook."

## Interface Coverage Table Iterations

We went through several iterations on the table format:

1. **Separate tables per category** ... Parker: "too hard on the eyes"
2. **Single table, bold category divider rows** ... better, but needed numbering
3. **Added numbers 1-11 in a # column** ... Parker liked it
4. **Tried moving categories into the # column, removing numbers** ... Parker: "looks worse, change it back"
5. **Final: numbers + category divider rows, no dashes in empty cells** ... clean and scannable

The lesson: don't overthink table formatting. Numbers give anchoring. Category rows give structure. Empty cells are cleaner than dashes.

## The Standard Going Forward

This is how we think SKILL.md files should be written for any tool in the toolbox:

1. YAML frontmatter with name, version, interface list
2. One-paragraph description of what the tool teaches
3. Complete command reference with all flags
4. Step-by-step operational detail (what happens when you run it)
5. File paths (reads from, writes to)
6. Safety notes (destructive operations, prerequisites)
7. Interface-specific behavior (how it works as CLI vs Hook vs MCP vs Plugin)

The SKILL.md is the source of truth. READMEs exist for humans browsing GitHub. But the AI reads the SKILL.md, and the SKILL.md must be complete.

## Release Notes Standard

We also established that release notes on GitHub should tell the story. Not just "bumped version" or a one-liner from `--notes`. The v1.7.4 release notes explain the thinking, the research, and what changed. This is how releases should read going forward.

Earlier releases (v1.7.1, v1.7.2) shipped with thin notes and we had to go back and manually update them via `gh release edit`. The tool (wip-release) uses the `--notes` flag, which encourages one-liners. For significant releases, we should write RELEASE-NOTES files on the branch and have the tool pick them up.

## Files Changed

- `SKILL.md` ... complete rewrite (140 -> 475 lines)
- `README.md` ... Interface Coverage table: numbered, category dividers, no dashes
- `ai/feedback/2026-03-10--gpt--v1.7.1-readme-review.md` ... GPT rated the README 9.6/10

## wip-release: Auto-Detect Dev Updates as Release Notes

Parker's feedback: "The release notes should be automated. I shouldn't have to keep telling you to do this."

We updated `wip-release` to auto-detect release notes from `ai/dev-updates/`. The priority order:

1. `--notes-file=path` (explicit)
2. `RELEASE-NOTES-v{ver}.md` in repo root
3. `ai/dev-updates/YYYY-MM-DD*` (today's dev update files, most recent first)
4. `--notes="one-liner"` (fallback, but dev updates win if they have more content)

This means: write dev updates as you work (which we already do). When you run `wip-release`, it finds today's dev update and uses it as the full release notes. No more thin one-liners on GitHub releases. No more "this week's sauce, come on, man."

## What's Next

- Consider making the SKILL.md standard a section in the Dev Guide
- Operational guide for agent identities (Parker mentioned needing this)

## 1.7.4 (2026-03-10)

SKILL.md full operational rewrite for AI agents. Every tool now has complete commands, flags, step-by-step behavior, file paths, and safety notes. Interface Coverage table cleaned up: numbered tools, category dividers, no dashes.

## 1.7.3 (2026-03-10)

Add category structure to SKILL.md matching README. Prevents AI from miscategorizing tools.

## 1.7.2 (2026-03-10)

Reframe Universal Installer description, fix tense, update SKILL.md intro framing

## 1.7.1 (2026-03-10)

Reframe tool descriptions with teach your AI pattern, file GPT and Grok feedback on v1.7.0

## 1.7.0 (2026-03-10)

## v1.7.0: Renamed to AI DevOps Toolbox, CLA, License Enforcement, Branch Prune, README Polish

This release renames the repo, adds contributor governance, makes licensing intent unmistakable, automates branch cleanup, and tightens the README based on a second round of external feedback.

The repo is now **AI DevOps Toolbox** (`wip-ai-devops-toolbox`). The name change reflects what this actually is: not just DevOps scripts, but AI-native development infrastructure.

Includes work from PRs #53, #54.

---

### Repo Rename: AI DevOps Toolbox

**What we did:** Renamed from "DevOps Toolbox" (`wip-devops-toolbox`) to "AI DevOps Toolbox" (`wip-ai-devops-toolbox`).

**Why:** The old name undersold what this is. "DevOps Toolbox" sounds like scripts. This is an interface architecture, an agent tool ecosystem, and a workflow framework for AI-assisted development. The name should say that.

**What changed:**
- GitHub repos renamed: `wip-ai-devops-toolbox-private` and `wip-ai-devops-toolbox`
- All internal references updated: README, TECHNICAL.md, SKILL.md, package.json, cross-repo references

---

### Contributor License Agreement (CLA)

**What we did:** Added `CLA.md` at the repo root and referenced it in the README License section.

**Why:** Without a CLA, contributors who submit PRs own their code. AGPL means we can't relicense their contributions commercially. We need contributors to grant WIP Computer, Inc. the right to use their contributions under any license, including commercial. This is standard open source governance. Apache, Google, Meta, and Anthropic all use similar agreements.

**How it works:** By submitting a PR, you agree to the CLA. Contributors keep their own copyright but grant WIP Computer, Inc. a broad license. Plain-English, no lawyer needed to understand it.

**New files:**
- `CLA.md` ... the agreement itself

---

### Licensing Clarity

**What we did:** Made the licensing intent unmistakable with two new sentences.

**Why:** The dual MIT+AGPLv3 license is technically correct, but people still ask "can I use this?" The answer needed to be obvious: yes, use the tools however you want. The only thing that requires a commercial license is taking the tools themselves and reselling them.

**What changed:**
- Added "Dual-license model designed to keep tools free while preventing commercial resellers" above the license block
- Added "Using these tools to build your own software is fine. Reselling the tools themselves is what requires a commercial license" to the "Can I use this?" section
- Updated `generateReadmeBlock()` in `tools/wip-license-guard/core.mjs` so every future repo gets the same wording automatically

---

### Branch Prune Automation

**What we did:** Built automatic branch cleanup into both `post-merge-rename.sh` and `wip-release`.

**Why:** Merged branches pile up on the remote. Before this release, the private repo had 30+ stale branches. The post-merge-rename script renamed them with `--merged-YYYY-MM-DD` but never cleaned up old ones. Manually deleting branches is a waste of time. We built these tools so we don't have to keep doing things manually.

**How it works:**

`post-merge-rename.sh --prune` does three things:
1. Renames any merged branches that don't have the `--merged` suffix yet
2. For each developer prefix (`cc-mini/`, `mini/`, `lesa-mini/`, etc.), keeps the last 3 `--merged` branches and deletes the rest from the remote
3. Finds stale branches that are fully merged into main but were never renamed, and deletes them

`wip-release` now runs prune automatically as step 11 after every release. No manual cleanup needed.

Rules: never deletes `main`, never deletes the current working branch, always keeps the last 3 per developer. `--dry-run` previews what would be deleted.

**Files changed:**
- `scripts/post-merge-rename.sh` ... new `--prune` flag, stale branch detection, keep-last-3 logic
- `tools/wip-release/core.mjs` ... step 11: automatic prune after every release

---

### License Enforcement Automation

**What we did:** Made license compliance automatic across three layers: CC Hook, wip-release gate, and one-command repo setup.

**Why:** `wip-license-guard` existed but was manual. Nobody remembered to run it. The dual-license + CLA standard from this release needs to be enforced, not just documented.

**How it works:**

**CC Hook** (`tools/wip-license-guard/hook.mjs`): PreToolUse hook for Claude Code. Intercepts `git commit` and `git push` commands. Checks LICENSE file, copyright, CLA.md, and README license section. Blocks if any check fails. Same pattern as `wip-file-guard`.

**wip-release gate** (step 0): Before bumping anything, wip-release checks license compliance. If `.license-guard.json` exists and any check fails, the release aborts with a clear message. No bad releases ship.

**`--from-standard` flag**: `wip-license-guard init --from-standard` applies WIP Computer defaults without prompting. Generates `.license-guard.json`, `LICENSE` (dual MIT+AGPLv3), and `CLA.md` in one command. For new repos, this is all you need.

**Files changed:**
- `tools/wip-license-guard/hook.mjs` ... new CC Hook (PreToolUse, blocks git commit/push)
- `tools/wip-license-guard/cli.mjs` ... `--from-standard` flag, CLA.md generation, CLA check in audit
- `tools/wip-release/core.mjs` ... step 0: license compliance gate

---

### README Polish (GPT Feedback Round 2)

**What we did:** Three targeted improvements based on GPT's review of v1.6.0.

**Karpathy quote shortened.** The full two-paragraph quote was too heavy for the README. Compressed to one line: *As Andrej Karpathy said: "Apps are for people. Tools are for LLMs, and increasingly, LLMs are the ones using software."* with a source link. Same message, doesn't interrupt the flow.

**One-line "why" on every feature.** Each tool now leads with the problem it solves before describing what it does:
- "AI agents forget release steps. This makes releases one command."
- "Dependencies change licenses without telling you. This catches it."
- "AI agents overwrite identity files by accident. This stops them."
- "Repos end up everywhere. This snaps them back to where they belong."

**Feedback filed:**
- `ai/feedback/2026-03-10--gpt--v1.6.0-readme-review.md`
- `ai/feedback/2026-03-10--grok--v1.6.0-summary.md`

---

### Install

```bash
npm install -g @wipcomputer/universal-installer
wip-install wipcomputer/wip-ai-devops-toolbox
```

Or update your local clone:
```bash
git pull origin main
```

---

Built by Parker Todd Brooks, Lēsa (OpenClaw, Claude Opus 4.6), Claude Code (Claude Opus 4.6).

## 1.6.0 (2026-03-10)

## v1.6.0: README Rewrite, Dual Licensing, License Guard, Release Notes Standard

Four systems that change how DevOps Toolbox presents itself, protects its licensing, and ships releases. The README is now for humans. Licensing is enforceable. Release notes tell a story.

This release spans PRs #46 through #50 and represents a complete rethink of how we present the toolbox, how we protect its licensing, and how we communicate what each release actually means.

---

### PR #46: License Format Standard

**What we did:** Rewrote the license section across the README and private Dev Guide to use a clear, scannable format that signals both openness and commercial intent.

**Why:** The old license section just said "MIT" in a badge. That's technically correct but it doesn't tell you the full story. We moved to dual licensing (MIT + AGPLv3) and needed a format that makes the distinction immediately clear: use it freely for personal work, need a commercial license if you're bundling it into something you sell.

**What changed:**
- License section switched to a code block format for readability: MIT for all CLI tools, MCP servers, skills, and hooks. AGPLv3 for commercial redistribution, marketplace listings, or bundling into paid services.
- Added "Commercial licenses available" as a one-line signal that this is a real product, not just an open source side project.
- AGPL renamed to AGPLv3 throughout for version specificity. Grok's feedback confirmed this matters for clarity.
- Private Dev Guide (`ai/DEV-GUIDE-private.md`) updated with the licensing standard so every repo going forward follows the same format.
- Fixed "Claude Code CLI" to "Claude Code" in attribution across all files.

**Commits:** `Update license section formatting for readability`, `License section: code block with Grok-style wording`, `License: personal vs commercial distinction, add standard to dev guide`, `License: AGPL -> AGPLv3 for version specificity`

---

### PR #47: LICENSE Files Across All Tools

**What we did:** Updated the actual LICENSE file in the root and all 10 sub-tool directories to dual MIT + AGPLv3.

**Why:** PR #46 changed how we talk about the license. This PR changed the legal documents themselves. Every sub-tool had its own LICENSE file that still said plain MIT. They all needed to match the new dual-license standard, and they needed to match each other exactly.

**What changed:**
- Root `LICENSE` rewritten to dual format. Section 1: MIT (full text). Section 2: GNU Affero General Public License v3.0 (commercial and cloud use). Starts with "Dual License: MIT + AGPLv3" so GitHub's license detection picks it up correctly.
- All 10 `tools/*/LICENSE` files updated to identical dual-license text with correct copyright holder (WIP Computer, Inc.).
- Bottom line on every LICENSE: "AGPLv3 for personal use is free. Commercial licenses available."

**Commits:** `LICENSE files: dual MIT+AGPLv3 on root and all sub-tools`

---

### PR #48: wip-license-guard (New Tool)

**What we did:** Built a new tool that enforces copyright, license format, and README structure across the toolbox.

**Why:** With 10 sub-tools, each needing its own LICENSE file, and a README standard that separates human content from technical content, manual enforcement doesn't scale. We needed a tool that catches drift before it ships. The tool also enforces the README standard from the session's feedback work: no install commands in the README (those go in TECHNICAL.md), no MCP config blocks, no Quick Start sections.

**How it works:**
- Interactive first-run (`wip-license-guard init`) asks for copyright holder, license type (MIT, AGPLv3, or dual MIT+AGPL), year, and attribution. Saves config to `.license-guard.json`.
- `wip-license-guard check` audits the repo against saved config. Checks LICENSE existence, copyright match, AGPLv3 terms (if dual-license), README license section, README structure.
- `wip-license-guard check --fix` auto-repairs: generates missing LICENSE files, updates wrong copyright, creates dual-license text.
- Toolbox-aware: automatically walks every `tools/` subdirectory and checks each sub-tool's LICENSE file.
- README structure standard enforcement: warns if README contains Quick Start sections, `npm install -g` commands, MCP config blocks, or Architecture/API/Config headings that belong in TECHNICAL.md.
- All 14 checks pass on this repo.

**New files:**
- `tools/wip-license-guard/cli.mjs` (268 lines) ... CLI entry point. Commands: `init`, `check`, `check --fix`, `help`.
- `tools/wip-license-guard/core.mjs` ... `generateLicense()` produces MIT, AGPL, or dual MIT+AGPLv3 LICENSE text. `generateReadmeBlock()` produces the README license section.
- `.license-guard.json` ... config: copyright "WIP Computer, Inc.", license "MIT+AGPL", year 2026.

**Interfaces:** CLI, Module. Beta stability.

**Commits:** `Add wip-license-guard tool and .license-guard.json config`

---

### PR #49: SKILL.md v1.5.1

**What we did:** Updated the skill documentation that AI agents read when you say "read the SKILL.md."

**Why:** The SKILL.md was stuck at v1.4.0. It didn't include wip-license-guard (new in this release), didn't have the interface coverage matrix, and used incorrect tool names. When someone tells their AI to read the SKILL.md, it needs to be current and accurate. Stale skill docs mean the AI gives wrong answers about what the tools can do.

**What changed:**
- Version bumped from v1.4.0 to v1.5.1.
- Added interfaces column to tool table: CLI, Module, MCP, OpenClaw, Skill, CC Hook for every tool.
- Added wip-license-guard to the tool list.
- Fixed tool names: `deploy-public` (not `deploy-public.sh`), `post-merge-rename` (not `post-merge-rename.sh`).
- Added "Talk to Your Tools" section with concrete MCP prompts: "Scan all dependencies for license changes" calls `license_scan`. "Check if memory-crystal can go public" calls `repo_permissions_check`. Etc.
- Added license section matching the new README format.
- Updated frontmatter description and capabilities.
- Added SKILL.md staleness warning to wip-release: warns when SKILL.md version falls more than a patch behind the release version, so this can't happen again silently.

**Commits:** `SKILL.md: update to v1.5.1 with full tool table and interfaces`

---

### PR #50: README Rewrite + Release Notes Standard

**What we did:** Rewrote the entire README based on external feedback, and upgraded the release pipeline to enforce narrative release notes.

**Why:** External feedback from Grok and GPT confirmed what we suspected: the README was developer-brain. Install commands, MCP tool mappings, and Quick Start sections front and center. That's what developers write for themselves. It's not what someone landing on the repo needs to see. They want to know: what does this do for me?

The release notes problem came up during this same work. Every release was producing commit lists instead of stories. Parker had to manually rewrite the notes every time. That needed to be fixed at the tooling level.

**README changes:**

The README now follows a strict standard: tagline, "Teach Your AI to Dev" prompt block, features with stability tags, interface coverage matrix, and license. No install commands. No technical implementation details.

- **Removed Quick Start section.** Install commands belong in TECHNICAL.md, not the README. Added a guard in wip-license-guard to catch `npm install -g` commands and Quick Start headings in any README going forward.
- **Removed "Talk to Your Tools" MCP examples.** These are for AIs, not humans. Moved to SKILL.md where they belong.
- **Added Karpathy quote.** The sensor/actuator framing from Andrej Karpathy anchors the Features section. Both paragraphs, "Andrej Karpathy put it clearly:" intro, Source link. This is the future of software: not apps, tools.
- **Added Interface Coverage matrix.** Single table showing all 10 tools and their six possible interfaces. At a glance you can see what ships as CLI, Module, MCP, OpenClaw, Skill, or CC Hook.
- **Added "Can I use this?" section.** Plain-English licensing examples. "Yes, freely:" for personal use. "Need a commercial license:" for bundling into products. Last bullet: "Fork it and send us feedback via PRs (we'd love that)."
- **Added License Guard to features list.** New tool from PR #48 needed to be in the features section.

**Release pipeline changes:**

Three changes to `wip-release` that make release notes a first-class part of the process:

1. **Quality warning.** When `--notes` is missing, too short (under 50 characters), or looks like a changelog entry (starts with "fix:", "add:", "update:"), wip-release warns: "Explain what was built, why, and why it matters."

2. **`--notes-file` flag.** Pass a markdown file with the full release narrative: `wip-release minor --notes-file=RELEASE-NOTES-v{version}.md`. This is how you write proper release notes and review them before they go live.

3. **Commits fold under narrative.** Commit history is still included, but inside a collapsible `<details>` section labeled "What changed (commits)". The narrative is the headline. The commits are supporting detail.

**New convention:** `RELEASE-NOTES-v{version}.md` lives on the feature branch. It's part of the PR diff. You review the release notes alongside the code. When the PR merges, `wip-release` reads from the file. The notes you approved are the notes that ship.

**Files changed:**
- `README.md` ... full rewrite
- `TECHNICAL.md` ... received Quick Start and npm install commands from README
- `tools/wip-release/core.mjs` ... `buildReleaseNotes()` restructured, new `warnIfNotesAreThin()`
- `tools/wip-release/cli.js` ... new `--notes-file=path` flag
- `tools/wip-license-guard/cli.mjs` ... README structure standard checks added
- `RELEASE-NOTES-v{version}.md` ... new convention file
- `ai/notes/2026-03-10--grok-feedback--readme-and-licensing.md` ... Grok feedback documented
- `ai/notes/2026-03-10--gpt-feedback--product-and-adoption.md` ... GPT feedback documented
- `ai/plan/current/2026-03-10--cc-mini--readme-polish-and-mcp-examples.md` ... 7-phase plan, all complete

**Commits:** `Add feedback notes, plan for README polish + MCP examples`, `README: golden path, MCP examples, interface matrix, license examples`, `Plan: mark phases 1-5 as DONE`, `README: add Karpathy quote on tools vs apps`, `wip-license-guard: add README structure standard checks`, `Move Quick Start to TECHNICAL.md, guard against install commands in README`, `Remove Talk to Your Tools section from README`, `README: full Karpathy argument with both quotes and source link`, `License: replace cloud instances bullet with fork/PR invitation`, `Karpathy quote: remove headline, inline attribution, semicolon`, `Fix Karpathy quote format: intro line, source outside blockquote`, `wip-release: narrative release notes standard`, `Add RELEASE-NOTES-v{version}.md for PR review`

---

### Install

```bash
npm install -g @wipcomputer/universal-installer
wip-install wipcomputer/wip-ai-devops-toolbox
```

Or update your local clone:
```bash
git pull origin main
```

---

Built by Parker Todd Brooks, Lēsa (OpenClaw, Claude Opus 4.6), Claude Code (Claude Opus 4.6).

## 1.4.0 (2026-03-09)

MCP unlock. All core tools are now agent-callable.

### MCP Servers (new)
- **wip-release**: `mcp-server.mjs` wrapping `core.mjs`. Tools: `release`, `release_status`
- **wip-license-hook**: `mcp-server.mjs` wrapping compiled `dist/`. Tools: `license_scan`, `license_audit`, `license_gate`, `license_ledger`
- **wip-repo-permissions-hook**: `mcp-server.mjs` wrapping `core.mjs`. Tools: `repo_permissions_check`, `repo_permissions_audit`
- **wip-repos**: `mcp-server.mjs` wrapping `core.mjs`. Tools: `repos_check`, `repos_sync_plan`, `repos_add`, `repos_move`, `repos_tree`

### SKILL.md files (new)
- **wip-repos**: added SKILL.md (was the only tool without one)
- **deploy-public**: added `scripts/SKILL-deploy-public.md`
- **post-merge-rename**: added `scripts/SKILL-post-merge-rename.md`

### Interface updates
- wip-release SKILL.md: interface updated from CLI to [cli, module, mcp], added MCP section
- wip-license-hook SKILL.md: added version, interface [cli, mcp], added MCP section
- wip-repo-permissions-hook SKILL.md: interface updated to [cli, module, mcp, hook, plugin], added MCP section
- All 4 tools: `@modelcontextprotocol/sdk` added as dependency

### Dev Guide updates
- Added "Universal Installer Checklist" section to DEV-GUIDE-GENERAL-PUBLIC.md
- Added "Universal Installer ... Dogfooding Rule" section to private Dev Guide
- Documented the v1.3.0 zero-MCP-servers incident

### Other
- Root SKILL.md bumped to 1.4.0, added all missing tools (wip-file-guard, wip-universal-installer, wip-repos, LDM Dev Tools.app), added MCP Servers section
- README source code table updated with mcp-server.mjs files

## 1.3.0 (2026-03-09)

Toolbox consolidation. Three new tools added.

### New tools
- **wip-file-guard**: blocks destructive edits to protected identity files. For Claude Code CLI and OpenClaw. Previously standalone repo, now folded into toolbox.
- **wip-universal-installer**: The Universal Interface specification for agent-native software. Six interfaces: CLI, Module, MCP Server, OpenClaw Plugin, Skill, Claude Code Hook. Previously standalone repo, now folded into toolbox.
- **wip-repos**: repo manifest reconciler. Makes repos-manifest.json the single source of truth for repo organization. Like prettier for folder structure. New tool, built from scratch.

### Other changes
- `UNIVERSAL-INTERFACE.md` promoted to repo root (from wip-universal-installer SPEC.md)
- README updated with all three new tools, source code table, install commands
- Standalone repos renamed to `-deprecated` on GitHub
- Toolbox now has 9 tools. All self-contained, zero shared dependencies.

## 1.2.0 (2026-03-09)

Major repo reorganization and Dev Guide expansion.

### Repo structure
- Separated public Dev Guide from private conventions
- `guide/DEV-GUIDE.md` → `DEV-GUIDE-GENERAL-PUBLIC.md` (genericized, root level, goes public)
- `ai/DEV-GUIDE-private.md` → `ai/DEV-GUIDE-FOR-WIP-ONLY-PRIVATE.md` (WIP-specific conventions)
- `guide/scripts/` → `scripts/` (moved to root level)
- Old `guide/` folder trashed

### New Dev Guide sections
- Post-merge branch rename convention (never delete branches, rename with `--merged-YYYY-MM-DD`)
- Repo directory structure (standard layout, staging folder conventions, create as `-private` from day one)
- The manifest (`repos-manifest.json` as source of truth for repo locations)
- Privatize Before You Work rule
- Cloudflare Workers deploy guard (commit before deploy, guarded npm scripts)
- PR checklist for private repos (dev update, roadmap, readme-first, plan archival)
- Expanded `_trash` convention
- Warning: never use `--no-publish` before `deploy-public.sh`

### New script
- `scripts/post-merge-rename.sh`: scans for merged branches missing `--merged-YYYY-MM-DD` suffix and renames them. Runs automatically as wip-release step 10, or standalone.

### README and SKILL.md
- Added post-merge-rename.sh to tools section and source table
- Fixed all paths for reorg
- Updated Dev Guide description with new sections

## 1.1.3 (2026-03-01)

- Fix npx package name in pre-pull.sh and pre-push.sh (@wipcomputer/license-hook → @wipcomputer/wip-license-hook)
- Fix wip-release test script (cli.mjs → cli.js)
- Clean up wip-release CHANGELOG blank lines
- Add visibility-audit.sh to DEV-GUIDE .app structure diagram
- Remove duplicate skill/SKILL.md subfolder

## 1.1.2 (2026-03-01)

- SKILL.md: sync version to 1.1.2
- CHANGELOG: add missing v1.1.0 and v1.1.1 entries
- ldm-jobs README: add visibility-audit.sh documentation

## 1.1.1 (2026-03-01)

- README: add wip-repo-permissions-hook section, source code table entry, cron schedule
- SKILL.md: bump version, add repo-visibility-guard capability, add tool section

## 1.1.0 (2026-03-01)

- New tool: wip-repo-permissions-hook. Blocks repos from going public without a -private counterpart
- Surfaces: CLI (check, audit, can-publish), Claude Code PreToolUse hook, OpenClaw plugin
- New cron job: visibility-audit.sh for LDM Dev Tools.app
- DEV-GUIDE: add hard rule for public/private repo pattern

## 1.0.4 (2026-03-01)

- DEV-GUIDE: replace inbox/punchlist system with per-agent todo files (To Do, Done, Deprecated. Never delete.)

## 1.0.3 (2026-02-28)

- deploy-public.sh: auto-detect harness ID from private repo path (cc-mini/, cc-air/, oc-lesa-mini/)

## 1.0.2 (2026-02-28)

- deploy-public.sh: fix branch prefix from mini/ to cc-mini/ per harness naming convention

## 1.0.1 (2026-02-28)

- DEV-GUIDE: add multi-agent clone workflow and harness branch convention (cc-mini/, cc-air/, lesa-mini/)

## 1.0.0 (2026-02-28)

- Production release: all tools battle-tested across 100+ repos, 200+ releases
- All source code visible and auditable in repo (no closed binaries)
- wip-license-hook bumped to v1.0.0
- LDM Dev Tools.app job scripts extracted to tools/ldm-jobs/
- Real-world example: wip-universal-installer release history
- Source code table, build instructions, and dev guide in README
- Standalone repos (wip-release, wip-license-hook) merged into umbrella

## 0.2.1 (2026-02-28)

- deploy-public.sh: fix release sync for repos without package.json (falls back to latest git tag)

## 0.2.0 (2026-02-28)

- deploy-public.sh: sync GitHub releases to public repos (pulls notes, rewrites references)
- DEV-GUIDE: add release quality standards (contributors, release notes, npm, both repos)
- DEV-GUIDE: add scheduled automation (.app pattern) documentation
- DEV-GUIDE: add built-by attribution standard
- LDM Dev Tools.app: macOS automation wrapper for cron jobs with Full Disk Access
- Add .npmignore to exclude ai/ from npm packages

## 0.1.1 (2026-02-27)

- DEV-GUIDE: add "never work on main" rule
- DEV-GUIDE: clarify private repo is the only local clone needed

## 0.1.0 (2026-02-27)

- Initial release: unified dev toolkit
- Includes wip-release (v1.2.4) and wip-license-hook (v0.1.0)
- DEV-GUIDE: general best practices for AI-assisted development
- deploy-public.sh: private-to-public repo sync tool


path: CLA.md
content: ###### WIP Computer

# Contributor License Agreement

By submitting a pull request to this repository, you agree to the following:

1. **You grant WIP Computer, Inc. a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license** to use, reproduce, modify, distribute, sublicense, and otherwise exploit your contribution under any license, including commercial licenses.

2. **You retain copyright** to your contribution. This agreement does not transfer ownership. You can use your own code however you want.

3. **You confirm** that your contribution is your original work, or that you have the right to submit it under these terms.

4. **You understand** that your contribution may be used in both open source and commercial versions of this software.

This is standard open source governance. Apache, Google, Meta, and Anthropic all use similar agreements. The goal is simple: keep the tools free for everyone while allowing WIP Computer, Inc. to offer commercial licenses to companies that need them.

Using these tools to build your own software is always free. This agreement only matters if WIP Computer, Inc. needs to relicense the codebase commercially.

If you have questions, open an issue or reach out.


path: DEV-GUIDE-GENERAL-PUBLIC.md
content: # Dev Guide ... Best Practices for AI-Assisted Development

**WIP team members: also read the private Dev Guide at `~/wipcomputerinc/settings/templates/dev-guide-private.md`.** It covers WIP-specific conventions (branch prefixes, agent IDs, deploy paths, incidents) that supplement everything below. Neither guide is complete without the other.

## Repo Structure Convention

Every project follows this split:

### Public Repo
Clean. Code only.
- `README.md` ... what it is, how to use it
- `LICENSE` ... MIT (verified, always)
- `SKILL.md` ... agent skill definition (if applicable)
- `src/` or `core/` ... source code
- `cli/` ... CLI wrapper
- `package.json` / `pyproject.toml` ... package config
- `CHANGELOG.md` ... release notes

**No dev noise.** No todos, no conversations, no internal notes.

### Plans and Dev Notes (per-repo `ai/` folder)

Plans, todos, dev updates, and conversations live in the repo's own `ai/` folder. See the `ai/` folder section under Git Conventions for the full structure.

### Architecture (4-piece pattern)

Every tool follows the dual-interface architecture:
1. **core.ts** ... pure logic, zero framework deps
2. **cli.ts** ... thin wrapper (argv -> core -> stdout)
3. **mcp-server.ts** ... MCP wrapper for agents
4. *(optional)* **plugin wrapper** ... platform-specific integration

CLI is the universal fallback. MCP and plugin wrappers are optimizations.

## Release Process

### Branch, PR, Merge, Publish

```
1. Create feature branch:  git checkout -b <prefix>/<feature>
2. Make changes, commit
3. Write release notes:    RELEASE-NOTES-v{next-version}.md (see below)
4. Push branch:            git push -u origin <prefix>/<feature>
5. Create PR:              gh pr create --title "..." --body "..."
6. Merge PR:               gh pr merge <number> --merge --delete-branch
7. Rename merged branch:   (see Post-Merge Branch Rename below)
8. Pull merged main:       git checkout main && git pull origin main
9. Release:                wip-release patch     (stable: full pipeline)
                           wip-release alpha     (prerelease: npm @alpha, silent)
                           wip-release beta      (prerelease: npm @beta, public notes)
                           wip-release hotfix    (urgent: npm @latest, no deploy-public)
                           # flags: --dry-run (preview), --no-publish (bump + tag only)
```

### Release Tracks

Four release tracks. Choose the right one for the situation:

| Track | Command | npm tag | Public code sync | When to use |
|-------|---------|---------|-----------------|-------------|
| Alpha | `wip-release alpha` | @alpha | No | Internal testing, not ready for users |
| Beta | `wip-release beta` | @beta | No | External testing, release candidate |
| Hotfix | `wip-release hotfix` | @latest | No | Urgent fix, skip deploy-public |
| Stable | `wip-release patch/minor/major` | @latest | Yes | Normal release, full pipeline |

**Alpha** is silent by default. No public release notes, no code sync. Add `--release-notes` to create a prerelease on the public GitHub repo.

**Beta** publishes prerelease notes to the public GitHub repo by default. Add `--no-release-notes` to skip.

**Hotfix** publishes to npm @latest and creates a release on the public GitHub repo, but does NOT run deploy-public (no code sync). Use this when you need a fix in npm immediately but the public repo code can wait for the next stable release.

**Stable** is the existing behavior. Full pipeline: npm @latest, deploy-public (code sync), full release notes.

Version numbering:
- Alpha: `1.9.68-alpha.1`, `1.9.68-alpha.2` (increments on repeat)
- Beta: `1.9.68-beta.1`, `1.9.68-beta.2` (increments on repeat)
- Hotfix: normal patch bump (`1.9.67` -> `1.9.68`)
- Stable: normal bump (patch/minor/major)

Install integration:
```bash
ldm install              # checks @latest (stable + hotfix)
ldm install --beta       # checks @beta
ldm install --alpha      # checks @alpha
```

**Important:**
- **Every change goes through a PR.** No direct pushes to main. Not even "just a README fix." Branch, PR, merge. Every time.
- **Never squash merge.** Every commit has co-authors and tells the story of how something was built. Squashing destroys attribution and history. Always use `--merge` or fast-forward. This applies to `gh pr merge`, manual merges, deploy-public.sh, and any other merge path. No exceptions. Always include `--delete-branch` so the PR branch is cleaned up automatically.
- **Never delete branches.** Branches are history. They tell the story of what was built and when. After merging, rename them (see below). Never `git branch -D` or `git push --delete` without renaming first.
- **Never use `--no-publish` before deploying to public.** `deploy-public.sh` pulls release notes from the private repo's GitHub release. If you skip the release with `--no-publish`, the public repo gets empty notes. Run the full pipeline first.
- After merging, switch back to your dev branch. Don't sit on main.

### Release Notes on the Branch

**Every PR must include a `RELEASE-NOTES-v{next-version}.md` file.** This is how release notes get reviewed before publishing. Same pattern as code review: the notes are on the branch, visible in the PR, reviewed alongside the changes.

**How it works:**

1. Figure out the next version. Current is v0.7.2, this is a patch, so next is v0.7.3.
2. Create `RELEASE-NOTES-v0-7-3.md` in the repo root. **Dashes, not dots** in the filename.
3. Write the summary: what changed, why it matters, what it fixes. Narrative, not a changelog.
4. Commit it with the rest of your changes. It ships with the branch.
5. The PR now shows code changes AND release notes. Both get reviewed.
6. After merge, `wip-release patch` auto-detects the file and uses it as the release summary.
7. After release, `wip-release` moves the file to `ai/_trash/` automatically.

**The file is the summary paragraph.** `wip-release` builds the full structured release (Changes, Fixes, Docs, Files changed, Install, Attribution, Changelog) from git history. Your file provides the human-written context at the top.

**Three-source priority** (first match wins):
1. `--notes-file=path` ... explicit file path via CLI flag
2. `RELEASE-NOTES-v{ver}.md` ... auto-detected from repo root (this is the standard)
3. `ai/dev-updates/` ... today's dev update files (fallback only)

**If no release notes file exists,** `wip-release` falls back to `--notes="..."` or dev updates. But the standard is: write the file, commit it, review it in the PR. Don't skip this.

### Post-Merge Branch Rename

**Never delete branches after merging.** Instead, rename them with `--merged-YYYY-MM-DD` appended. This preserves history and makes it instantly clear which branches are done and when they were merged.

**Format:**
```
<original-branch-name>--merged-YYYY-MM-DD
```

**Examples:**
```
dev/fix-search                  -> dev/fix-search--merged-2026-03-08
agent-a/weekly-tuning           -> agent-a/weekly-tuning--merged-2026-03-08
team-b/add-relay                -> team-b/add-relay--merged-2026-03-08
```

**After merging a PR:**
```bash
# 1. Rename locally
git branch -m <prefix>/<feature> <prefix>/<feature>--merged-$(date +%Y-%m-%d)

# 2. Push renamed branch to remote
git push origin <prefix>/<feature>--merged-$(date +%Y-%m-%d)

# 3. Remove old remote branch name
git push origin --delete <prefix>/<feature>

# 4. Scan for any other merged branches that missed renaming
git branch --merged main | grep -v main | grep -v "\-\-merged\-" | while read branch; do
  echo "WARNING: $branch is merged but not renamed"
done
```

**The scan step is mandatory.** Every time you merge, check for stale branches that missed renaming. If you find any, rename them with the date they were merged (check `git log main` for the merge date, not today's date).

**Automation:** `wip-release` runs this scan automatically as step 10 of the release pipeline. It finds all local branches merged into main that haven't been renamed yet, renames them with the correct merge date, and pushes to remote. You don't have to do anything extra on release.

For repos where you merge but don't release immediately, use the standalone script:
```bash
bash scripts/post-merge-rename.sh            # scan + rename all
bash scripts/post-merge-rename.sh --dry-run   # preview only
bash scripts/post-merge-rename.sh <branch>    # rename specific branch
```
- Use scoped npm tokens for publishing, not personal credentials.

### Release Quality Standards

**Every release must have exhaustive, categorized notes.** People use our software. Sloppy notes are embarrassing. Look at [OpenClaw releases](https://github.com/openclaw/openclaw/releases) as the benchmark.

`wip-release` generates structured notes automatically:

1. **Changes** ... new features, refactors, additions. One bullet per commit with hash.
2. **Fixes** ... bug fixes, hotfixes. One bullet per commit with hash.
3. **Docs** ... README, TECHNICAL, RELAY, any documentation changes.
4. **Files changed** ... diffstat (excludes `ai/` folder).
5. **Install** ... npm install command + git pull.
6. **Attribution** ... Built-by line.
7. **Full changelog** ... GitHub compare URL.

The `--notes` flag provides the summary paragraph at the top. The tool builds everything else from git history.

**For major releases (minor/major bumps):** the auto-generated notes are a starting point. Always review and expand them. Add context, describe architectural changes, explain why things changed. A commit subject like "Add cc-poller.ts" should become a paragraph explaining what the poller does, why it replaces the old hook, and what problem it solves.

**For patch releases:** auto-generated notes are usually sufficient. Review before publishing.

**Never publish a release with just a one-liner.** If two days of work went into it, the release notes should reflect that.

#### Release Checklist

Every release must also have:

1. **All contributors represented.** Every team member (human and AI) must have authored at least one commit in the repo. GitHub tracks contributors by commit author, not co-author trailers. If a contributor is missing, make a real commit with `--author`.
2. **Release on both repos.** The private repo gets the release from wip-release. The public repo gets a matching release from deploy-public.sh. Both must show the release in their GitHub Releases tab.
3. **npm package published.** Available via `npm install <package-name>@<version>`. Verify after publishing.
4. **CHANGELOG.md updated.** wip-release handles this, but verify it's accurate and complete.

**After every release, verify all of these.** Check the public repo's GitHub page. Does it show the release? Does it show all three contributors? Are the release notes complete? Is the npm package available? If any of these are missing, fix it before moving on.

### Release Order (Critical)

The release flow must happen in this exact order:

1. **Merge PR to main** on the private repo
2. **`wip-release`** on the private repo (bumps version, creates tag, creates GitHub release with full notes, publishes npm)
3. **`deploy-public`** to sync to the public repo (pulls release notes from private repo's GitHub release)

If you skip step 2 or do it manually (e.g. `git tag` + `git push` without creating a GitHub release), `deploy-public` will create the public release with empty notes. The script pulls notes from the private repo's GitHub release. No release on private = no notes on public.

### Merge, Deploy, Install ... Three Separate Steps

These are three distinct actions. Never combine them.

| Step | What it means | What happens |
|------|--------------|-------------|
| **Merge** | Development done | PR merged to private repo's main. Code lands. Nothing else changes. |
| **Deploy** | Ship to public | `wip-release` + `deploy-public.sh`. Package published. Available to the world. **Not on your machine yet.** |
| **Install** | Put it on your system | Run the install prompt (`crystal init`, `ldm install`, etc.). Only when the user says "install." |

After Deploy, stop. Do not copy files to extension directories. Do not run `npm install -g`. Do not run `npm link`. The user tests the install flow by running the install prompt. That's how you dogfood.

**If you must release manually** (no root package.json, toolbox repos, etc.):
1. Update CHANGELOG.md and SKILL.md version
2. Commit, PR, merge
3. `git tag vX.Y.Z && git push origin vX.Y.Z`
4. `gh release create vX.Y.Z --title "vX.Y.Z" --notes "..."` on the PRIVATE repo first
5. THEN run `deploy-public`

The GitHub release on the private repo must exist before deploy-public runs. This is not optional.

### Universal Installer Checklist

Every tool must be verified with the Universal Installer before release. This is not optional.

**Before every release:**
```bash
wip-install /path/to/tool --dry-run
```

This shows which interfaces are detected and which are missing.

**Minimum for agent-callable tools:**
- Module (`main` or `exports` in package.json)
- Skill (SKILL.md with YAML frontmatter)
- MCP Server (`mcp-server.mjs` wrapping the core module)

**Full interface coverage (the goal):**
- CLI (`bin` in package.json)
- Module (`main`/`exports`)
- MCP Server (`mcp-server.mjs`)
- OpenClaw Plugin (`openclaw.plugin.json`, only for tools with lifecycle hooks)
- Skill (`SKILL.md`)
- Claude Code Hook (`guard.mjs` or `claudeCode.hook`, only for tools that guard operations)

**For toolbox repos** (repos with multiple tools in `tools/` subfolders): apply this checklist to each sub-tool, not just the root. Every sub-tool gets its own package.json, SKILL.md, and interface files.

**Dogfood rule:** After releasing, run `wip-install` on the toolbox itself to reinstall. Eat your own cooking.

### Pre-Publish Checklist

Before any repo goes public:

1. [ ] Code complete (all punchlist items done)
2. [ ] Code review (architecture, edge cases, quality)
3. [ ] Human review (spec, UX, direction)
4. [ ] LICENSE file present (MIT, verified)
5. [ ] README covers usage, installation, examples
6. [ ] CHANGELOG started
7. [ ] npm package published (scoped)
8. [ ] GitHub release created with tag
9. [ ] License compliance ledger initialized for all dependencies

## Cloudflare Workers Deploy

Some repos deploy to Cloudflare Workers via `wrangler deploy`. Same rules as git: **never deploy uncommitted code.**

### The Rule

**Commit first. Deploy second. Always.** The source that produced the deployed worker must exist in git before it goes to Cloudflare. If something breaks, we need to know exactly what's running.

### Deploy Workflow

```
1. Write code on feature branch
2. Build:                npm run build:demo (or whatever the build script is)
3. Test locally:         npm run dev:demo (wrangler dev)
4. Commit source:        git add src/worker-*.ts wrangler-*.toml && git commit
5. Push + PR + merge:    normal PR flow
6. Deploy:               npm run deploy:demo (wrangler deploy)
```

**Steps 4-5 happen BEFORE step 6.** Not after. Not "I'll commit later." The deploy command should never run on uncommitted code.

### Deploy Guard

Every repo with a `wrangler*.toml` should use guarded deploy scripts in package.json:

```json
"deploy:demo": "bash -c 'git diff --quiet HEAD -- src/ wrangler-demo.toml || (echo \"ERROR: uncommitted changes. commit before deploying.\" && exit 1)' && wrangler deploy --config wrangler-demo.toml"
```

This checks that all source files are committed before `wrangler deploy` runs. If anything is dirty, it refuses.

### What Gets Tracked

The deployed worker is the compiled output of committed source. The chain is:

```
source (git) -> build (tsup) -> dist/*.js -> wrangler deploy -> Cloudflare edge
```

We track the source. The build is reproducible from source. The deploy is reproducible from the build. If we have the git commit, we can reconstruct exactly what's running.

## License Compliance

Use `wip-license-hook` for license rug-pull detection:
- Pre-pull hook: blocks upstream merges if license changed
- Pre-push hook: alerts if upstream has drifted
- LICENSE snapshots archived at adoption
- Daily cron scan of all dependencies
- Dashboard published for public verification

**Rule: never merge upstream if license changed. Hard stop.**

## Git Conventions

### Never Work on Main

**Main is for merged, released code only.** Never make changes directly on main. Every repo should have a dev branch checked out as the working branch at all times.

When you clone a repo or finish a PR, immediately create or switch to a dev branch:

```bash
git checkout -b <prefix>/dev           # new repo, first time
git checkout <prefix>/<feature>        # existing feature work
```

If you find yourself on main with uncommitted changes, stash, branch, and apply:

```bash
git stash
git checkout -b <prefix>/fix-name
git stash pop
```

### Branch Prefixes

Branch names use the **harness name** (agent + machine) as the prefix. Every harness is a distinct entity. Claude Code on the Mini is not the same as Claude Code on the Air.

```
<harness>/<feature>
```

Examples: `dev/fix-search`, `agent-a/add-relay`, `team-b/weekly-tuning`

### Multi-Agent Clone Workflow

**Every harness gets their own clone of every repo.** This prevents checkout collisions when multiple agents work on the same repo at the same time.

```
staff/
  Agent-A/
    repos/
      my-project-private/         <- agent-a works here, agent-a/ branches
  Agent-B/
    repos/
      my-project-private/         <- agent-b works here, agent-b/ branches
  Human/
    repos/
      my-project-private/         <- human works here, dev/ branches
```

**Rules:**
- Never work in another agent's folder. If Agent-A originated a repo, Agent-B still clones it to their own folder.
- Each harness uses their own branch prefix.
- PRs merge to `main` on GitHub. That's the shared integration point.
- If something needs to change in another agent's working tree, open a PR or ask them.

**When a new repo is created:**
1. Whoever creates it pushes to GitHub
2. Every other agent clones it to their own repos folder
3. Each agent creates their dev branch with their prefix

This is how we avoid the "two agents have different branches checked out in the same folder" problem. It doesn't work. Separate folders, separate clones, shared remote.

### Commit Messages

- Imperative mood, concise (`add: license scanner`, `fix: offline detection`)
- Co-author trailers for all contributors on every commit
- PRs for cross-agent edits: don't edit another agent's working tree directly
- Never push directly to main. Always branch, PR, merge. No exceptions.

### File Naming Convention

All files authored by an agent use this format:

```
YYYY-MM-DD--HH-MM-SS--{agent}--{description}.md
```

Single dashes within date and time. Double dashes between segments. 24-hour clock.

This applies to dev updates, plans, todos, notes, session exports, daily logs ... everything with an author and a timestamp.

### Daily Logs

Each entry is its own file, not appended to a shared file.

```
agents/{agent-id}/memory/daily/
  2026-02-27--17-45-30--agent-a--feature-deploy.md
  2026-02-27--19-12-00--agent-a--config-migration.md
```

One file per entry. Full timestamp. Agent ID in the name. Nothing gets overwritten or collided.

### The `ai/` Folder (per-repo standard)

Every repo gets an `ai/` folder. It holds all the thinking between humans and agents ... plans, dev updates, todos, conversations, notes. Scoped to the repo it belongs to.

```
ai/
  plan/              ... architecture plans, roadmaps, convention notes
  dev-updates/       ... what was built, session logs
  todos/
    Human-todo.md    ... human lead's action items
    Agent-A-todo.md  ... Agent A's action items
    Agent-B-todo.md  ... Agent B's action items
  notes/             ... research, raw conversation logs, references
```

### Todo Files

One file per person/agent. Named `{Name}-todo.md`. Lives in `ai/todos/`.

**Three sections, always in this order:**

```markdown
# {Name} ... {Project} To-Do

**Updated:** YYYY-MM-DD

---

## To Do
- [ ] Thing that needs doing
- [ ] Another thing

---

## Done
- [x] Thing that was completed ... YYYY-MM-DD

---

## Deprecated
- ~~Thing that's no longer needed~~ ... reason. (YYYY-MM-DD)
```

**Rules:**
- **Never delete anything.** Items move between sections, never off the page.
- **To Do** ... work that needs to happen.
- **Done** ... work that was completed. Check the box, add the date.
- **Deprecated** ... work that was planned but is no longer needed (code changed, approach changed, requirement dropped). Strikethrough the text, add the reason and date. This is NOT the same as Done. Deprecated means "we decided not to do this."
- **Update the date** at the top of the file every time you edit it.
- Each person/agent has exactly one file. Don't create per-date or per-feature todo files.

**Example todo files:**

| File | Who |
|------|-----|
| `Human-todo.md` | Human lead (setup, deploy, review) |
| `Agent-A-todo.md` | Agent A (code, docs, builds) |
| `Agent-B-todo.md` | Agent B (testing, integration) |

Add more as agents or team members are added.

### GitHub Issues

**Use GitHub Issues for actionable bugs, feature requests, and tasks.** The `ai/todos/` files are for rough planning and brainstorming. Once something becomes a concrete action item, it goes on GitHub.

**Why both?** Todos are quick, local, and low-friction. Issues are trackable, cross-referenceable, and visible to all agents and humans. Todos are where you think. Issues are where you commit to doing.

#### Filing Convention

Every issue filed by an agent must include:

1. **Attribution line** at the top of the body:
   ```
   > Filed by: <agent-name> (<agent-id>) on <YYYY-MM-DD>
   ```

2. **`filed-by` label** identifying the author:
   ```
   filed-by:<agent-id>
   ```
   This makes issues filterable by who created them. Create these labels per-agent on every repo in the org.

3. **Clear problem/solution structure.** State what's wrong, then what should change.

#### When to use issues vs todos

| Use | When |
|-----|------|
| GitHub Issue | Bug, feature request, task with a clear definition of done |
| `ai/todos/` | Brainstorming, rough planning, "we should think about..." |
| Both | Start in todos, promote to issue when it's concrete |

#### Public vs Private Issues

For repos following the public/private pattern:

- **Public repo issues** are for users. Someone installs your tool, finds a bug, files an issue on the public repo. Triage and respond there.
- **Private repo issues** are for the team. Internal work, architecture decisions, agent coordination.

**When a public issue needs internal work:**
1. Respond on the public issue ("Looking into this")
2. Open a private issue with the full context, link back (`Public: org/repo#42`)
3. Fix in private, release, deploy to public
4. Close the public issue with the version (`Fixed in v0.5.0`)

**When you find a bug internally:**
1. File on the private repo
2. Fix, release, deploy
3. No public issue needed unless it's worth announcing

The release is what connects public and private. No issue syncing, no mirroring. Public issues are the front door. Private issues are the workshop.

#### Agent ID Convention

Agents are identified by a structured ID that encodes platform, name, and machine:

```
[platform]-[agent]-[machine]
```

Examples: `oc-lesa-mini` (OpenClaw, Lesa, on mini), `cc-mini` (Claude Code, on mini), `cc-air` (Claude Code, on air).

This ID is used in:
- GitHub issue labels (`filed-by:*`)
- Memory systems (agent_id field)
- LDM agent config (`~/.ldm/agents/<id>/config.json`)
- Git branch prefixes

## Branch Protection

All repos should have branch protection on `main` with `enforce_admins=true`. This means:
- No direct pushes to main (even for admins)
- All changes go through PRs

**To add protection:**
```bash
gh api "repos/<org>/<repo>/branches/main/protection" -X PUT \
  -F "required_pull_request_reviews[required_approving_review_count]=0" \
  -F "enforce_admins=true" \
  -F "restrictions=null" \
  -F "required_status_checks=null"
```

## Worktree Workflow

**Every session starts in a worktree. No one works directly in the main working tree.**

The main working tree stays on `main` and is read-only in practice. All development happens in git worktrees. This keeps the primary clone clean, prevents accidental commits to main, and enables parallel work within a single agent.

### Worktree Location Convention

**All worktrees go in `.worktrees/` as a sibling to the repos directory.** Never create worktrees as siblings to repos directly. They look like real repos, confuse iCloud sync, and are hard to find/clean.

**Convention:** `.worktrees/<repo-name>--<branch-suffix>/`

```
repos/
  ldm-os/
    components/
      memory-crystal-private/     <- real repo
    devops/
      wip-ai-devops-toolbox-private/  <- real repo
  .worktrees/
    memory-crystal-private--cc-mini--fix-search/   <- worktree
    wip-ai-devops-toolbox-private--cc-mini--guard/  <- worktree
```

### Starting a Worktree

**Preferred:** Use the `ldm worktree` command:
```bash
ldm worktree add cc-mini/fix-bug    # auto-detects repo, creates in .worktrees/
```

**From Claude Code:**
```bash
claude --worktree <name>
```

**Manual:**
```bash
git worktree add ../.worktrees/<repo>--<branch> -b <branch>
```

The branch guard warns if you create worktrees outside `.worktrees/` or `.claude/worktrees/`.

### Branch Naming

Worktree branches follow the same prefix convention as regular branches:

```
<harness>/<feature>
```

Examples: `cc-mini/fix-search`, `lesa-mini/add-relay`, `cc-air/weekly-tuning`

The worktree name and the branch name don't have to match, but the branch must use your harness prefix.

### Subagents and Parallel Work

Subagents use `isolation: "worktree"` for parallel tasks. Each subagent gets its own worktree, its own branch, and can commit independently without interfering with the parent session or other subagents.

This is the safe way to do parallel work within a single agent. Repos-per-agent solves cross-agent isolation. Worktrees solve within-agent parallelism.

### Commit Before Session Ends

**Always commit and push before a session ends.** Worktree cleanup deletes the entire worktree directory, including any uncommitted work. If it's not committed and pushed, it's gone.

```bash
git add <files>
git commit -m "description"
git push -u origin <prefix>/<feature>
```

### Release from the Main Working Tree

**`wip-release` must run from the main working tree, not a worktree.** The release pipeline expects to be on `main` in the primary clone. After merging your PR, switch to the main working tree to run the release:

```bash
cd /path/to/repo          # the main working tree, not .claude/worktrees/...
git checkout main && git pull
wip-release patch --notes="description"
```

### Gitignore

**`.claude/worktrees/` must be in `.gitignore`.** Worktrees are local, ephemeral, and per-machine. They should never be committed.

```
# .gitignore
.claude/worktrees/
```

Add this to every repo that uses worktrees.

## Review Flow

```
Agent builds -> pushes to dev branch
  -> Code review (another agent or human)
  -> Human reviews (direction, spec)
  -> merge to main
  -> publish (npm, GitHub, skill registry)
```

## PR Checklist (Private Repos)

Every PR to a private repo must include product doc updates. This is not optional. Do it before merging, not after.

### Required on every PR:

1. **Dev update.** Write a dev update in `ai/dev-updates/` documenting what changed, key decisions, and what's next. Format: `YYYY-MM-DD--HH-MM--agent--description.md`.

2. **Roadmap update.** Review `ai/product/plans-prds/roadmap.md`:
   - Move completed items from **Upcoming** to **Done** (with `[x]` checkboxes)
   - Add new items to **Upcoming** if the work revealed them
   - Move abandoned items to **Deprecated** (never delete)

3. **readme-first update.** Review `ai/product/readme-first.md`:
   - Update **What's Built** and **What's Missing** sections
   - Update any stats, counts, or version references
   - Update the **Databases** or architecture sections if they changed

4. **Plan archival.** If a plan in `plans-prds/current/` is complete, move it to `plans-prds/archive-complete/`.

### Why this matters:

Product docs drift fast. If roadmap updates only happen "when someone remembers," the roadmap becomes fiction. Tying updates to PRs means the docs stay current by default, not by heroics.

### Release notes:

Release notes are the public face of the project. They must be comprehensive. One-liners like "Release v0.6.0" are unacceptable. Every feature, every change, documented section by section. This applies to both private and public GitHub releases.

## Feature Planning: 5 Mandatory Questions

Before implementing any feature that changes how the system works (installer, config, deploy, architecture), answer these 5 questions in your plan or PR description. Not optional. Not "consider this." Answer all five or the plan is incomplete.

1. **What source files change?** (in the repo)
2. **What does `ldm install` deploy?** (templates, rules, docs, boot config, CLAUDE.md, skills)
3. **What needs to update for fresh install vs existing install?**
4. **What docs need updating?** (repo docs, settings/docs, website)
5. **What are ALL the files the installer touches on deploy?**

If you can't answer #5, you don't understand the change well enough to ship it.

## Doc Update Dependencies

When you change a file on the left, you MUST also update the files on the right. This is not optional.

| If you change | You must also update |
|--------------|---------------------|
| `SKILL.md` | `references/`, `settings/docs/how-install-works.md`, wip.computer/install/ (auto via wip-release) |
| `lib/deploy.mjs` | `settings/docs/how-install-works.md`, `docs/universal-installer/SPEC.md`, `docs/universal-installer/TECHNICAL.md` |
| `catalog.json` | `settings/docs/what-is-ldm-os.md`, `README.md`, `docs/skills/README.md` |
| `bin/ldm.js` (init) | `settings/docs/how-install-works.md`, `settings/docs/system-directories.md` |
| `shared/rules/*` | `settings/docs/how-rules-and-commands-work.md` |
| `shared/boot/*` | `settings/docs/how-agents-work.md` |
| `lib/detect.mjs` | `docs/universal-installer/SPEC.md`, `settings/docs/how-install-works.md` |
| Backup scripts | `settings/docs/how-backup-works.md` |
| Agent identity files | `settings/docs/how-agents-work.md` |
| Any repo `README.md` | Public repo README (via deploy-public.sh) |

Machine-readable version: `~/wipcomputerinc/settings/docs/change-dependencies.json`

### Three doc layers

Every change flows through three layers:

1. **Repo docs** (generic, source of truth): README.md, TECHNICAL.md, SPEC.md per repo. Written for anyone.
2. **Settings docs** (personalized, deployed by ldm install): `~/wipcomputerinc/settings/docs/`. Written for YOUR system. Personalized from config.json.
3. **Website docs** (public): wip.computer. SKILL.md auto-deployed by wip-release. Other docs via Mintlify or deploy script.

If repo docs change but settings docs don't update, the user's local docs drift. If settings docs change but the website doesn't, the public docs drift. All three layers must stay in sync.

## Repo Directory Structure

### The Standard Layout

All repos are organized into this directory structure. Every agent on every machine must follow this layout. The folders are organizational categories, not monorepos. Each repo inside is its own independent git repo.

```
repos/
├── <project>/                   ← NOT a repo. Organizes project repos by category.
│   ├── apis/                    ← API integrations
│   ├── apps/                    ← user-facing apps
│   ├── components/              ← core components
│   ├── operations/              ← dev tools, release pipeline
│   └── utilities/               ← support tools
├── <company>/                   ← Repo. Company docs (always private).
├── third-party-repos/           ← NOT a repo. Forks and external repos.
├── _sort/                       ← NOT a repo. Repos not yet categorized.
├── _sunsetted/                  ← NOT a repo. Deprecated repos.
└── _trash/                      ← NOT a repo. Deleted repos.
```

### Staging Folder Conventions

- **`_to-privatize/`** ... repos staged for privatization
- **`_sort/`** ... repos that need to be categorized or figured out
- **`_trash/`** ... deleted items (never truly delete, move here)
- **Underscore prefix** (`_`) keeps staging folders sorted to the top, visually separated from real repos

These conventions apply at every level: top-level `repos/`, inside project categories, and nested within staging folders.

### Creating a New Repo

**Always create repos as `-private` from day one.** Do not create a repo and privatize it later. Start with the right name and structure.

```bash
# 1. Pick the category
#    apis, apps, components, operations, utilities

# 2. Create on GitHub as private with -private suffix
gh repo create <org>/<name>-private --private

# 3. Clone into the correct category folder
cd repos/<project>/<category>/
git clone [REDACTED_SECRET]:<org>/<name>-private.git

# 4. Create the ai/ folder structure
cd <name>-private
mkdir -p ai/product/plans-prds/{upcoming,current,archive-complete}
mkdir -p ai/product/plans-prds/todos
mkdir -p ai/product/product-ideas
mkdir -p ai/product/notes/research
mkdir -p ai/dev-updates

# 5. Create your dev branch
git checkout -b <prefix>/dev
```

**Never create a repo without picking its category first.** If you don't know where it goes, put it in `_sort/` and figure it out before starting work.

### The Manifest

`repos/repos-manifest.json` is the source of truth for where every repo lives. It maps local paths to GitHub remotes. When a repo is created, moved, or renamed, update the manifest.

Every agent can use the manifest to sync their local directory structure. The goal: every agent on every machine has the same layout.

### Privatize Before You Work

**Do not start any work on a non-privatized repo.** If a repo is in `_to-privatize` and you need to work on it, run it through the privatization process first:

1. Rename the GitHub repo to `<name>-private`
2. Update the local remote URL (`git remote set-url origin ...`)
3. Rename the local folder to match
4. Then start your work

Working on a non-privatized repo means your `ai/` content (plans, todos, dev updates) gets committed to a repo that could accidentally go public. No exceptions.

---

## Public/Private Repo Pattern

### The Rule

**Never make a repo public unless it has a `-private` counterpart with all `ai/` content separated out.** If a repo doesn't have a `-private` counterpart yet, it stays private until one is created. No exceptions. Violating this exposes internal plans, todos, and development context.

**The private repo is the working repo. The public repo is everything except `ai/`.**

**You only need the private repo locally.** Clone `<name>-private`, work in it, release from it, deploy to public from it. Never clone the public repo for development. The public repo is a deployment target, not a working tree. The deploy script handles syncing.

Every repo has an `ai/` folder where agents and humans collaborate ... plans, todos, dev updates, notes, conversations. This is the development process. It doesn't ship publicly.

The private repo tracks everything, including `ai/`. The public repo is the same codebase without `ai/`. Two repos, same code, clean boundary.

```
<name>-private/      <- working repo (clone this one, work here)
  src/, README.md, LICENSE, package.json, SKILL.md ...
  ai/                <- plans, todos, notes, dev updates
    plan/
    todos/
    dev-updates/
    notes/

<name>/              <- public repo (deploy target only, never clone for dev)
  src/, README.md, LICENSE, package.json, SKILL.md ...
  (no ai/ folder)
```

### Why

The `ai/` folder contains personal notes, half-formed ideas, internal debates, agent inboxes. Useful for the team. Irrelevant to users. Can be taken out of context. Should not be public.

The public repo has everything an LLM or human needs to understand and use the project: README, code, docs, SKILL.md, LICENSE. The `ai/` folder is operational context, not conceptual context.

### Workflow

1. All work happens in the private repo
2. Merge PR to main on the private repo
3. Run `wip-release` on the private repo (version bump, changelog, npm publish, GitHub release)
4. Deploy to public repo (everything except `ai/`)

**The order matters.** Release first, then deploy. The public repo should always reflect a released version with correct version numbers, changelog, and SKILL.md.

```bash
# Step 1-2: normal PR flow on private repo
cd /path/to/private-repo
git checkout main && git pull origin main

# Step 3: release (MUST create GitHub release for deploy-public.sh to pull notes)
wip-release patch --notes="description of changes"

# Step 4: deploy to public (code sync + release)
bash deploy-public.sh /path/to/private-repo <org>/<public-repo>
```

**Never use `--no-publish` before deploying to public.** The `deploy-public.sh` script pulls release notes from the private repo's GitHub release. If the GitHub release doesn't exist (because `--no-publish` skipped it), the public release gets empty notes. Always run the full `wip-release` pipeline before `deploy-public.sh`.

The deploy script:
1. Clones the public repo
2. Rsyncs everything except `ai/` and `.git/`
3. Creates a branch, commits, opens a PR, merges it
4. Creates a matching GitHub release on the public repo (pulls notes from the private repo's release)

**After deploy, the public repo should show:**
- Updated code (matching private minus `ai/`)
- A GitHub release with the version tag and release notes
- npm package available via `npm install <package-name>`

**What goes where:**

| Artifact | Where it lives |
|----------|---------------|
| npm package | Public npm registry (anyone can install) |
| GitHub release (private) | `<name>-private` repo (internal reference) |
| GitHub release (public) | `<name>` repo (what users see) |
| GitHub Packages | Not used (npm registry is the source of truth) |

### Config-specific splits

Some repos also have deployment config that shouldn't be public (real paths, contacts, secrets references). Same pattern applies ... the private repo has `config.json`, the public repo has `config.example.json`.

**Key rule:** never put real paths, contacts, personal notes, or deployment values in the public repo.

## Scheduled Automation (.app Pattern)

macOS restricts cron and shell scripts from accessing protected files (Full Disk Access). The workaround: wrap automation in a native `.app` bundle and grant FDA to the app.

### How it works

A minimal macOS `.app` bundle that:
1. Contains a compiled Mach-O binary (so macOS recognizes it as a real app)
2. The binary calls a shell script that dispatches to individual job scripts
3. Jobs live in `YourApp.app/Contents/Resources/jobs/*.sh`
4. Adding a new job = dropping a new `.sh` file in that folder

### Structure

```
~/Applications/YourDevTools.app/
  Contents/
    Info.plist                    ... app metadata (bundle ID, version)
    MacOS/
      your-dev-tools              ... compiled binary (Mach-O, calls dispatcher)
      your-dev-tools-run          ... shell dispatcher (routes to jobs)
    Resources/
      jobs/
        backup.sh                 ... daily backup of databases + state
        branch-protect.sh         ... audit + enforce branch protection across org
        visibility-audit.sh       ... audit public repos for missing -private counterparts
```

### Setup

1. Build the app (or copy from dev-tools repo)
2. Drag the `.app` into **System Settings > Privacy & Security > Full Disk Access**
3. Schedule via cron:

```bash
0 0 * * * open -W ~/Applications/YourDevTools.app --args backup >> /tmp/dev-tools/cron.log 2>&1
0 1 * * * open -W ~/Applications/YourDevTools.app --args branch-protect >> /tmp/dev-tools/cron.log 2>&1
```

### Why not LaunchAgents?

LaunchAgents have been unreliable across macOS updates. FDA grants to `/bin/bash` and `cron` don't persist. The `.app` bundle is the one thing macOS consistently respects for FDA permissions.

### Adding a new job

Create a file in `Contents/Resources/jobs/`:

```bash
# ~/Applications/YourDevTools.app/Contents/Resources/jobs/my-job.sh
#!/bin/bash
echo "=== My job: $(date) ==="
# ... your automation here
echo "=== Done ==="
```

Then: `open -W ~/Applications/YourDevTools.app --args my-job`

### Logs

All job output goes to `/tmp/dev-tools/`:
- `dev-tools.log` ... dispatcher log (which jobs ran, exit codes)
- `<job-name>.log` ... individual job output
- `<job-name>-last-exit` ... last exit code (for monitoring)
- `<job-name>-last-run` ... last run timestamp

## The _trash Convention

**Never delete files. Move them to `_trash/`.** Every directory that might have discarded files should have a `_trash/` subfolder.

### Why:

- Space is cheap. Recovery from `_trash/` is instant. Recovery from git history requires knowing the commit, the path, and the exact filename.
- Files in `_trash/` are visible. You can browse them, grep them, copy them back. Deleted files are invisible unless you know they existed.
- It prevents the "wait, who deleted that?" conversation.

### Where it applies:

- **Repos:** `ai/product/plans-prds/_trash/`, `ai/product/product-ideas/_trash/`, etc.
- **Agent data:** workspace files, config backups, old extension versions
- **Extension installs:** old plugin versions before upgrade

### How:

```bash
# Instead of this:
rm old-file.md

# Do this:
mkdir -p _trash
mv old-file.md _trash/
```

Use `git mv` if the file is tracked. The underscore prefix sorts `_trash/` to the top of directory listings so it stays visible but out of the way.

### When to clean up:

Rarely. Maybe annually. If `_trash/` gets huge, archive it. But the default is: leave it. The cost of keeping files around is near zero. The cost of needing a file you deleted is real.


path: README.md
content: ###### WIP Computer

[![npm](https://img.shields.io/npm/v/@wipcomputer/universal-installer)](https://www.npmjs.com/package/@wipcomputer/universal-installer) [![CLI / TUI](https://img.shields.io/badge/interface-CLI_/_TUI-black)](https://github.com/wipcomputer/wip-ai-devops-toolbox/blob/main/tools/wip-universal-installer/install.js) [![MCP Server](https://img.shields.io/badge/interface-MCP_Server-black)](https://github.com/wipcomputer/wip-ai-devops-toolbox/blob/main/tools/wip-release/mcp-server.mjs) [![OpenClaw Plugin](https://img.shields.io/badge/interface-OpenClaw_Plugin-black)](https://github.com/wipcomputer/wip-ai-devops-toolbox/blob/main/tools/wip-repo-permissions-hook/openclaw.plugin.json) [![Claude Code Skill](https://img.shields.io/badge/interface-Claude_Code_Skill-black)](https://github.com/wipcomputer/wip-ai-devops-toolbox/blob/main/SKILL.md) [![Claude Code Hook](https://img.shields.io/badge/interface-Claude_Code_Hook-black)](https://github.com/wipcomputer/wip-ai-devops-toolbox/blob/main/tools/wip-file-guard/guard.mjs) [![Universal Interface Spec](https://img.shields.io/badge/Universal_Interface_Spec-black?style=flat&color=black)](https://github.com/wipcomputer/wip-ai-devops-toolbox/blob/main/tools/wip-universal-installer/SPEC.md)

# AI DevOps Toolbox

## Want your AI to dev? Here's what's working for us at WIP Computer.

Your AI writes code. But does it know how to release it? Check license compliance? Protect your identity files? Sync private repos to public? Follow a real development process?

AI DevOps Toolbox is the complete toolkit. Built by a team of humans and AIs shipping real software together.

## Teach your AI to use DevOps Toolbox

Open your AI and paste this:

```
Read wip.computer/install/wip-ai-devops-toolbox.txt

Then explain:
1. What is AI DevOps Toolbox?
2. What does it install on my system?
3. What changes for us? (this AI)
4. What changes across all my AIs?

Check if AI DevOps Toolbox is already installed.

If it is, show me what I have and what's new.

Then ask:
- Do you have questions?
- Want to see a dry run?

If I say yes, run: ldm install wipcomputer/wip-ai-devops-toolbox --dry-run

Show me exactly what will change. Don't install anything until I say "install".
```

Your agent will read the spec, explain everything, and do a dry-run install first so you can see exactly what changes before anything is written to your system.

## AI DevOps Toolbox Features

Every tool ships as one or more **interfaces:** the ways you and your AI can use it. **CLI** runs in your terminal. **Module** imports into your code. **MCP** connects to any AI that supports Model Context Protocol. **OC Plugin** plugs into the OpenClaw agent platform. **Skill** teaches your AI how to use the tool via a SKILL.md file (works in both Claude Code and OpenClaw). **CC Hook** runs automatically inside Claude Code on specific events.

As Andrej Karpathy [said](https://x.com/karpathy/status/2024583544157458452): *"Apps are for people. Tools are for LLMs, and increasingly, LLMs are the ones using software."*

### Setup & Onboarding

**Universal Installer**
- Teaches your AI to take anything you build and make it work across every AI interface. You write code in any language. This tool turns it into a CLI, MCP Server, OpenClaw Plugin, Skill, and Claude Code Hook. One command, all six interfaces.
- Detects what a repo supports and deploys it all. Toolbox mode walks every sub-tool automatically
- **Interfaces:** CLI, Module, Skill
- *Stable*
- [Read more about Universal Installer](https://github.com/wipcomputer/wip-ldm-os/blob/main/docs/universal-installer.md)

**Dev Guide**
- Your team's conventions, baked in. Release process, repo structure, branch protection, the `ai/` folder standard.
- Best practices for AI-assisted development teams. Covers everything from branching to compliance
- [Read the Dev Guide](DEV-GUIDE-GENERAL-PUBLIC.md)

### Infrastructure

**LDM Dev Tools.app**
- Scheduled automation that runs whether anyone remembers or not. Backup, branch protection audit, visibility audit.
- macOS .app bundle with Full Disk Access. One app to grant permissions to, one place to add new automation. Scripts can be run standalone without the .app
- *Stable*
- [Read more about LDM Dev Tools.app](tools/ldm-jobs/README.md)

### Repo Management

**Repo Visibility Guard**
- Never accidentally expose a private repo.
- Blocks repos from going public without a `-private` counterpart. Catches accidental exposure of internal plans, todos, and development context before it happens
- **Interfaces:** CLI, Module, MCP, OpenClaw, Skill, CC Hook
- *Stable*
- [Read more about Repo Visibility Guard](tools/wip-repo-permissions-hook/README.md)

**Repo Manifest Reconciler**
- Know where every repo belongs. One source of truth for folder structure.
- Like prettier for folder structure. Move folders around all day; on sync, everything snaps back to where the manifest says
- **Interfaces:** CLI, Module, MCP, Skill
- *Stable*
- [Read more about Repo Manifest](tools/wip-repos/README.md)

**Repo Init**
- Scaffold the standard `ai/` directory in any repo. Plans, notes, ideas, dev updates, todos. One command.
- New repo: creates the full structure. Existing repo: moves old `ai/` contents to `ai/_sort/ai_old/` so you can sort at your own pace. Nothing is deleted.
- **Interfaces:** CLI, Skill
- *Stable*
- [Read more about Repo Init](tools/wip-repo-init/README.md)

**README Formatter**
- Generate or validate READMEs that follow the WIP Computer standard. Badges, title, tagline, "Teach Your AI" block, features, interface coverage table, license.
- Generates separate section files (README-init-badges.md, README-init-features.md, etc.) so you can edit any section independently. Deploy assembles them into the final README. Same pattern as release notes: staging, review, deploy.
- **Interfaces:** CLI, Skill
- *Stable*
- [Read more about README Formatter](tools/wip-readme-format/README.md)

**Forced Git Worktrees**
- Every repo uses git worktrees. Agents never edit on main. Period.
- When an agent needs to make changes, it creates a worktree (isolated copy of the repo on its own branch). All edits happen there. Main stays clean. Multiple agents can work on the same repo simultaneously without collisions. When the work is done, it goes through a PR to merge back.
- **Interfaces:** CLI, CC Hook
- *Stable*

**Branch Guard**
- Blocks all writes on main. The enforcement layer for forced worktrees.
- PreToolUse hook that catches Write, Edit, and destructive Bash commands. Resolves the repo from the file path, not the CWD, so it works when Claude Code opens in a different directory. Read-only operations and merge/pull are still allowed on main.
- **Interfaces:** CC Hook
- *Stable*
- [Read more about Branch Guard](tools/wip-branch-guard/INSTALL.md)

### License, Compliance, and Protection

**Identity File Protection**
- Know what it can never overwrite. CLAUDE.md, SOUL.md, MEMORY.md, SHARED-CONTEXT.md are permanently protected.
- Blocks destructive edits to protected identity files. Your AI can read them but can't blow them away
- **Interfaces:** CLI, Module, OpenClaw, Skill, CC Hook
- *Stable*
- [Read more about Identity File Protection](tools/wip-file-guard/README.md)

**License Guard**
- Enforce licensing on every commit. Copyright, dual-license, CLA. Checked automatically.
- Ensures your own repos have correct copyright, license type, and LICENSE files. Interactive first-run setup. Toolbox-aware: checks every sub-tool. Auto-fix mode repairs issues
- `readme-license` scans all your repos and applies a standard license block to every README in one command. Removes duplicate license sections from sub-tool READMEs
- **Interfaces:** CLI
- *Stable*
- [Read more about License Guard](tools/wip-license-guard/README.md)

**License Rug-Pull Detection**
- Catch license changes in dependencies before they ship.
- Scans every dependency for license changes. Blocks merges if a license changed upstream. Daily cron scan. Generates a public compliance dashboard
- **Interfaces:** CLI, Module, MCP, Skill
- *Stable*
- [Read more about License Detection](tools/wip-license-hook/README.md)

### Release & Deploy

**Release Pipeline**
- Release software correctly. Version bump, changelog, npm publish, GitHub release. One command, nothing forgotten.
- SKILL.md sync, release notes on the branch for PR review. Warns when notes are too short or look like changelogs instead of narrative
- **Interfaces:** CLI, Module, MCP, Skill
- *Stable*
- [Read more about Release Pipeline](tools/wip-release/README.md)

**Private-to-Public Sync**
- Publish safely. Syncs private to public, excludes internal files, every time.
- One script syncs your private working repo to a clean public mirror. Excludes internal `ai/` folders automatically. Creates a PR, merges it, cleans up branches
- **Interfaces:** CLI, Skill
- *Stable*
- [Read more about Private-to-Public Sync](tools/deploy-public/README.md)

**Post-Merge Branch Naming**
- Cleans up after itself. Merged branches get renamed with dates automatically.
- Renames merged branches with `--merged-YYYY-MM-DD`. Preserves history without cluttering your branch list
- **Interfaces:** CLI, Skill
- *Stable*
- [Read more about Post-Merge Naming](tools/post-merge-rename/README.md)

**Skill Publish to Website**
- After every release, your SKILL.md goes live as plain text on your website. No manual copying. No forgetting.
- Add `.publish-skill.json` to your repo with `name` and `websiteRepo`. On release, SKILL.md is copied to `yoursite.com/install/{name}.txt` and deployed automatically. Any AI can fetch the URL and get clean, parseable instructions. Like `robots.txt` but for agent install prompts.
- **Interfaces:** Module (built into Release Pipeline)
- *Stable*

**Make Discoverable in Claude Code**
- Turn any repo into a Claude Code plugin. Auto-generates `.claude-plugin/plugin.json` from your existing interfaces.
- Runs during release. Detects what your repo exposes (skills, hooks, MCP servers, agents) and builds the plugin manifest so it shows up in Claude Code's `/plugin` marketplace. No manual config.
- **Interfaces:** Module (built into Release Pipeline)
- *Planned*

## Interface Coverage

| # | Tool | CLI | Module | MCP | OC Plugin | Skill | CC Hook |
|---|------|-----|--------|-----|-----------|-------|---------|
| | **Setup & Onboarding** | | | | | | |
| 1 | Universal Installer | Y | Y | | | Y | |
| 2 | Dev Guide | | | | | | |
| | **Infrastructure** | | | | | | |
| 3 | LDM Dev Tools.app | | | | | | |
| | **Repo Management** | | | | | | |
| 4 | Repo Visibility Guard | Y | Y | Y | Y | Y | Y |
| 5 | Repo Manifest Reconciler | Y | Y | Y | | Y | |
| 6 | Repo Init | Y | | | | Y | |
| 7 | README Formatter | Y | | | | Y | |
| 8 | Forced Git Worktrees | Y | | | | | Y |
| 9 | Branch Guard | | | | | | Y |
| | **License, Compliance, and Protection** | | | | | | |
| 10 | Identity File Protection | Y | Y | | Y | Y | Y |
| 11 | License Guard | Y | | | | | |
| 12 | License Rug-Pull Detection | Y | Y | Y | | Y | |
| | **Release & Deploy** | | | | | | |
| 13 | Release Pipeline | Y | Y | Y | | Y | |
| 14 | Private-to-Public Sync | Y | | | | Y | |
| 15 | Post-Merge Branch Naming | Y | | | | Y | |
| 16 | Skill Publish to Website | | Y | | | | |
| 17 | Make Discoverable in Claude Code | | Y | | | | |

## More Info

- [Technical Documentation](TECHNICAL.md) ... source code, build steps, architecture
- [Universal Interface Spec](tools/wip-universal-installer/SPEC.md) ... the seven interfaces every agent-native tool can ship
- [Dev Guide](DEV-GUIDE-GENERAL-PUBLIC.md) ... best practices for AI-assisted development

## Part of LDM OS

AI DevOps Toolbox installs into [LDM OS](https://github.com/wipcomputer/wip-ldm-os), the local runtime for AI agents.
Run `ldm install` to see other components you can add.

## License

Dual-license model designed to keep tools free while preventing commercial resellers.

```
MIT      All CLI tools, MCP servers, skills, and hooks (use anywhere, no restrictions).
AGPLv3   Commercial redistribution, marketplace listings, or bundling into paid services.
```

AGPLv3 for personal use is free. Commercial licenses available.

### Can I use this?

**Yes, freely:**
- Use any tool locally or on your own servers
- Modify the code for your own projects
- Include in your internal CI/CD pipelines
- Fork it and send us feedback via PRs (we'd love that)

**Need a commercial license:**
- Bundle into a product you sell
- List on a marketplace (VS Code, JetBrains, etc.)
- Offer as part of a hosted/SaaS platform
- Redistribute commercially

Using these tools to build your own software is fine. Reselling the tools themselves is what requires a commercial license.

By submitting a PR, you agree to the [Contributor License Agreement](CLA.md).

Built by Parker Todd Brooks, Lēsa (OpenClaw, Claude Opus 4.6), Claude Code (Claude Opus 4.6).


path: TECHNICAL.md
content: ###### WIP Computer

# AI DevOps Toolbox

## Want your AI to dev? Here's the full system.

Your AI writes code. But does it know how to release it? Check license compliance? Sync private repos to public ones? Follow a real development process?

**AI DevOps Toolbox** is a collection of battle-tested tools for AI-assisted software development. Built by a team of humans and AIs shipping real software together.

Used internally to manage 100+ repos, 200+ releases, and daily license compliance across the [wipcomputer](https://github.com/wipcomputer) org. These tools run in production every day.

**Real-world example:** [wip-universal-installer](tools/wip-universal-installer/) ships its releases entirely through wip-release. 6 releases, v2.1.5, changelog and GitHub releases all generated automatically.

## Quick Start

```bash
# Install LDM OS (shared infrastructure for all your AI tools)
npm install -g @wipcomputer/wip-ldm-os
ldm init

# Preview what will be installed (12 tools, 39+ interfaces)
ldm install wipcomputer/wip-ai-devops-toolbox --dry-run

# Install everything
ldm install wipcomputer/wip-ai-devops-toolbox

# Verify
ldm doctor
```

## Tools

### Universal Installer (built into [LDM OS](https://github.com/wipcomputer/wip-ldm-os))

The Universal Interface specification for agent-native software. Defines how every tool ships six interfaces: CLI, importable module, MCP Server, OpenClaw Plugin, Skill, Claude Code Hook. The detection engine powers [`ldm install`](https://github.com/wipcomputer/wip-ldm-os).

```bash
# Detect what interfaces a repo supports
ldm install /path/to/repo --dry-run

# Install a tool from GitHub
ldm install wipcomputer/wip-file-guard

# Standalone fallback (bootstraps LDM OS if needed)
wip-install wipcomputer/wip-file-guard
```

**Source:** Pure JavaScript, no build step. [`tools/wip-universal-installer/detect.mjs`](tools/wip-universal-installer/detect.mjs) (detection), [`tools/wip-universal-installer/install.js`](tools/wip-universal-installer/install.js) (standalone installer). Zero dependencies. LDM OS deploy engine at [`lib/deploy.mjs`](https://github.com/wipcomputer/wip-ldm-os/blob/main/lib/deploy.mjs).

[README](tools/wip-universal-installer/README.md) ... [SKILL.md](tools/wip-universal-installer/SKILL.md) ... [Universal Interface Spec](tools/wip-universal-installer/SPEC.md) ... [Reference](tools/wip-universal-installer/REFERENCE.md)

### Dev Guide

Best practices for AI-assisted development teams. Covers release process, repo structure, the `ai/` folder convention, branch protection, private/public repo patterns, post-merge branch renaming, repo directory structure, Cloudflare Workers deploy guards, and more.

[Read the Dev Guide](DEV-GUIDE-GENERAL-PUBLIC.md)

### LDM Dev Tools.app

macOS automation wrapper. A native `.app` bundle that runs scheduled jobs (backup, branch protection audit, etc.) with Full Disk Access. One app to grant permissions to, one place to add new automation.

**Source:** Job scripts are plain shell. The app provides a Full Disk Access wrapper.

| Script | What it does | Source |
|--------|-------------|--------|
| `backup.sh` | Calls `~/.ldm/bin/ldm-backup.sh` (unified backup) | wip-ldm-os-private/scripts/ |
| [`branch-protect.sh`](tools/ldm-jobs/branch-protect.sh) | Audit and enforce branch protection across all org repos | tools/ldm-jobs/ |
| [`visibility-audit.sh`](tools/ldm-jobs/visibility-audit.sh) | Audit public repos for missing -private counterparts | tools/ldm-jobs/ |

The backup script is deployed by `ldm install` to `~/.ldm/bin/`. It backs up ~/.ldm/, ~/.openclaw/, ~/.claude/, and the workspace. See `how-backup-works.md` in the workspace docs.

```bash
# Run standalone
~/.ldm/bin/ldm-backup.sh                # or --dry-run to preview
bash tools/ldm-jobs/branch-protect.sh
bash tools/ldm-jobs/visibility-audit.sh

# Or via the app wrapper
open -W ~/Applications/LDMDevTools.app --args backup
open -W ~/Applications/LDMDevTools.app --args branch-protect
open -W ~/Applications/LDMDevTools.app --args visibility-audit
```

[README](tools/ldm-jobs/README.md)

**Setup:** Drag `LDMDevTools.app` into System Settings > Privacy & Security > Full Disk Access. Then schedule via cron:

```bash
# Daily backup at midnight, branch protection audit at 1 AM, visibility audit at 2 AM
0 0 * * * open -W ~/Applications/LDMDevTools.app --args backup >> ~/.ldm/logs/cron.log 2>&1
0 1 * * * open -W ~/Applications/LDMDevTools.app --args branch-protect >> ~/.ldm/logs/cron.log 2>&1
0 2 * * * open -W ~/Applications/LDMDevTools.app --args visibility-audit >> ~/.ldm/logs/cron.log 2>&1
```

Logs: `~/.ldm/logs/`

### wip-release

One-command release pipeline. Version bump, changelog, SKILL.md sync, npm publish, GitHub release, website skill publish. All in one shot.

```bash
wip-release patch                               # auto-detects RELEASE-NOTES-v{version}.md
wip-release minor --dry-run
wip-release major
```

**Release notes are mandatory.** Write `RELEASE-NOTES-v{version}.md` (dashes, not dots) on your feature branch. Commit it with the code. The PR diff shows both code and notes for review. On release, wip-release auto-detects the file.

**Quality gates (all run before release):**
- **Release notes:** Must come from a file (--notes flag removed). Three sources: RELEASE-NOTES file, ai/dev-updates/, or --notes-file. Blocks changelog-format entries ("fix: ...", "add: ..."). Must reference at least one GitHub issue (#XX).
- **Product docs:** Warns if roadmap, readme-first, or dev-updates are stale. Auto-updates version/date in `ai/product/plans-prds/roadmap.md` and `ai/product/readme-first-product.md` before commit.
- **Technical docs:** When source files (.mjs, .js, .ts) changed since last tag, checks that SKILL.md or TECHNICAL.md was also updated. Warns on patch, blocks on minor/major. Skip: `--skip-tech-docs-check`.
- **Interface coverage (toolbox repos):** Scans `tools/*/` for actual interfaces (CLI, Module, MCP, OC Plugin, Skill, CC Hook). Compares against README.md and SKILL.md coverage table. Reports: missing from table, detected but not marked, marked but not detected. Warns on patch, blocks on minor/major. Skip: `--skip-coverage-check`.
- **Stale branches:** Warns (patch) or blocks (minor/major) if merged branches exist on remote.
- **Worktree guard:** Blocks releases from linked worktrees. Must run from main working tree. Skip: `--skip-worktree-check`.
- **Dogfood cooldown:** Writes `.last-release` marker. Branch guard blocks `npm install -g` for 5 minutes.

**Post-release automation:**
- Post-merge branch rename (--merged-YYYY-MM-DD)
- Stale worktree prune from `_worktrees/`
- Skill publish to wip.computer/install/{name}.txt
- Product docs version sync

**All 7 CLIs support `--version` and `-v`.**

**Source:** Pure JavaScript, no build step. [`tools/wip-release/cli.js`](tools/wip-release/cli.js) (entry point), [`tools/wip-release/core.mjs`](tools/wip-release/core.mjs) (main logic), [`tools/wip-release/mcp-server.mjs`](tools/wip-release/mcp-server.mjs) (MCP server). Zero dependencies.

[README](tools/wip-release/README.md) ... [SKILL.md](tools/wip-release/SKILL.md) ... [Reference](tools/wip-release/REFERENCE.md)

### wip-license-hook

License rug-pull detection. Scans every dependency and fork for license changes. Pre-pull hook blocks merges if a license changed upstream. Pre-push hook alerts. Daily cron scan. Generates a public compliance dashboard.

```bash
wip-license-hook scan
wip-license-hook audit
```

**Source:** TypeScript. All source in [`tools/wip-license-hook/src/`](tools/wip-license-hook/src/):

| File | What it does |
|------|-------------|
| `src/cli/index.ts` | CLI entry point |
| `src/core/scanner.ts` | Dependency scanning (npm, pip, cargo, go, forks) |
| `src/core/detector.ts` | License text fingerprinting |
| `src/core/ledger.ts` | Ledger persistence and snapshots |
| `src/core/reporter.ts` | Reporting and dashboard HTML generation |

[README](tools/wip-license-hook/README.md) ... [SKILL.md](tools/wip-license-hook/SKILL.md)

### wip-repo-permissions-hook

Repo visibility guard. Blocks repos from going public without a `-private` counterpart. Works as a CLI, Claude Code hook, and OpenClaw plugin. Catches accidental exposure of internal plans, todos, and development context.

```bash
# Check a single repo
wip-repo-permissions check wipcomputer/memory-crystal
# -> OK: memory-crystal-private exists

# Audit all public repos in org
wip-repo-permissions audit wipcomputer
# -> Lists violations, exit code 1 if any found
```

**Source:** Pure JavaScript, no build step. [`tools/wip-repo-permissions-hook/core.mjs`](tools/wip-repo-permissions-hook/core.mjs) (logic), [`tools/wip-repo-permissions-hook/cli.js`](tools/wip-repo-permissions-hook/cli.js) (CLI), [`tools/wip-repo-permissions-hook/guard.mjs`](tools/wip-repo-permissions-hook/guard.mjs) (Claude Code hook). Zero dependencies.

[README](tools/wip-repo-permissions-hook/README.md) ... [SKILL.md](tools/wip-repo-permissions-hook/SKILL.md)

### post-merge-rename.sh

Post-merge branch renaming. Scans for merged branches that haven't been renamed, appends `--merged-YYYY-MM-DD` to preserve history. Runs automatically as part of `wip-release`, or standalone.

**Source:** Plain shell. [`scripts/post-merge-rename.sh`](scripts/post-merge-rename.sh)

```bash
bash scripts/post-merge-rename.sh              # scan + rename all
bash scripts/post-merge-rename.sh --dry-run     # preview only
bash scripts/post-merge-rename.sh <branch>      # rename specific branch
```

### wip-file-guard

Hook that blocks destructive edits to protected identity files. Works with Claude Code CLI and OpenClaw. Protects CLAUDE.md, SHARED-CONTEXT.md, SOUL.md, IDENTITY.md, MEMORY.md, and pattern-matched memory/journal files.

Two rules: block `Write` on protected files entirely, block `Edit` when removing more than 2 lines or replacing more than 4 lines.

```bash
# List protected files
wip-file-guard --list
```

**Source:** Pure JavaScript, no build step. [`tools/wip-file-guard/guard.mjs`](tools/wip-file-guard/guard.mjs) (single file, all logic). Zero dependencies.

[README](tools/wip-file-guard/README.md) ... [SKILL.md](tools/wip-file-guard/SKILL.md) ... [Reference](tools/wip-file-guard/REFERENCE.md)

### deploy-public.sh

Private-to-public repo sync. The full pipeline:

1. Rsyncs all files except `ai/` from private to public repo clone
2. Rewrites repository URL from private to public in package.json
3. Creates a branch, commits with co-authors, pushes, creates PR
4. Merges PR (--merge, never squash)
5. Creates matching GitHub release on public repo (pulls notes from private repo's release)
6. Publishes to npm from public repo clone
7. Publishes to GitHub Packages from public repo clone (uses `gh auth token`)
8. Cleans stale branches on public repo

```bash
bash scripts/deploy-public.sh /path/to/private-repo wipcomputer/public-repo
bash scripts/deploy-public.sh /path/to/private-repo wipcomputer/public-repo --dry-run
```

**Source:** Plain shell. [`scripts/deploy-public.sh`](scripts/deploy-public.sh) and [`tools/deploy-public/deploy-public.sh`](tools/deploy-public/deploy-public.sh)

### wip-repos

Repo manifest reconciler. Makes `repos-manifest.json` the single source of truth for repo organization. Like prettier for folder structure. Move folders around all day; on sync, everything snaps back to where the manifest says. Also generates cross-repo CLAUDE.md ecosystem sections.

```bash
# Check for drift
wip-repos check

# Sync filesystem to match manifest
wip-repos sync --dry-run

# Add a repo
wip-repos add ldm-os/utilities/my-tool --remote wipcomputer/my-tool

# Move a repo in the manifest
wip-repos move ldm-os/utilities/my-tool --to ldm-os/devops/my-tool

# Generate directory tree
wip-repos tree

# Generate cross-repo CLAUDE.md ecosystem sections
wip-repos claude                         # all repos
wip-repos claude my-repo                 # one repo
wip-repos claude --init                  # create CLAUDE.md for repos missing one
wip-repos claude --dry-run               # preview
```

**How `wip-repos claude` works:**

Agents can't read sibling repos at runtime. This command solves that by pre-generating cross-repo context into each repo's CLAUDE.md.

1. Reads all repos from `repos-manifest.json`
2. Extracts metadata from each: `package.json` (name, version, bin, exports), `SKILL.md` (interfaces), directory structure
3. For each repo, determines relevant siblings (same category + core repos)
4. Generates an `## Ecosystem` section between `<!-- wip-repos:start -->` / `<!-- wip-repos:end -->` delimiter comments
5. Hand-written CLAUDE.md content outside the delimiters is never touched

Templates at `templates/global-claude-md.md` (for `~/.claude/CLAUDE.md`) and `templates/repo-claude-md.template` (for per-repo starter).

**Source:** Pure JavaScript, no build step. [`tools/wip-repos/core.mjs`](tools/wip-repos/core.mjs) (manifest logic), [`tools/wip-repos/claude.mjs`](tools/wip-repos/claude.mjs) (ecosystem generator), [`tools/wip-repos/cli.mjs`](tools/wip-repos/cli.mjs) (CLI). Zero dependencies.

[README](tools/wip-repos/README.md)

### wip-repo-init

Scaffold the standard `ai/` directory in any repo. Plans, notes, ideas, dev updates, todos. One command.

New repo: creates the full structure. Existing repo: moves old `ai/` contents to `ai/_sort/ai_old/` so you can sort at your own pace. Nothing is deleted.

```bash
wip-repo-init /path/to/repo              # scaffold ai/ in a repo
wip-repo-init /path/to/repo --dry-run    # preview without changes
```

**Source:** Pure JavaScript, no build step. [`tools/wip-repo-init/init.mjs`](tools/wip-repo-init/init.mjs). Zero dependencies.

[README](tools/wip-repo-init/README.md) ... [SKILL.md](tools/wip-repo-init/SKILL.md)

### wip-readme-format

Generate or validate READMEs that follow the WIP Computer standard. Badges, title, tagline, "Teach Your AI" block, features, interface coverage table, license.

```bash
wip-readme-format /path/to/repo              # generate section files
wip-readme-format /path/to/repo --deploy     # assemble into final README
wip-readme-format /path/to/repo --dry-run    # preview without writing
```

**Source:** Pure JavaScript, no build step. [`tools/wip-readme-format/format.mjs`](tools/wip-readme-format/format.mjs). Zero dependencies. Reads templates from `ai/wip-templates/readme/`.

[README](tools/wip-readme-format/README.md) ... [SKILL.md](tools/wip-readme-format/SKILL.md)

### wip-license-guard

License enforcement for your own repos. Checks copyright, dual-license (MIT+AGPL), CLA, README license section. Toolbox-aware: checks every sub-tool. Interactive first-run setup. Auto-fix mode repairs issues.

```bash
wip-license-guard check                  # audit current repo
wip-license-guard check --fix            # audit and auto-fix
wip-license-guard init --from-standard   # apply WIP Computer defaults
wip-license-guard readme-license         # audit/fix license blocks across all repos
```

**Claude Code Hook:** Also wired as a PreToolUse hook (`guard.mjs`). On `ldm install`, registers in `~/.claude/settings.json`. Blocks `git commit` and `git push` when license compliance fails. Only checks repos with `.license-guard.json`. Repos without config silently pass.

**Source:** Pure JavaScript, no build step. [`tools/wip-license-guard/cli.mjs`](tools/wip-license-guard/cli.mjs) (CLI), [`tools/wip-license-guard/core.mjs`](tools/wip-license-guard/core.mjs) (logic), [`tools/wip-license-guard/guard.mjs`](tools/wip-license-guard/guard.mjs) (CC hook). Zero dependencies.

[README](tools/wip-license-guard/README.md) ... [SKILL.md](tools/wip-license-guard/SKILL.md)

### wip-branch-guard

Blocks all writes on main branch. The enforcement layer for required worktrees. PreToolUse hook that catches Write, Edit, and destructive Bash commands. Resolves the repo from the file path, not the CWD. If a file is outside any git repo (e.g. `~/.claude/plans/`), the guard allows edits immediately. Only protects files within git repos.

**Features:**
- **Workflow teaching:** Error messages include the full 8-step dev process (worktree, branch, commit, push, PR, merge, wip-release, deploy-public). Agents learn the workflow from the error, not just that they're blocked.
- **Worktree path warning:** Warns when `git worktree add` creates outside `_worktrees/`. Suggests `ldm worktree add`.
- **Dogfood cooldown:** After `wip-release`, blocks `npm install -g` for 5 minutes. Forces dogfooding via the install prompt.
- **Worktree requirement on branches:** On any non-main branch, edits blocked if not inside a worktree. Separate error message directs agents to create a worktree properly.
- **Dangerous flag blocking:** `--no-verify` and `git push --force` blocked on any branch.
- **Shared state allowlist:** CLAUDE.md, SHARED-CONTEXT.md, daily logs, `~/.ldm/logs/` always writable on main.
- **Non-repo passthrough:** Files outside any git repo allowed immediately.

```bash
wip-branch-guard --check       # report current branch status
```

**Source:** Pure JavaScript, no build step. [`tools/wip-branch-guard/guard.mjs`](tools/wip-branch-guard/guard.mjs). Zero dependencies.

## Source Code

All implementation source is committed in this repo. No closed binaries, no mystery boxes.

| Tool | Language | Source location | Build step? |
|------|----------|----------------|-------------|
| Dev Guide | Markdown | `DEV-GUIDE-GENERAL-PUBLIC.md` | None. |
| LDM Dev Tools jobs | Shell | `tools/ldm-jobs/backup.sh`, `branch-protect.sh`, `visibility-audit.sh` | None. Runnable standalone or via `.app` wrapper. |
| wip-release | JavaScript (ESM) | `tools/wip-release/cli.js`, `core.mjs`, `mcp-server.mjs` | None. What you see is what runs. |
| wip-license-hook | TypeScript | `tools/wip-license-hook/src/**/*.ts`, `mcp-server.mjs` | `cd tools/wip-license-hook && npm install && npm run build` |
| wip-license-guard | JavaScript (ESM) | `tools/wip-license-guard/cli.mjs`, `core.mjs`, `guard.mjs` | None. What you see is what runs. |
| wip-repo-permissions-hook | JavaScript (ESM) | `tools/wip-repo-permissions-hook/core.mjs`, `cli.js`, `guard.mjs`, `mcp-server.mjs` | None. What you see is what runs. |
| post-merge-rename.sh | Shell | `scripts/post-merge-rename.sh` | None. |
| wip-file-guard | JavaScript (ESM) | `tools/wip-file-guard/guard.mjs` | None. What you see is what runs. |
| wip-branch-guard | JavaScript (ESM) | `tools/wip-branch-guard/guard.mjs` | None. What you see is what runs. |
| wip-universal-installer | JavaScript (ESM) | `tools/wip-universal-installer/detect.mjs`, `install.js` | None. What you see is what runs. |
| deploy-public.sh | Shell | `scripts/deploy-public.sh` | None. |
| wip-repos | JavaScript (ESM) | `tools/wip-repos/core.mjs`, `cli.mjs`, `mcp-server.mjs`, `claude.mjs` | None. What you see is what runs. |
| wip-repo-init | JavaScript (ESM) | `tools/wip-repo-init/init.mjs` | None. What you see is what runs. |
| wip-readme-format | JavaScript (ESM) | `tools/wip-readme-format/format.mjs` | None. What you see is what runs. |

Previously standalone tools (wip-release, wip-license-hook, wip-file-guard, wip-universal-installer) were merged here. The standalone repos redirect to this one.

### Private/Public Repo Pattern

Development happens in private repos (with `ai/` folders for internal notes, plans, dev updates). When publishing, `deploy-public.sh` syncs everything except `ai/` to the public repo. Source files are always committed. Compiled output (`dist/`) is gitignored and only published to npm.

## Development

### wip-license-hook (TypeScript)

```bash
cd tools/wip-license-hook
npm install
npm run build          # compiles src/ -> dist/
node dist/cli/index.js scan   # test locally
```

### wip-release (JavaScript)

No build step needed. Edit `cli.js` or `core.mjs` and test directly:

```bash
cd tools/wip-release
node cli.js --dry-run patch --notes="test"
```

## Install

Tell your AI:

```
Read wip.computer/install/wip-ai-devops-toolbox.txt

Then explain what these tools do and help me set them up.
```

Or install via LDM OS:

```bash
npm install -g @wipcomputer/wip-ldm-os
ldm init
ldm install wipcomputer/wip-ai-devops-toolbox --dry-run
ldm install wipcomputer/wip-ai-devops-toolbox
ldm doctor
```

Or install the root package directly:

```bash
npm install -g @wipcomputer/wip-ai-devops-toolbox
```

Or install individual tools:

```bash
npm install -g @wipcomputer/wip-release
npm install -g @wipcomputer/wip-license-hook
npm install -g @wipcomputer/wip-file-guard
npm install -g @wipcomputer/wip-repos
```

## License

Dual-license model designed to keep tools free while preventing commercial resellers.

```
MIT      All CLI tools, MCP servers, skills, and hooks (use anywhere, no restrictions).
AGPLv3   Commercial redistribution, marketplace listings, or bundling into paid services.
```

Built by Parker Todd Brooks, Lēsa (OpenClaw, Claude Opus 4.6), Claude Code (Claude Opus 4.6).


path: UNIVERSAL-INTERFACE.md
content: # The Universal Interface Specification

Every tool is a sensor, an actuator, or both. Every tool should be accessible through multiple interfaces. We call this the Universal Interface.

This is the spec.

## The Six Interfaces

### 1. CLI

A shell command. The most universal interface. If it has a terminal, it works.

**Convention:** `package.json` with a `bin` field.

**Detection:** `pkg.bin` exists.

**Install:** `npm install -g .` or `npm link`.

```json
{
  "bin": {
    "wip-grok": "./cli.mjs"
  }
}
```

### 2. Module

An importable ES module. The programmatic interface. Other tools compose with it.

**Convention:** `package.json` with `main` or `exports` field. File is `core.mjs` by convention.

**Detection:** `pkg.main` or `pkg.exports` exists.

**Install:** `npm install <package>` or import directly from path.

```json
{
  "type": "module",
  "main": "core.mjs",
  "exports": {
    ".": "./core.mjs",
    "./cli": "./cli.mjs"
  }
}
```

### 3. MCP Server

A JSON-RPC server implementing the Model Context Protocol. Any MCP-compatible agent can use it.

**Convention:** `mcp-server.mjs` (or `.js`, `.ts`) at the repo root. Uses `@modelcontextprotocol/sdk`.

**Detection:** One of `mcp-server.mjs`, `mcp-server.js`, `mcp-server.ts`, `dist/mcp-server.js` exists.

**Install:** Add to `.mcp.json`:

```json
{
  "tool-name": {
    "command": "node",
    "args": ["/path/to/mcp-server.mjs"]
  }
}
```

### 4. OpenClaw Plugin

A plugin for OpenClaw agents. Lifecycle hooks, tool registration, settings.

**Convention:** `openclaw.plugin.json` at the repo root.

**Detection:** `openclaw.plugin.json` exists.

**Install:** Copy to `~/.openclaw/extensions/<name>/`, run `npm install --omit=dev`.

### 5. Skill (SKILL.md)

A markdown file that teaches agents when and how to use the tool. The instruction interface.

**Convention:** `SKILL.md` at the repo root. YAML frontmatter with name, version, description, metadata.

**Detection:** `SKILL.md` exists.

**Install:** Referenced by path. Agents read it when they need the tool.

```yaml
---
name: wip-grok
version: 1.0.0
description: xAI Grok API. Search the web, search X, generate images.
metadata:
  category: search,media
  capabilities:
    - web-search
    - image-generation
---
```

### 6. Claude Code Hook

A hook that runs during Claude Code's tool lifecycle (PreToolUse, Stop, etc.).

**Convention:** `guard.mjs` at repo root, or `claudeCode.hook` in `package.json`.

**Detection:** `guard.mjs` exists, or `pkg.claudeCode.hook` is defined.

**Install:** Added to `~/.claude/settings.json` under `hooks`.

```json
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{
        "type": "command",
        "command": "node /path/to/guard.mjs",
        "timeout": 5
      }]
    }]
  }
}
```

## Architecture

Every repo that follows this spec has the same basic structure:

```
your-tool/
  core.mjs            pure logic, zero or minimal deps
  cli.mjs             thin CLI wrapper around core
  mcp-server.mjs      MCP server wrapping core functions as tools
  SKILL.md            agent instructions with YAML frontmatter
  package.json         name, bin, main, exports, type: module
  README.md            human documentation
  ai/                  development process (plans, todos, notes)
```

Not every tool needs all six interfaces. Build the ones that make sense.

The minimum viable agent-native tool has two interfaces: **Module** (importable) and **Skill** (agent instructions). Add CLI for humans. Add MCP for agents that speak MCP. Add OpenClaw/CC Hook for specific platforms.

## The `ai/` Folder

Every repo should have an `ai/` folder. This is where agents and humans collaborate on the project ... plans, todos, dev updates, research notes, conversations.

```
ai/
  plan/              architecture plans, roadmaps
  dev-updates/       what was built, session logs
  todos/
    PUNCHLIST.md     blockers to ship
    inboxes/         per-agent action items
  notes/             research, references, raw conversation logs
```

The `ai/` folder is the development process. It is not part of the published product.

**Public/private split:** If a repo is public, the `ai/` folder should not ship. The recommended pattern is to maintain a private working repo (with `ai/`) and a public repo (everything except `ai/`). The public repo has everything an LLM or human needs to understand and use the tool. The `ai/` folder is operational context for the team building it.

## The Reference Installer

`wip-install` is the reference implementation. It scans a repo, detects which interfaces exist, and installs them all. One command.

```bash
wip-install /path/to/repo          # local
wip-install org/repo               # from GitHub
wip-install --dry-run /path/to/repo # detect only
wip-install --json /path/to/repo    # JSON output
```

## Examples

| Repo | Interfaces | Type |
|------|------------|------|
| [wip-grok](https://github.com/wipcomputer/wip-grok) | CLI + Module + MCP + Skill | Sensor + Actuator |
| [wip-x](https://github.com/wipcomputer/wip-x) | CLI + Module + MCP + Skill | Sensor + Actuator |
| [wip-file-guard](https://github.com/wipcomputer/wip-file-guard) | CLI + OpenClaw + CC Hook | Actuator |
| [wip-markdown-viewer](https://github.com/wipcomputer/wip-markdown-viewer) | CLI + Module | Actuator |


path: _trash/RELEASE-NOTES-v1-8-0.md
content: # v1.8.0: Fix CC Hook duplicates, add GitHub Issues convention

## CC Hook duplicate detection fix

`wip-install` was adding duplicate PreToolUse hooks to `~/.claude/settings.json` every time it ran. After a few installs, there were 8 hooks when there should have been 2. The duplicates pointed to repo clones and `/tmp/` paths, violating the "never run tools from repo clones" rule.

The root cause: duplicate detection compared exact command strings. The same `guard.mjs` installed from different paths produced different strings, so each install added another entry.

The fix:
- Match existing hooks by tool name in the path, not exact command string
- Always prefer `~/.ldm/extensions/<tool>/guard.mjs` over source or temp paths
- If a hook for the same tool exists at a different path, update it instead of adding a duplicate

## GitHub Issues convention added to Dev Guide

We were tracking work in `ai/todos/` markdown files. Items got lost. GitHub Issues gives us tracking, cross-referencing, and visibility across agents.

Added to the public Dev Guide:
- When to use GitHub Issues vs `ai/todos/`
- Filing convention: `filed-by:<agent-id>` labels and attribution lines
- Public vs private issue routing: public issues are the front door, private issues are the workshop
- Agent ID naming convention: `[platform]-[agent]-[machine]`

Added to the private Dev Guide:
- `filed-by:cc-mini` (blue) and `filed-by:oc-lesa-mini` (purple) label details
- Org-wide deployment commands
- Incident note: Memory Crystal agent ID drift

Both labels deployed across all wipcomputer repos.


path: _trash/RELEASE-NOTES-v1-8-1.md
content: # v1.8.1: Fix CLI install when package name changed

When a tool's npm package gets renamed but the binary name stays the same, `npm install -g` fails with EEXIST. The stale symlink from the old package blocks the new one.

The installer now detects this: if the binary is a symlink pointing to a different package, it removes the stale link and retries. Only affects symlinks, only when the target doesn't match the package being installed.

Found on `wip-license-hook` (renamed from `@wipcomputer/license-hook` to `@wipcomputer/wip-license-hook`).


path: _trash/RELEASE-NOTES-v1-8-2.md
content: # v1.8.2: Clean up release notes after release

RELEASE-NOTES files were piling up in the repo root. `wip-release` consumed them for the GitHub release and CHANGELOG but never cleaned up.

Now after consuming the file, `wip-release` moves all `RELEASE-NOTES-v*.md` files to `_trash/` as part of the version bump commit. We never delete anything.

`deploy-public.sh` also now excludes `_trash/` so these files stay private.


path: _trash/RELEASE-NOTES-v1-9-0.md
content: # v1.9.0: README Formatter, Repo Init, Dev Guide overhaul

Two new tools, eight SKILL.md fixes, and a major Dev Guide update.

## New: wip-readme-format

Auto-generates READMEs following the WIP Computer standard. Detects all six interfaces, reads SKILL.md for tool names, generates badges, "Teach Your AI" block, features, interface coverage table, license block. Works on single repos and toolbox repos.

The key design: generates separate section files instead of one monolithic README.

```
wip-readme-format /path/to/repo          # generates README-init-*.md section files
wip-readme-format /path/to/repo --deploy  # assembles sections into README.md
```

Section files: `README-init-badges.md`, `README-init-title.md`, `README-init-teach.md`, `README-init-features.md`, `README-init-coverage.md`, `README-init-more-info.md`, `README-init-license.md`, `README-init-technical.md`. Edit any section independently, then deploy assembles them in order. Same pattern as release notes: staging, review, deploy.

Also supports `--dry-run` (preview) and `--check` (validate existing README against the standard).

## New: wip-repo-init

Scaffolds the standard `ai/` directory in any repo. Plans, notes, ideas, dev updates, todos. Every folder has self-documenting READMEs.

New repo: creates the full structure. Existing repo: moves old `ai/` contents to `ai/_sort/ai_old/` so you can sort at your own pace. Nothing is deleted.

## Dev Guide: release notes workflow

Both Dev Guides (public and private) now explicitly document the `RELEASE-NOTES-v{version}.md` workflow. Write the release notes file on the branch, commit it with the code, review it in the PR, `wip-release` auto-detects it after merge. Both guides cross-reference each other at the top so agents know to read both.

## Fixes

- Fixed SKILL.md `name:` frontmatter in all 8 existing tools. Interface coverage table now shows human-readable names ("Release Pipeline", "Identity File Protection") instead of directory names ("wip-release", "wip-file-guard").
- Fixed interface coverage table: renamed "OpenClaw" column to "OC Plugin", corrected License Guard row (was falsely claiming Module + CC Hook).
- Skill deployment: `wip-install` now deploys SKILL.md files to `~/.openclaw/skills/<tool>/` so OpenClaw agents can use them.
- Amalgamated interface system notes, README standard, and Universal Installer vision into one reference document.
- Dogfooded wip-repo-init on the toolbox itself. Filled in product bible, roadmap, and readme-first with real content.
- Created plan stubs for all roadmap items (README Formatter, Daily Dev Summary, GitHub Actions Pack, Security Suite).


path: _trash/RELEASE-NOTES-v1-9-1.md
content: # v1.9.1: Release gates ... product docs and release notes quality enforcement

Agents read the Dev Guide, say "got it," and then release with garbage one-liner notes anyway. Documentation doesn't change behavior. Tools do. This release adds two new gates to `wip-release` that block bad releases before they happen.

## Product docs gate

Every PR is supposed to include updated product docs: a dev update, roadmap changes, and readme-first updates. This was documented in the Dev Guide as a manual checklist. Nobody followed it.

`wip-release` now checks three things before publishing:

1. **Dev update exists.** Looks in `ai/dev-updates/` for a file from the last 3 days. If you did work worth releasing, you should have written about it.
2. **Roadmap was updated.** Checks `ai/product/plans-prds/roadmap.md` via `git diff` against the last tag. If the roadmap doesn't reflect what just shipped, it's stale.
3. **Readme-first was updated.** Same check on `ai/product/readme-first-product.md`. The product bible should always describe what's actually built.

Repos without an `ai/` directory are skipped silently. This only applies to repos that have adopted the `ai/` folder standard.

For **patch** releases: warns but doesn't block. Hotfixes shouldn't be held up by docs.
For **minor/major** releases: blocks the release. You can't ship a meaningful feature with stale product docs.

`--skip-product-check` overrides for exceptional cases.

## Release notes quality gate

On 2026-03-11, the other CC session released memory-crystal v0.7.4. It read the Dev Guide (which now explicitly says "write a RELEASE-NOTES file on the branch"). It said it understood. Then it ran `wip-release patch --notes="MCP fix and agent ID config"` and published a one-liner to GitHub. The old `warnIfNotesAreThin()` function printed a warning to console. The agent ignored it.

The root cause was architectural, not behavioral. The warning ran at step 8 of the pipeline, AFTER the version was already bumped, committed, tagged, and pushed. By the time the warning appeared, the damage was done. And it was a warning, not a gate. Agents don't read warnings.

The fix:
- `checkReleaseNotes()` replaces `warnIfNotesAreThin()`. It runs before the version bump, not after.
- The CLI now tracks `notesSource`: where the notes came from (`file`, `dev-update`, `flag`, or `none`).
- For minor/major releases: if notes came from a bare `--notes` flag instead of a `RELEASE-NOTES-v{version}.md` file, the release is **blocked**. The agent gets explicit instructions: "Write RELEASE-NOTES-v{version}.md (dashes not dots), commit it, then release."
- For patch releases: warns if notes are short, but doesn't block.

## Both gates follow the same pattern

The existing license compliance gate (step 0) checks `.license-guard.json` and blocks if licensing is wrong. The new product docs gate (step 0.5) and release notes gate (step 0.75) work the same way: check early, block before any changes, show status in `--dry-run`, give clear instructions on how to fix it.

The MCP server was also updated with `skipProductCheck` and `notesSource` passthrough so agents calling wip-release via MCP get the same enforcement.


path: _trash/RELEASE-NOTES-v1-9-10.md
content: # Release Notes: AI DevOps Toolbox v1.9.10

**Fix: Release notes files on disk always beat --notes flag**

v1.9.9 shipped with a one-liner on the GitHub release instead of the full narrative release notes. The RELEASE-NOTES-v1-9-9.md file was sitting right there on disk, but `--notes="short text"` took priority because the auto-detect only ran when `--notes` was absent.

This is exactly the kind of bug that happens when a rule exists in documentation but not in code. "Write release notes on the branch" is in the Dev Guide. The tool ignored them.

## What changed

### Notes priority is now enforced (highest wins):

1. `--notes-file=path` ... explicit file path (always wins)
2. `RELEASE-NOTES-v{ver}.md` ... in repo root (always wins over `--notes` flag)
3. `ai/dev-updates/YYYY-MM-DD*` ... today's dev update (wins over `--notes` flag if longer)
4. `--notes="text"` ... fallback only. Use for repos without release notes files.

If a RELEASE-NOTES file exists on disk, `--notes` is ignored and a warning is printed:

```
! --notes flag ignored: RELEASE-NOTES-v1-9-10.md takes priority
```

Written notes on disk always take priority over a CLI one-liner. The agent wrote the file. The tool should use it.

## Files changed

```
 tools/wip-release/cli.js | ~40 lines rewritten (notes cascade logic)
```

## Install

```bash
git pull origin main
```

## Attribution

Built by Parker Todd Brooks, Lesa, and Claude Opus 4.6 at WIP.computer.


path: _trash/RELEASE-NOTES-v1-9-2.md
content: # v1.9.2: Distribution Pipeline Fix

The entire distribution pipeline was broken. Tools built but never reached users. 8 of 13 tools weren't on npm. ClawHub publish only shipped the root SKILL.md. deploy-public never ran npm publish. Errors were silent.

This release fixes all of it.

## What changed

### Install fixes (#96, #110)
- CLI binaries now have correct executable permissions (git +x on all bin entry files)
- wip-license-hook dist/ committed to repo (TypeScript build output was gitignored)
- Installer auto-detects TypeScript projects and runs build if dist/ missing
- chmod +x safety net after every npm install -g
- SSH fallback when HTTPS clone fails (private repos)

### SKILL.md spec compliance (#107, #108)
- All 12 SKILL.md files conform to agentskills.io spec
- name field: lowercase-hyphen format matching directory name
- Display names in metadata.display-name
- version, homepage, author in metadata block
- license: MIT on all files
- metadata.openclaw blocks with install instructions and emoji
- New SKILL.md created for wip-license-guard (was missing)

### Distribution pipeline (#97, #100, #104)
- ClawHub publish now iterates all sub-tool SKILL.md files, not just root
- detectSkillSlug reads the name field from SKILL.md frontmatter
- deploy-public.sh runs npm publish from the public clone after code sync
- Handles both single repos and toolbox repos (iterates tools/*)
- Distribution summary at end of release: shows all targets with pass/fail
- syncSkillVersion handles quoted version strings in new metadata format

## Install

```bash
npm install -g @wipcomputer/wip-ai-devops-toolbox
wip-install wipcomputer/wip-ai-devops-toolbox
```

Built by Parker Todd Brooks, Lesa (OpenClaw, Claude Opus 4.6), Claude Code (Claude Opus 4.6).


path: _trash/RELEASE-NOTES-v1-9-31.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.31

Branch guard no longer blocks global npm operations on main.

## What changed

Moved `npm install -g` and `npm link` from BLOCKED_BASH_PATTERNS to ALLOWED_BASH_PATTERNS in `wip-branch-guard/guard.mjs`. Global npm operations modify `/opt/homebrew/`, not the repo. Local `npm install` (no -g flag) remains blocked.

## Why

During LDM OS v0.4.0 dogfood, a CC session couldn't run `npm install -g @wipcomputer/wip-ldm-os@0.4.0` even after Parker explicitly said "install." The guard was too aggressive. Original intent (issue #137) was to block repo writes on main, not system-level package installs.

## Issues closed

- Closes #188 (branch guard blocks npm install -g)
- Cross-ref: wipcomputer/wip-ldm-os#44

## How to verify

```bash
# On main branch, these should now succeed:
npm install -g @wipcomputer/wip-ldm-os@0.4.0
npm link
# This should still be blocked on main:
npm install
```


path: _trash/RELEASE-NOTES-v1-9-32.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.32

Remove wip-install binary from toolbox. It lives in LDM OS now.

## What changed

The `wip-install` CLI binary has been removed from `@wipcomputer/universal-installer`. It now ships with `@wipcomputer/wip-ldm-os` (v0.4.1+). This prevents the EEXIST collision that blocked `npm install -g @wipcomputer/wip-ldm-os` when both packages tried to own the same binary.

## Issues closed

- Closes wipcomputer/wip-ldm-os#46

## How to verify

```bash
npm install -g @wipcomputer/wip-ldm-os@0.4.1  # no EEXIST error
which wip-install  # points to LDM OS, not toolbox
```


path: _trash/RELEASE-NOTES-v1-9-41.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.41

**One-line summary of what this release does**

## What changed

Describe the changes. Not a commit list. Explain:
- What was built or fixed
- Why it matters
- What the user should know

## Why

What problem does this solve? What was broken or missing?

## Issues closed

- #251
- #117
- #128
- #250
- #73

## How to verify

```bash
# Commands to test the changes
```


path: _trash/RELEASE-NOTES-v1-9-45.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.45

**Guard now teaches the workflow instead of just blocking.**

## What changed

- **Branch guard error messages overhauled (#213).** When the guard blocks a write on main, it now shows the full 8-step process: worktree, branch, commit, push, PR, merge, wip-release, deploy-public. Includes the lesson that release notes go on the feature branch, not as a separate PR.
- **Separate error for "on branch but not in worktree."** Tells the agent to go back to main and create a worktree properly.
- **CLAUDE.md added to shared state allowlist.** Was patched in the deployed guard but missing from source. Now in sync.

## Why

Agents kept getting blocked by the guard and then trying workarounds instead of following the process. The error message said "Use a worktree" but didn't explain the full workflow. Today's session hit this 5+ times. The guard works. The gap was agent knowledge.

## Issues closed

- #213
- #256

## How to verify

```bash
# In any repo on main, try to edit a file. The error should show the full workflow.
# In any repo on a branch (not worktree), try to edit. Should show worktree instructions.
```


path: _trash/RELEASE-NOTES-v1-9-46.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.46

**Centralized worktree management: guard rule, wip-release prune, Dev Guide convention.**

## What changed

### Guard: worktree path warning (#212)
Branch guard now warns when `git worktree add` creates a worktree outside `_worktrees/`. Shows the convention and suggests `ldm worktree add`. Warning only, not a hard block.

### wip-release: worktree prune (#212)
New step 12 in the release pipeline. After branch cleanup, prunes stale worktrees from `_worktrees/` whose branches are merged into main. Automatic cleanup after every release.

### Dev Guide: _worktrees/ convention (#212)
Documents the centralized worktree convention:
- All worktrees go in `_worktrees/<repo-name>--<branch-suffix>/`
- Use `ldm worktree add` (auto-detects repo, creates in the right place)
- Guard warns about worktrees outside the convention
- `wip-release` auto-prunes merged worktrees

## Why

Worktrees created as repo siblings confused iCloud sync, looked like real repos in directory listings, and were never cleaned up. This session alone created 10+ stale worktrees. The convention keeps them organized and the release pipeline cleans them automatically.

## Issues closed

- #212
- #213

## How to verify

```bash
# Guard warning:
cd /path/to/repo
git worktree add ../my-worktree -b test   # should warn about _worktrees/

# Correct path:
ldm worktree add cc-mini/test             # creates _worktrees/<repo>--cc-mini--test/
```


path: _trash/RELEASE-NOTES-v1-9-47.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.47

**New: `wip-repos claude` command + CLAUDE.md templates.**

## What changed

### `wip-repos claude` (Phases 1-3 of the CLAUDE.md plan)

New subcommand that generates cross-repo ecosystem sections in CLAUDE.md files. When an agent opens repo-A, it can't read repo-B. This command pre-generates the context.

```bash
wip-repos claude              # regenerate all repos
wip-repos claude my-repo      # regenerate one repo
wip-repos claude --init       # create CLAUDE.md for repos missing one
wip-repos claude --dry-run    # preview changes
```

Features:
- Reads all repos from manifest, extracts metadata (package.json, SKILL.md, directory structure)
- Generates `## Ecosystem` sections with delimiter comments (`<!-- wip-repos:start/end -->`)
- Hand-written sections are never overwritten
- Relevance filtering: only related repos shown (same category + core repos)
- `--init` creates starter CLAUDE.md from template for repos missing one

### Templates

- `templates/global-claude-md.md` ... universal CLAUDE.md for ~/.claude/CLAUDE.md
- `templates/repo-claude-md.template` ... per-repo starter with ecosystem placeholder

## Why

Agents lose context across repos. They can't read sibling repos at runtime. Pre-generating cross-repo maps into CLAUDE.md solves this without requiring runtime access.

## Issues closed

- #212 (partial: Phases 1-3 of 6)

## How to verify

```bash
wip-repos claude --dry-run
```


path: _trash/RELEASE-NOTES-v1-9-48.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.48

**Document wip-repos claude command in SKILL.md and TECHNICAL.md.**

## What changed

- SKILL.md: added `wip-repos claude` commands to the wip-repos section
- TECHNICAL.md: full documentation of how the ecosystem generator works, template locations, delimiter convention

## Why

v1.9.47 shipped the `wip-repos claude` command without updating technical docs. Now documented.

## Issues closed

- #212 (docs portion)

## How to verify

```bash
grep "wip-repos claude" SKILL.md TECHNICAL.md
```


path: _trash/RELEASE-NOTES-v1-9-49.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.49

**TECHNICAL.md audit: 2 weeks of undocumented features now documented.**

## What changed

Full TECHNICAL.md audit covering v1.9.15 through v1.9.48. Two passes. Key additions:

- **wip-release quality gates:** Technical docs gate, interface coverage gate, product docs auto-sync, all skip flags documented.
- **deploy-public.sh:** Full 8-step pipeline including GitHub Packages publishing, repo URL rewrite, co-author sync.
- **wip-license-guard:** Now documented as both CLI and Claude Code PreToolUse hook (guard.mjs). Enforcement details.
- **wip-branch-guard:** Worktree requirement on branches, non-repo file passthrough, workflow teaching messages.
- **wip-repos claude:** Cross-repo CLAUDE.md ecosystem generator fully documented.
- **Source code table:** Missing files added (guard.mjs, claude.mjs, mcp-server.mjs).
- **Log paths:** Fixed stale /tmp/ references to ~/.ldm/logs/.

## Why

15 releases shipped without TECHNICAL.md updates. Agents reading the docs were missing critical features: release gates, license enforcement hooks, deploy pipeline details.

## Issues closed

- #218

## How to verify

```bash
grep "Interface coverage" TECHNICAL.md    # new gate
grep "guard.mjs" TECHNICAL.md             # license-guard hook
grep "GitHub Packages" TECHNICAL.md       # deploy pipeline
```


path: _trash/RELEASE-NOTES-v1-9-50.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.50

**wip-release: require product update doc on every release.**

## What changed

New quality gate in wip-release: checks that `ai/dev-updates/product-update/*-product-update.md` was modified since the last release tag. Same pattern as dev-updates, roadmap, and readme-first checks.

The product update doc is a human-readable test guide. Each release entry has: what changed, how it's supposed to work, and how to test. New entries go at the top. Additive only.

## Why

Three repos now have product update docs but nothing enforced keeping them current. Without the gate, the docs will drift immediately (same problem we had with TECHNICAL.md).

## Issues closed

- #220

## How to verify

```bash
wip-release patch --dry-run
# Should warn if product update doc not modified since last release
```


path: _trash/RELEASE-NOTES-v1-9-51.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.51

## Branch Guard: Workspace Files Allowlist (#185)

Added TOOLS.md, MEMORY.md, IDENTITY.md, SOUL.md, WHERE-TO-WRITE.md, HEARTBEAT.md to the shared state allowlist. Both agents can now write to workspace files on main without being blocked.

Previously only SHARED-CONTEXT.md was allowed. This broke Lesa's ability to edit her own workspace files during the migration to ~/wipcomputerinc/.

## TECHNICAL.md: Backup Documentation

Updated LDM Dev Tools.app backup section to reflect the unified backup system. backup.sh now calls `~/.ldm/bin/ldm-backup.sh` (deployed by ldm install from wip-ldm-os-private/scripts/).


path: _trash/RELEASE-NOTES-v1-9-52.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.52

**Fix branch guard false-blocking bash commands targeting worktree paths**

## What changed

- Branch guard now extracts absolute paths from any bash command (mkdir, cp, mv, touch, etc.) and resolves the git branch from the target path's repo, not the CWD
- `findRepoRoot()` improved to walk up to existing directories for paths that don't exist yet (handles mkdir for new directories)
- Added `.ldm/worktrees` to allowed worktree locations alongside `_worktrees/` and `.claude/worktrees`

## Why

When Claude Code launches from `~/wipcomputerinc/` (on main) and runs bash commands targeting files inside a worktree (e.g., `mkdir -p /path/to/_worktrees/repo--branch/new-dir/`), the guard only knew how to extract paths from `cd` and `git -C` patterns. Any other command fell back to CWD resolution, saw "main", and blocked incorrectly. This caused minutes of wasted time every session.

## Issues closed

- wipcomputer/wip-ldm-os#187

## How to verify

```bash
# From CWD on main, this should no longer be blocked:
# mkdir -p /path/to/_worktrees/repo--branch/new-directory/
# cp file.txt /path/to/_worktrees/repo--branch/
```


path: _trash/RELEASE-NOTES-v1-9-53.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.53

**One-line summary of what this release does**

Tell the story. What was broken or missing? What did we build? Why does the user care?
Write at least one real paragraph of prose. Not just bullets. The release notes gate
will block if there is no narrative. Bullets are fine for details, but the story comes first.

## The story

(Write a paragraph here. What was the problem? What does this release fix? Why does it matter?
This is what users read. Make it worth reading.)

## Issues closed

- #282

## How to verify

```bash
# Commands to test the changes
```


path: _trash/RELEASE-NOTES-v1-9-54.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.54

Force redeploy: guard files were stale after v1.9.53.

## The story

v1.9.53 published the .worktrees guard fix to npm but ldm install saw the version as current and skipped redeploying the files. The deployed guard.mjs was still the old version. This release forces a version bump so the installer re-deploys.

This is a bug in the installer: it checks version numbers but not file contents. Filed for future fix.

## Issues closed

- #240 (partial: .worktrees convention)


path: _trash/RELEASE-NOTES-v1-9-55.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.55

Force redeploy: .worktrees guard fix.

## The story

v1.9.53 had the guard fix but deploy-public was missed. v1.9.54 force-redeployed but installer had already cached v1.9.54. This version ensures the public repo and npm are in sync so ldm install deploys the correct guard.mjs with .worktrees convention.

## Issues closed

- #240 (partial)


path: _trash/RELEASE-NOTES-v1-9-56.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.56

**Branch guard now blocks destructive git commands on all branches.**

## The story

The branch guard blocked commits and file writes on main, but allowed destructive git commands that destroy uncommitted work. Commands like `git clean -fd`, `git checkout --`, `git stash drop`, and `git reset --hard` slipped through because they were either in the allowed list or not in the blocked list. These commands destroyed Parker's Finder aliases, other agents' uncommitted edits, and user files multiple times on Mar 28-29.

The fix adds a new DESTRUCTIVE_PATTERNS list that fires on ALL branches, not just main. The guard also closes several bypass vectors: `node -e` removed from the allowed list, python/node file-write patterns detected, and `git checkout` narrowed to branch-switching only.

## What changed

- Added DESTRUCTIVE_PATTERNS: git clean -f, git checkout --, git stash drop/pop/clear, git reset --hard, git restore, python/node bypasses
- Removed `git checkout` blanket allow. Now only allows `git checkout <branch>` (switching)
- Removed `git stash drop` from allowed list
- Removed `node -e` from allowed bash patterns (bypass vector)
- Added `git stash show` and `git restore --staged` as safe read-only operations
- Deny message tells agent to use worktrees and safety checkpoints instead

## Issues closed

- #240 (branch guard + harness directories)
- #241 (python bypass detection)
- PR #284

## How to verify

```bash
# These should all be BLOCKED:
# git clean -fd
# git checkout -- somefile
# git stash drop
# git stash pop
# git reset --hard
# python3 -c "open('f','w').write('x')"

# These should still WORK:
# git checkout main (branch switching)
# git stash list (read-only)
# git status, git log, git diff
# Normal worktree workflow
```


path: _trash/RELEASE-NOTES-v1-9-57.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.57

**deploy-public.sh now excludes .worktrees/ and _worktrees/ from public repo syncs.**

## The story

v1.9.56 accidentally deployed worktree directories (containing embedded git repos) to the public repo. The deploy script's rsync excluded ai/, .git/, _trash/, and other dev artifacts but didn't exclude worktree directories. Added both .worktrees/ (new convention) and _worktrees/ (old convention) to the exclude list.

## Issues closed

- #228 (deploy-public.sh leaks .worktrees/ to public repo)

## How to verify

```bash
# Run deploy-public.sh --dry-run and confirm .worktrees/ is not synced
grep -n "worktrees" scripts/deploy-public.sh
```


path: _trash/RELEASE-NOTES-v1-9-58.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.58

**Fix deploy-public.sh losing release notes when invoked with relative path.**

## The story

When deploy-public.sh was called with `.` as the private repo path (e.g. `bash scripts/deploy-public.sh . wipcomputer/repo`), the script later cd'd into a temp directory. After that, `cd "."` no longer pointed to the private repo, so `gh release view` failed silently and release notes fell back to the empty "Release vX.Y.Z" default. This has been broken since at least v1.9.51.

Fix: resolve PRIVATE_REPO to an absolute path at startup before any cd happens.

## Issues closed

- #228 (continued from v1.9.57)

## How to verify

```bash
# From a repo directory, run with "." and check public release has real notes:
cd /path/to/private-repo
bash scripts/deploy-public.sh . wipcomputer/public-repo --dry-run
```


path: _trash/RELEASE-NOTES-v1-9-59.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.59

**Fix three bugs in branch guard destructive command handling.**

## The story

v1.9.56 added destructive command blocking but introduced three bugs because the new code was written differently from the existing guard pattern. The existing guard checks allowed patterns before blocked patterns and works per-command. The new code skipped the allowed check and matched against the entire raw command string, causing false positives on quoted text (blocking `gh issue create` when the body mentioned git commands) and false negatives on compound commands (allowing `rm -f file ; echo done` because `echo` is in the allowed list).

Fix: two helper functions that strip quoted content before matching and check each command segment independently. Same pattern as the existing guard code. Also adds `~/.claude/plans/` to the shared state allowlist so plan files are editable.

## Issues closed

- #232 (branch guard three bugs in v1.9.56)

## How to verify

```bash
# These should now be ALLOWED (were false-positive blocked):
# gh issue create --body "use git checkout -- to fix"
# echo "don't run git commit on main"

# These should now be DENIED (were false-negative allowed):
# rm -f file ; echo done  (on main)

# These should still be DENIED:
# git checkout -- file.txt
# python3 -c "open('f').write('x')"
```


path: _trash/RELEASE-NOTES-v1-9-6.md
content: # v1.9.6 ... Enforcement Gates

Three fixes that move the release pipeline from "suggestions agents forget" to "gates that block."

---

## syncSkillVersion corrupted quoted versions (#71)

Every release was appending the old version instead of replacing it. SKILL.md went from `"1.9.5"` to `"1.9.5".9.4".9.3".9.2".9.1"` over five releases.

Root cause: the regex `"?\S+?"?` used non-greedy matching. For quoted values, it consumed only part of the string, leaving the rest as trailing garbage.

Fix: replaced with `(?:"[^\n]*|\S+)`. Quoted values now match through end of line. Unquoted values use greedy `\S+`. Also fixed the staleness-check regex to extract clean semver from corrupted strings.

**Files changed:**
- `tools/wip-release/core.mjs` ... `syncSkillVersion()` regex fix
- `SKILL.md` ... repaired corrupted version back to `"1.9.5"`

---

## gh pr merge now always deletes branch (#74)

Every `gh pr merge` call in the codebase now includes `--delete-branch`. Previously, deploy-public.sh had a manual 3-line `gh api -X DELETE` cleanup block. That's gone. The flag handles it.

Also verified every merge uses `--merge` (never squash). Dev Guide updated with the new convention.

**Files changed:**
- `scripts/deploy-public.sh` ... added `--delete-branch`, removed manual cleanup
- `tools/deploy-public/deploy-public.sh` ... same
- `DEV-GUIDE-GENERAL-PUBLIC.md` ... updated merge examples
- `ai/DEV-GUIDE-FOR-WIP-ONLY-PRIVATE.md` ... updated merge rules
- `ai/_trash/DEV-GUIDE-private.md` ... updated
- `ai/_sort/_trash/ai_old/_trash/DEV-GUIDE-private.md` ... updated

---

## wip-release blocks on stale remote branches (#75)

New gate in the release pipeline. Before releasing, wip-release checks for remote branches that are fully merged into main but haven't been cleaned up.

- **Patch:** warns with the list of stale branches (non-blocking)
- **Minor/major:** blocks the release. Clean up first.
- **`--skip-stale-check`:** override flag for emergencies

Follows the existing gate pattern: fetches with `--prune`, filters out `origin/main`, `origin/HEAD`, and `--merged-` branches. Fails gracefully if git commands error.

**Files changed:**
- `tools/wip-release/core.mjs` ... `checkStaleBranches()` function, integrated as gate 0.8
- `tools/wip-release/cli.js` ... `--skip-stale-check` flag, help text

---

## Diffstat

```
 10 files changed, 102 insertions(+), 21 deletions(-)
```

## Install

```bash
npm install -g @wipcomputer/wip-ai-devops-toolbox
```

Or update an existing install:
```bash
wip-install wipcomputer/wip-ai-devops-toolbox
```

---

Built by Parker Todd Brooks, Lēsa (OpenClaw, Claude Opus 4.6), Claude Code (Claude Opus 4.6).


path: _trash/RELEASE-NOTES-v1-9-60.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.60

**Fix npm package bloat: exclude worktrees and _trash from published tarball.**

## The story

v1.9.59 published 869 files (3.9 MB) to npm because leftover worktree directories and _trash/ were included in the tarball. The .npmignore only excluded ai/ and .DS_Store. Added _trash/, .worktrees/, _worktrees/, .claude/, .wrangler/ to .npmignore. Also cleaned up 10 stale worktrees from previous sessions.

## Issues closed

- #232 (continued cleanup)

## How to verify

```bash
npm pack --dry-run 2>&1 | tail -5
# Should show ~200 files, not 869
```


path: _trash/RELEASE-NOTES-v1-9-61.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.61

**Add test script for branch guard. Fix node bypass regex.**

## The story

Every guard bug this session (v1.9.56-59) would have been caught by running a test before merging. This release adds test.sh to the guard that pipes test JSON into guard.mjs and verifies allow/deny results. 30 test cases covering destructive commands, quoted strings (Bug 1/3), compound commands (Bug 2), safe commands, and plan files.

Also fixes the node bypass regex: `require('fs').writeFileSync` wasn't caught because the regex looked for `fs.writeFile` literally. Broadened to match `writeFile` after `node -e`.

## Issues closed

- #232 (guard test coverage)

## How to verify

```bash
cd tools/wip-branch-guard && bash test.sh
# Should show: 30 passed, 0 failed, 3 skipped
```


path: _trash/RELEASE-NOTES-v1-9-62.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.62

**Fix wip-release leaving dirty state on main after every release.**

## The story

wip-release writes to 15+ files during a release (root package.json, 12 sub-tool package.json files, SKILL.md, CHANGELOG.md, product docs, trashed release notes). But gitCommitAndTag() only staged 3 files (package.json, CHANGELOG.md, SKILL.md). The other 12+ files were left modified on disk, uncommitted. This blocked git pull on the next operation and required manual `git checkout -- .` every time.

Fix: stage all files that wip-release modifies. Sub-tool package.json files, product docs (ai/product/), and trashed release notes (_trash/) are now included in the release commit.

## Issues closed

- #231 (wip-release rollback version bumps on failure)

## How to verify

```bash
wip-release patch
git status
# Should show clean working tree after release
```


path: _trash/RELEASE-NOTES-v1-9-63.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.63

**Fix all wip-release errors: branch cleanup crashes, shell injection, stale remote refs.**

## The story

Every wip-release run produced errors: "fatal: Not a valid object name +", "remote ref does not exist", and shell injection risks from branch names passed through execSync template strings. These were dismissed as "non-blocking" but they cluttered every release output and masked real problems.

Root cause: branch cleanup code (sections 10 and 11) used `execSync` with template strings, which breaks on branch names with special characters and allows shell injection. Also tried to delete remote branches that GitHub already deleted during PR merge.

Fix: replaced all `execSync` template strings with `execFileSync` array args (safe from injection). Added character validation to skip branches with special chars. Wrapped remote delete in try/catch since GitHub PR merge already handles deletion.

## Issues closed

- #231 (continued: release pipeline reliability)

## How to verify

```bash
wip-release patch --dry-run
# Should show no "fatal" or "Not a valid object name" errors
# Guard tests: cd tools/wip-branch-guard && bash test.sh
```


path: _trash/RELEASE-NOTES-v1-9-64.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.64

Closes #295

## Branch guard: allow extension cleanup

The branch guard blocked `rm` on deployed extension directories (`~/.openclaw/extensions/` and `~/.ldm/extensions/`) because those paths live inside git repos. But deployed extensions are managed by `ldm install`, not by hand. When a stale `-private` extension needed to be removed (e.g. `wip-xai-grok-private` replaced by the public `wip-xai-grok`), the agent couldn't clean it up without asking the user to run the command manually.

Added an allowlist pattern for `rm` targeting `.openclaw/extensions/` and `.ldm/extensions/` paths. Same approach as the existing `.ldm/state/` allowlist. The guard still blocks `rm` on actual repo source files.


path: _trash/RELEASE-NOTES-v1-9-65.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.65

**Fix release notes scaffold on protected branches**

When `wip-release patch` runs on main without a RELEASE-NOTES file, it used to scaffold a
template directly in the working tree. On repos with branch guards (pre-commit hooks that
block commits to main), this scaffolded file could not be removed or committed. It would
block `git pull` and leave the working tree dirty. This has happened multiple times across
different repos.

The fix adds a branch check before scaffolding. If the current branch is main or master,
wip-release now prints a clear error telling the user to write release notes on their
feature branch before merging, then exits non-zero without creating any files. The scaffold
behavior still works on feature branches, where it's actually useful.

## Issues closed

- Closes #223

## How to verify

```bash
# On main, without release notes: should error, NOT scaffold
cd any-repo && git checkout main
wip-release patch
# Expected: "Release notes missing. Write RELEASE-NOTES-v*.md on your feature branch before merging."
# Expected: no RELEASE-NOTES file created in working tree

# On a feature branch: should scaffold as before
git checkout -b test/scaffold-check
wip-release patch
# Expected: scaffolded template created
```


path: _trash/RELEASE-NOTES-v1-9-66.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.66

Auto-combine release notes when batching multiple PRs into a single release.

## The story

When multiple PRs merge to main before wip-release runs, the release had no good way to gather all their stories. Each PR might have its own RELEASE-NOTES file committed on the branch, but once the branch merges and the file gets trashed, the next release only sees an empty repo root. The agent had to write a new RELEASE-NOTES file from scratch, losing the narrative that was already reviewed in each PR.

Now wip-release looks back through git history. It finds every merge commit since the last tag, checks each one for RELEASE-NOTES files via `git diff-tree` and `git show`, and combines them into a single document. If only one PR had notes, it uses them as-is (fully backwards compatible). If multiple PRs had notes, it wraps them with per-PR section headers, strips duplicate top-level headings, and collects all issue references into a combined list at the end.

The detection sits at priority 2.5 in the release notes cascade: after the single-file check (RELEASE-NOTES-v{ver}.md on disk) but before the dev-update fallback. A file on disk always wins. The merged-PR scan only kicks in when nothing is found on disk.

## What changed

- New exported function `collectMergedPRNotes()` in `core.mjs` that scans git merge history for RELEASE-NOTES files
- Updated `cli.js` to call it at priority 2.5 in the notes detection cascade
- Updated help text to document the new detection path
- Zero breaking changes. Single-file detection still works exactly as before.

## Issues closed

- Closes #237

## How to verify

```bash
# In any repo with multiple merged PRs since last tag, each having RELEASE-NOTES files:
wip-release patch --dry-run
# Should show: "Combined release notes from N merged PRs"
```


path: _trash/RELEASE-NOTES-v1-9-68.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.68

Closes #239

## Four-track release pipeline

The release tool now supports four tracks: alpha, beta, hotfix, and stable. This replaces the single-track model where every release was public.

Alpha is silent (no public release notes by default). Beta publishes prerelease notes to the public repo. Hotfix publishes to npm @latest without syncing code to public. Stable is the full deploy: npm + code sync + release notes. Developers can iterate on private, ship betas to testers, and only go public when ready.

Version numbering uses standard semver prereleases: `1.9.68-alpha.1`, `1.9.68-beta.1`. The installer (`ldm install --beta` / `--alpha`) pulls the right tag from npm.


path: _trash/RELEASE-NOTES-v1-9-7.md
content: # Release Notes: AI DevOps Toolbox v1.9.7

## LDM OS Integration

AI DevOps Toolbox now works with LDM OS when it's available.

### wip-install delegates to ldm install

When the `ldm` CLI exists on PATH, `wip-install` delegates to `ldm install`. LDM OS handles the scaffold, interface detection, and extension deployment. The Toolbox's standalone behavior is preserved as a fallback when `ldm` isn't available.

Supports `--dry-run` and `--json` passthrough to `ldm install`.

### LDM OS tip

After standalone installs, the Toolbox prints a tip: "Run `ldm install` to see more skills you can add."

### Universal Installer link

The "Read more about Universal Installer" link now points to the LDM OS docs page. The Universal Installer engine moved to LDM OS. The Toolbox keeps `wip-install` as an entry point that delegates.

### Part of LDM OS

README includes a "Part of LDM OS" section linking back to the LDM OS repo.


path: _trash/RELEASE-NOTES-v1-9-71-alpha-11.md
content: # v1.9.71-alpha.11

## wip-branch-guard: SessionStart hook for main-CWD detection (Phase 13)

The guard now runs on two hook events, not just one:

1. **PreToolUse** (existing since 1.9.0): blocks file writes, git commits, and other mutating operations on main branch. Specific escape hatches via `ALLOWED_GIT_PATTERNS` and `ALLOWED_BASH_PATTERNS`.
2. **SessionStart** (new in 1.9.73): fires once per session boot, including startup, resume, and post-compaction resume. If the session's CWD is the main-branch working tree of a protected git repo, injects a warning into the boot context with actionable recovery commands.

## Why SessionStart matters

Earlier today's session ($900 of Opus tokens, 60 minutes of wall time) began with the agent waking up on main-branch CWD, trying to edit a file, hitting the PreToolUse guard, and entering a retry loop because the abstract error message did not give the agent the specific command it needed to unblock. The same class of failure had trapped at least two prior sessions earlier in the week.

The fix was multi-layered:

- Phase 1 (shipped in 1.9.72): make the `git stash push` escape hatch available so there's always a native way out
- Phase 2, 4, 6-11 (shipped today): fix the release pipeline so guard fixes actually reach the runtime
- **Phase 13 (this release): prevent the loop from starting in the first place by warning at session boot**

## What the SessionStart hook does

On every session boot, the guard checks if the CWD is in a git repo, reads the current branch, and:

- **Not in a git repo** → silent exit (nothing to warn about).
- **Not on main or master** → silent exit (feature branches are fine).
- **On main or master** → emits a warning via `hookSpecificOutput.additionalContext` that includes:
  - The repo path
  - A list of existing linked worktrees (first 10) with ready-to-paste `cd <path>` commands for each, annotated with the branch name
  - The template for creating a fresh worktree: `git worktree add .worktrees/<repo>--cc-mini--<feature> -b cc-mini/<feature>`
  - The native `git stash push` escape hatch instructions in case an untracked file blocks `git pull`
  - Pointers to the guard master plan and the bugs-plan-04-05-2026-002 master plan

The warning is informational. It does NOT block session boot. An agent that wakes up on main gets the warning in its initial context so the first time it reaches for a write operation, it already knows the recovery path.

## Implementation

Single-file change to `guard.mjs`. The existing `main()` function now dispatches on `hook_event_name` (falling back to shape detection for older payloads). A new `handleSessionStart(input)` function handles the SessionStart path, exiting the process when it's done.

`package.json` `claudeCode.hooks` now advertises both events. `INSTALL.md` updated with the new two-event wiring.

## New hook wiring

Both events point at the same `guard.mjs` script. Add both to `~/.claude/settings.json`:

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit|NotebookEdit|Bash",
        "hooks": [
          { "type": "command", "command": "node /Users/lesa/.ldm/extensions/wip-branch-guard/guard.mjs", "timeout": 5 }
        ]
      }
    ],
    "SessionStart": [
      {
        "hooks": [
          { "type": "command", "command": "node /Users/lesa/.ldm/extensions/wip-branch-guard/guard.mjs", "timeout": 5 }
        ]
      }
    ]
  }
}
```

## Files changed

- `tools/wip-branch-guard/guard.mjs`: new `handleSessionStart(input)`, event dispatcher in `main()`, worktree enumeration helper
- `tools/wip-branch-guard/package.json`: 1.9.72 -> 1.9.73, `claudeCode.hook` -> `claudeCode.hooks` (array of two entries)
- `tools/wip-branch-guard/INSTALL.md`: complete rewrite with new two-event wiring, what each event does, and test invocations for both
- `tools/wip-branch-guard/test.sh`: three new SessionStart test cases (main tree warns, feature branch silent, non-git silent)
- `CHANGELOG.md`: entry for 1.9.73

## Verified

- 36/36 test cases pass (33 existing PreToolUse + 3 new SessionStart)
- Manual injection with `echo '{"hook_event_name":"SessionStart","cwd":"...","source":"startup"}' | node guard.mjs` produces expected output
- Manual injection with feature-branch CWD exits silently
- Manual injection with /tmp (non-git) exits silently
- Existing PreToolUse tests unchanged, no regressions

## Cross-references

- `ai/product/bugs/guard/2026-04-05--cc-mini--guard-master-plan.md` Phase 7 (guard master plan's Phase 7 maps to this release)
- `ai/product/bugs/master-plans/bugs-plan-04-05-2026-002.md` Wave 2 phase 13
- Prior guard ships today: 1.9.72 (stash allow), 1.9.73 (this release)
- Settings.json wiring needs to be deployed to `~/.claude/settings.json` for the SessionStart hook to activate. `ldm install` should handle this.


path: _trash/RELEASE-NOTES-v1-9-71-alpha-15.md
content: # Release Notes: wip-ai-devops-toolbox v1.9.71-alpha.15

## Phase 3: True publish-before-commit

The release pipeline now publishes to npm BEFORE creating the git commit. Previously the order was commit -> publish -> push. If npm failed, the commit and tag were already created, requiring manual rollback.

New order: bump files -> npm publish -> (on success) commit+tag -> push. If npm publish fails, file changes are reverted with `git checkout -- .`. No commit exists. No tag exists. No remote state changed. Clean retry.

## Phase 5: Auto-publish sub-tools to npm

After the root package publishes successfully, the pipeline now scans `tools/*/package.json` and publishes each sub-tool that has a `name` field and is not `private`. If a sub-tool is already published at its current version, it's silently skipped. If a sub-tool fails to publish, the error is surfaced (Phase 7) but does not block the root release.

This means a guard fix that bumps `tools/wip-branch-guard/package.json` will auto-publish `@wipcomputer/wip-branch-guard` during the same release. No manual `npm publish` step.

## What this fixes

- Incident 3 (Apr 5): npm publish succeeded but git push failed, creating permanent state divergence
- Incident 5 (Apr 5): sub-tool packages required manual npm publish
- Incident 7 (Apr 5): sub-tool publish errors were swallowed as "non-fatal"


path: _trash/RELEASE-NOTES-v1-9-71-alpha-7.md
content: # v1.9.71-alpha.7

## wip-release: three hardening fixes for the release pipeline

Ships three related wip-release fixes in one release, each targeting a release-pipeline master-plan phase. See `ai/product/bugs/release-pipeline/2026-04-05--cc-mini--release-pipeline-master-plan.md` for the full context (7 incidents we hit today while trying to ship a single guard fix, 8 phases of forward work).

### Phase 1: refuse non-main invocations (was Incident 1)

Earlier today `wip-release alpha` ran from a feature worktree because `releasePrerelease()` had no worktree check at all (only `release()` and `releaseHotfix()` did). The result was a botched release commit on the worktree branch, never pushed to main, plus a cascade of downstream pipeline failures.

**Fix.** Extract a shared `enforceMainBranchGuard(repoPath, skipWorktreeCheck)` helper. Call it from all three release functions (`release`, `releaseHotfix`, `releasePrerelease`). The helper enforces two independent conditions:

1. **Linked worktree check.** If `git rev-parse --git-dir` resolves under `.git/worktrees/`, refuse with a ready-to-paste `cd <main-tree>` recovery command.
2. **Current branch check.** Even from the main working tree, `git branch --show-current` must be `main` or `master`. Refuse with `git checkout main && git pull && wip-release <track>` recovery command.

Both conditions bypassable via `--skip-worktree-check` for break-glass scenarios.

### Phase 2: tag collision pre-flight (was Incident 2)

Earlier today the pipeline also failed mid-release because `v1.9.71-alpha.4` and `v1.9.71-alpha.5` existed as local-only tags from prior failed releases. `wip-release alpha` tried to bump to alpha.5, hit the existing tag, and aborted. The release tool had no recovery path.

**Fix.** New `checkTagCollision(repoPath, newVersion)` helper runs after the main-branch guard, before the version bump. It distinguishes two cases:

1. **Tag exists on origin remote.** Legitimate prior release; refuses with a clear message.
2. **Tag exists locally but NOT on origin.** Stale leftover from a failed release; refuses but prints the safe recovery command: `git tag -d <tag> && wip-release <track>`.

Both cases log a clear error before any state mutation.

### Phase 8: sub-tool version drift becomes an error (was Incident 8)

Previously, if `tools/<sub-tool>/` files changed since the last git tag but `tools/<sub-tool>/package.json` version did not bump, `wip-release` printed a WARNING and proceeded. This silently shipped at least one "committed but never deployed" bug today: the guard fix had new code in `tools/wip-branch-guard/guard.mjs` but the same version, so `ldm install` ignored the sub-tool on redeploy.

**Fix.** New `validateSubToolVersions(repoPath, allowSubToolDrift)` helper replaces the three in-line duplicated drift checks in `release`, `releaseHotfix`, and `releasePrerelease`. Sub-tool drift without a version bump is now a hard refusal unless the caller passes `--allow-sub-tool-drift`.

## New CLI flags

- `--allow-sub-tool-drift` — Allow release even if a sub-tool's files changed since the last tag without a version bump. Default behavior is to refuse.

## Files changed

- `tools/wip-release/core.mjs`: new `enforceMainBranchGuard`, `logMainBranchGuardFailure`, `checkTagCollision`, `validateSubToolVersions` helpers. Inline checks in `release`, `releaseHotfix`, `releasePrerelease` replaced with calls to the helpers. `allowSubToolDrift` threaded through all three signatures.
- `tools/wip-release/cli.js`: parses `--allow-sub-tool-drift`, passes it to all three release functions. `skipWorktreeCheck` now also passed to `releasePrerelease` (was missing). Help text updated.
- `tools/wip-release/package.json`: version bump to 1.9.72.
- `CHANGELOG.md`: entry added.

## Verified

- From a feature worktree: `wip-release alpha --dry-run` refuses with concrete `cd <main-tree>` recovery command. Same for `patch` and `hotfix`.
- `--skip-worktree-check` bypass works.
- Module imports cleanly via `node -e "import('./tools/wip-release/core.mjs')"`.

## Known limitation (follow-up)

The tag collision and sub-tool drift checks run in live release mode, not in dry-run preview. Dry-run still shows "would bump" for a version that would actually fail later. Follow-up: move both checks before the dry-run short-circuit so preview is a faithful preflight. Tracked in the release-pipeline master plan as a small cleanup.

## Cross-references

- `ai/product/bugs/release-pipeline/2026-04-05--cc-mini--release-pipeline-master-plan.md` Phases 1, 2, 8
- `ai/product/bugs/guard/2026-04-05--cc-mini--guard-master-plan.md` Phases 3, 4 (partial, not all covered here; auto-publish sub-tool remains deferred to a follow-up PR)
- `ai/product/bugs/master-plans/bugs-plan-04-05-2026-002.md` Wave 2 phases 4, 5, 11


path: _trash/RELEASE-NOTES-v1-9-71-alpha-8.md
content: # v1.9.71-alpha.8

## wip-release: automatic PR flow for protected main (Phase 4)

When `git push origin main` fails with GitHub's "protected branch" rejection (`GH006: Changes must be made through a pull request`), wip-release now automatically:

1. Creates a release branch `cc-mini/release-v<version>` at the current commit
2. Pushes the branch to origin
3. Opens a PR via `gh pr create` with title `release: v<version>`
4. Merges the PR via `gh pr merge --merge --delete-branch`
5. Pushes the tag separately (tags bypass branch protection on most GitHub setups)
6. Fast-forwards local main so downstream steps (deploy-public, etc.) have a clean state

Previously this was a 4-command manual workflow every release:

```
git branch cc-mini/release-alpha-N
git push -u origin cc-mini/release-alpha-N
gh pr create --base main --head cc-mini/release-alpha-N --title '...'
gh pr merge <pr> --merge --delete-branch
git push origin v<version>
```

Every release. Every time. Eliminated.

## Fallback behavior

If any step of the auto-PR flow fails (gh CLI missing, PR create failure, merge failure, tag push failure), wip-release logs a concrete recovery command for the exact failure mode and continues (non-fatal, matches prior push-failed behavior). The user can always complete the remaining steps manually.

## Direct push still works

If the repo allows direct push to main (typical for private staging repos), wip-release tries direct push first and only falls back to the PR flow on the specific GH006 / "protected branch" error. No behavioral change for unprotected repos.

## Files changed

- `tools/wip-release/core.mjs`: new `pushReleaseWithAutoPr(repoPath, newVersion, level)` and `logPushFailure(result, tag)` helpers. Three push sites in `release()`, `releaseHotfix()`, `releasePrerelease()` migrated to use the helper.
- `tools/wip-release/package.json`: 1.9.72 -> 1.9.73
- `CHANGELOG.md`: entry added

## Verified

- Module imports cleanly via `node -e "import('./tools/wip-release/core.mjs')"`.
- Error detection regex handles GH006 variants: `/protected branch|GH006|Changes must be made through a pull request/i`.
- All three release tracks (stable, prerelease, hotfix) use the same helper.

## Cross-references

- `ai/product/bugs/release-pipeline/2026-04-05--cc-mini--release-pipeline-master-plan.md` Phase 4 (Incident 4)
- `ai/product/bugs/master-plans/bugs-plan-04-05-2026-002.md` Wave 2 phase 7
- Prior ship: alpha.7 closed Phases 1, 2, 8 of the same plan.


path: _trash/RELEASE-NOTES-v1-9-72-alpha-1.md
content: # v1.9.72-alpha.1

## wip-branch-guard: unblock native escape hatch for clearing untracked files on main

**Problem.** When an untracked file exists in main's working tree (for example, content Parker saved manually before a PR merged, or a deployed artifact the pipeline dropped there), `git pull` refuses to proceed because it would overwrite the untracked file. Every command that could clear the file was blocked by the guard: `rm`, `mv`, `git stash push`, `git clean`, `git reset`, `git restore`. No native escape hatch existed. Agents (and humans) lost hours looping: retry rm, retry mv, tool-swap to Write/Edit to bypass the guard, rationalize, spiral. One session today burned $936 on the loop before the bug was isolated.

**Fix.** Add `git stash push` / `git stash save` / bare `git stash` to `ALLOWED_GIT_PATTERNS`. Stashing is non-destructive because `git stash drop`, `git stash pop`, and `git stash clear` remain in `DESTRUCTIVE_PATTERNS` (blocked on any branch). The stash survives as a safety net; nothing is ever lost.

**New workflow for this failure mode:**

```
git stash push -u -- path/to/untracked-file    # move untracked file aside
git pull                                        # pulls cleanly
git stash list                                  # file preserved in stash
```

**Error message improvement.** The `WORKFLOW_ON_MAIN` block now includes a concrete, copy-pasteable stash workaround so future sessions don't loop. LLMs and humans both follow concrete commands more reliably than abstract workflow steps.

**Test coverage added.** `test.sh` now asserts `git stash push`, `git stash save`, and bare `git stash` all return `allow`. All 33 tests pass.

## Why this matters

This is the third time in five days that the guard loop has trapped a session. The prior bug files (`ai/product/bugs/guard/2026-04-03--cc-mini--guard-blocks-readonly-bash-loops.md`, `2026-04-05--cc-mini--branch-guard-compaction-loop.md`) document the pattern. This fix closes one specific failure mode (untracked-stub-blocks-pull). Other guard loop failure modes remain and will be addressed separately.

## Files changed

- `tools/wip-branch-guard/guard.mjs`: two new `ALLOWED_GIT_PATTERNS` entries, expanded `WORKFLOW_ON_MAIN` with stash workaround
- `tools/wip-branch-guard/package.json`: 1.9.71 -> 1.9.72
- `tools/wip-branch-guard/test.sh`: three new passing test cases
- `CHANGELOG.md`: entry for 1.9.72-alpha.1


path: ai/_sort/README.md
content: # _sort/

The holding pen. Files that need to be looked at and filed somewhere.

## What Goes Here

- iCloud duplicates or randomly placed files that need sorting
- Files you're not sure where to put yet
- Anything that needs a human to look at it and decide where it belongs

## Rules

- **Not trash.** `_sort/` is for files you want to review. `_trash/` is for files you're done with.
- **Don't let it pile up.** Check this folder periodically. File things or trash them.
- **Agents:** If you don't know where a file goes, put it in `_sort/`. A human will sort it later.


path: ai/repos/gstack-private/browse/test/fixtures/empty.html
content: <!DOCTYPE html>
<html><body></body></html>


path: ai/repos/gstack-private/conductor.json
content: {
  "scripts": {
    "setup": "bin/dev-setup",
    "archive": "bin/dev-teardown"
  }
}


path: tools/wip-file-guard/openclaw.plugin.json
content: {
  "name": "wip-file-guard",
  "version": "1.0.0",
  "description": "Blocks destructive edits to protected files (CLAUDE.md, SHARED-CONTEXT.md, SOUL.md, etc.)",
  "lifecycle": {
    "before_tool_use": "./guard.mjs"
  }
}


Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)