From ae791781c22b150baaad9f095c9703ff28fb546c Mon Sep 17 00:00:00 2001 From: Defame1297 Date: Mon, 31 Aug 2026 19:46:35 +0000 Subject: [PATCH] fix(git): restore router coverage and commands the retrofit dropped git-workflow calls itself a router but named two of the six domains it routes to; the other four appeared nowhere in the file. All six are now named, with a routing table in the always-loaded body. git-submodules lost the foreach shell-variable semantics -- only the bare names survived, though $sm_path and $displaypath differ solely by which directory you are in. The table is back. Its relocated commands had also dropped the rtk git prefix its own SKILL.md mandates; 24 of them are re-prefixed. The wider rtk inconsistency across the plugin stays with #113. Also restores git-commits' body and footers output fields, git-branches' tag/ branch detection commands, git-worktrees' git config --worktree, pc-run's ambiguity fallback, git-remotes' git-history boundary, and git-history's pickaxe triggers. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01EJJrm5YmacbwMdzZpXcoti --- plugins/git/.apm/skills/git-branches/SKILL.md | 2 +- plugins/git/.apm/skills/git-commits/SKILL.md | 11 ++++- plugins/git/.apm/skills/git-history/SKILL.md | 8 ++-- plugins/git/.apm/skills/git-remotes/SKILL.md | 1 + .../git/.apm/skills/git-submodules/README.md | 2 +- .../git/.apm/skills/git-submodules/SKILL.md | 6 ++- .../git-submodules/references/README.md | 5 ++- .../git-submodules/references/removal.md | 12 +++--- .../references/setup-and-update.md | 42 ++++++++++++++----- .../references/urls-and-config.md | 18 ++++---- .../git/.apm/skills/git-workflow/README.md | 4 +- plugins/git/.apm/skills/git-workflow/SKILL.md | 26 ++++++++++-- .../git/.apm/skills/git-worktrees/SKILL.md | 2 +- plugins/git/.apm/skills/pc-run/SKILL.md | 3 ++ plugins/git/skills/git-branches/SKILL.md | 2 +- plugins/git/skills/git-commits/SKILL.md | 11 ++++- plugins/git/skills/git-history/SKILL.md | 8 ++-- plugins/git/skills/git-remotes/SKILL.md | 1 + plugins/git/skills/git-submodules/README.md | 2 +- plugins/git/skills/git-submodules/SKILL.md | 6 ++- .../git-submodules/references/README.md | 5 ++- .../git-submodules/references/removal.md | 12 +++--- .../references/setup-and-update.md | 42 ++++++++++++++----- .../references/urls-and-config.md | 18 ++++---- plugins/git/skills/git-workflow/README.md | 4 +- plugins/git/skills/git-workflow/SKILL.md | 26 ++++++++++-- plugins/git/skills/git-worktrees/SKILL.md | 2 +- plugins/git/skills/pc-run/SKILL.md | 3 ++ 28 files changed, 198 insertions(+), 86 deletions(-) diff --git a/plugins/git/.apm/skills/git-branches/SKILL.md b/plugins/git/.apm/skills/git-branches/SKILL.md index 7a2e715..ca98aaf 100644 --- a/plugins/git/.apm/skills/git-branches/SKILL.md +++ b/plugins/git/.apm/skills/git-branches/SKILL.md @@ -20,7 +20,7 @@ metadata: ## Gotchas - **Uncommitted changes abort a switch.** `git switch` refuses rather than clobbering conflicting local edits. Offer to stash and retry — forcing the checkout past it is how work disappears. -- **A branch and a tag can carry the same name.** Prefer `git switch` over `git checkout`, and where a command accepts either ref, disambiguate with `refs/heads/` or `refs/tags/`. +- **A branch and a tag can carry the same name.** Detect it before acting — `git branch --list ` and `git tag --list `; output from both means the name is ambiguous. Prefer `git switch` over `git checkout`, and where a command accepts either ref, disambiguate with `refs/heads/` or `refs/tags/`. - **`main` and `master` are a refusal, not a gate.** Force-pushing, force-deleting, or renaming them is rejected even when the caller passes `confirm: true` — no flag makes the remote's history recoverable. Offer a new branch instead. ## Step 1 — Determine the branching pattern diff --git a/plugins/git/.apm/skills/git-commits/SKILL.md b/plugins/git/.apm/skills/git-commits/SKILL.md index 4cc71c2..3b9683c 100644 --- a/plugins/git/.apm/skills/git-commits/SKILL.md +++ b/plugins/git/.apm/skills/git-commits/SKILL.md @@ -57,8 +57,17 @@ For an agent caller, return: "semver_impact": "MAJOR|MINOR|PATCH|none", "breaking_change": false, "confirmation_required": false, - "details": { "type": "feat", "scope": "api", "description": "add user authentication" } + "details": { + "type": "feat", + "scope": "api", + "description": "add user authentication", + "body": "optional body text, or null", + "footers": ["Fixes: #123", "Refs: #456", "Co-authored-by: Bob "] + } } ``` +`details.footers` is an array of the resolved trailer lines, empty when there are none — never a +single joined string, and never omitted. Downstream agents index it. + For a human caller, show the same fields as a prose preview with a confirmation prompt. diff --git a/plugins/git/.apm/skills/git-history/SKILL.md b/plugins/git/.apm/skills/git-history/SKILL.md index a4ab045..bfb1fa9 100644 --- a/plugins/git/.apm/skills/git-history/SKILL.md +++ b/plugins/git/.apm/skills/git-history/SKILL.md @@ -2,10 +2,10 @@ name: git-history description: > - Use when investigating git history — querying logs, tracing when a change - landed, bisecting the commit that broke something, or locating one to - revert or backport. Not authoring or rebasing commits -> `git-commits`. - Not history on a Gitea server -> `gitea-branches`. + Use when investigating git history — pickaxe (`-S`/`-G`) or `-L` line-range log + queries, tracing when a change landed, bisecting what broke something, or + locating a commit to revert or backport. Not authoring or rebasing commits -> + `git-commits`. Not a Gitea server's history -> `gitea-branches`. metadata: category: git diff --git a/plugins/git/.apm/skills/git-remotes/SKILL.md b/plugins/git/.apm/skills/git-remotes/SKILL.md index 3cb6a01..5f457c1 100644 --- a/plugins/git/.apm/skills/git-remotes/SKILL.md +++ b/plugins/git/.apm/skills/git-remotes/SKILL.md @@ -6,6 +6,7 @@ description: > remote, even when the user does not name it. Not local commits -> `git-commits`. Not local branches -> `git-branches`. + Not log or bisect queries -> `git-history`. Not submodule pointers -> `git-submodules`. metadata: diff --git a/plugins/git/.apm/skills/git-submodules/README.md b/plugins/git/.apm/skills/git-submodules/README.md index 06aa066..4b1d2b9 100644 --- a/plugins/git/.apm/skills/git-submodules/README.md +++ b/plugins/git/.apm/skills/git-submodules/README.md @@ -29,7 +29,7 @@ conflicts, and a recovery `next_step` when applicable). |------|---------| | `SKILL.md` | Skill instructions for agents — gotchas, shared working rules, and the task dispatch table | | `references/README.md` | Describes contents of references/ | -| `references/setup-and-update.md` | Loaded when cloning a superproject, adding a submodule, or initializing, updating, or re-pinning one — includes the full `add` and `update` flag tables and the pinning workflows | +| `references/setup-and-update.md` | Loaded when cloning a superproject, adding a submodule, initializing, updating, or re-pinning one, or running a command across all of them — includes the full `add` and `update` flag tables, the pinning workflows, and the `foreach` shell-variable table | | `references/urls-and-config.md` | Loaded when changing where a submodule points or how it is configured — `.gitmodules` vs `.git/config` anatomy, both key tables, `sync`/`set-url`/`set-branch`, local mirror overrides, relative URLs, the custom-`update` security gate, and `absorbgitdirs` | | `references/removal.md` | Loaded when removing or deinitializing a submodule — why `deinit` is not removal, and the four-step removal sequence | | `references/sources.md` | Research sources and provenance | diff --git a/plugins/git/.apm/skills/git-submodules/SKILL.md b/plugins/git/.apm/skills/git-submodules/SKILL.md index e274475..297f6a2 100644 --- a/plugins/git/.apm/skills/git-submodules/SKILL.md +++ b/plugins/git/.apm/skills/git-submodules/SKILL.md @@ -34,7 +34,9 @@ them pins a state nobody else can reproduce. To run one command across every submodule: `rtk git submodule foreach --recursive ''`. Inside ``, Git sets `$name`, `$sm_path`, `$displaypath`, `$sha1` and `$toplevel`; append `|| :` to -continue past a failure instead of aborting the traversal. +continue past a failure instead of aborting the traversal. `$sm_path` and `$displaypath` name the +same directory from different vantage points — if which one you want is not obvious, read the +variable table in `references/setup-and-update.md` before writing the command. ## Dispatch @@ -42,7 +44,7 @@ Read only the row that matches the request. | Task | Reference | |---|---| -| Clone a superproject with submodules, or add, initialize, update or re-pin one | `references/setup-and-update.md` | +| Clone a superproject with submodules; add, initialize, update or re-pin one; run a command across all of them with `foreach` | `references/setup-and-update.md` | | Change where a submodule points — `sync`, `set-url`, `set-branch`, a local mirror override, `absorbgitdirs`, or any `.gitmodules` / `.git/config` key | `references/urls-and-config.md` | | Remove a submodule, or `deinit` one without removing it | `references/removal.md` | diff --git a/plugins/git/.apm/skills/git-submodules/references/README.md b/plugins/git/.apm/skills/git-submodules/references/README.md index 19b9784..0df0d93 100644 --- a/plugins/git/.apm/skills/git-submodules/references/README.md +++ b/plugins/git/.apm/skills/git-submodules/references/README.md @@ -10,8 +10,9 @@ One file per task branch in SKILL.md's dispatch table. Load only the one that ma ## setup-and-update.md Cloning a superproject that has submodules, adding a dependency as a submodule, initializing -without cloning, and updating or re-pinning. Carries the `add` and `update` flag tables and the -keep-pinned and move-the-pin-forward workflows. +without cloning, updating or re-pinning, and running one command across every submodule. Carries +the `add` and `update` flag tables, the keep-pinned and move-the-pin-forward workflows, and the +`foreach` shell-variable table (`$name`, `$sm_path`, `$displaypath`, `$sha1`, `$toplevel`). ## urls-and-config.md diff --git a/plugins/git/.apm/skills/git-submodules/references/removal.md b/plugins/git/.apm/skills/git-submodules/references/removal.md index 4bee62e..0b7d331 100644 --- a/plugins/git/.apm/skills/git-submodules/references/removal.md +++ b/plugins/git/.apm/skills/git-submodules/references/removal.md @@ -11,7 +11,7 @@ Both operations are destructive. Confirm with the user before executing either. ## `deinit` is not removal ```bash -git submodule deinit # --all for every submodule, -f if locally modified +rtk git submodule deinit # --all for every submodule, -f if locally modified ``` `deinit` clears the submodule's section from `.git/config` and empties its working tree. The @@ -22,11 +22,11 @@ or to reset a broken checkout, not to delete a dependency. ## Full removal, in order ```bash -git submodule deinit -f # unregister from .git/config -git rm # drop the .gitmodules entry and the gitlink from the index -rm -rf .git/modules// # stale git dir: not tracked, not cleaned up by git -git commit -m "chore: remove submodule" +rtk git submodule deinit -f # unregister from .git/config +rtk git rm # drop the .gitmodules entry and the gitlink from the index +rm -rf .git/modules// # stale git dir: not tracked, not cleaned up by git +rtk git commit -m "chore: remove submodule" ``` -The third step is the one that gets skipped. `.git/modules//` survives `git rm`, and while it +The third step is the one that gets skipped. `.git/modules//` survives `rtk git rm`, and while it is present Git refuses to add a submodule at the same path again. diff --git a/plugins/git/.apm/skills/git-submodules/references/setup-and-update.md b/plugins/git/.apm/skills/git-submodules/references/setup-and-update.md index e7bae51..dfb9c75 100644 --- a/plugins/git/.apm/skills/git-submodules/references/setup-and-update.md +++ b/plugins/git/.apm/skills/git-submodules/references/setup-and-update.md @@ -9,16 +9,16 @@ source_keys: ## Clone a superproject that already has submodules ```bash -git clone --recurse-submodules # Git 2.13+, one step +rtk git clone --recurse-submodules # Git 2.13+, one step # or, against an existing clone -git submodule update --init --recursive +rtk git submodule update --init --recursive ``` ## Add a dependency as a submodule ```bash -git submodule add -git commit -m "chore: add as submodule" +rtk git submodule add +rtk git commit -m "chore: add as submodule" ``` `add` stages a `.gitmodules` entry and a gitlink — the commit is still required. Flags: @@ -32,14 +32,14 @@ git commit -m "chore: add as submodule" ## Initialize without cloning -`git submodule init [...]` copies submodule URLs from `.gitmodules` into `.git/config` and +`rtk git submodule init [...]` copies submodule URLs from `.gitmodules` into `.git/config` and does nothing else. This is the point at which a local URL override can be edited before any fetch happens. If a local mirror override is wanted, read `references/urls-and-config.md` before running `update`. Use `update --init` to run both steps at once. ## Update -`git submodule update --init --recursive` is the common case: it clones what is missing and checks +`rtk git submodule update --init --recursive` is the common case: it clones what is missing and checks out the commit the superproject recorded, in detached HEAD. | Flag | Meaning | @@ -59,16 +59,38 @@ out the commit the superproject recorded, in detached HEAD. ## Keep submodules pinned to the recorded commit ```bash -git submodule update --recursive # after every git pull -git config submodule.recurse true # or do it automatically on pull/push/checkout +rtk git submodule update --recursive # after every rtk git pull +rtk git config submodule.recurse true # or do it automatically on pull/push/checkout ``` ## Move the pin forward to the tracked branch tip ```bash -git submodule update --remote --merge --recursive -git commit -am "chore: update submodules to latest" +rtk git submodule update --remote --merge --recursive +rtk git commit -am "chore: update submodules to latest" ``` `--remote` requires `submodule..branch`; without it Git falls back to the remote's default branch. Commit the superproject afterwards or the new pin is lost on the next `update`. + +## Run one command across every submodule + +```bash +rtk git submodule foreach --recursive '' +rtk git submodule foreach 'git pull origin main || :' # || : continues past a failure +``` + +`` runs inside each submodule's own working tree, so the git calls in it are the +submodule's own — that is the one place a bare `git` is correct. Append `|| :` to keep the +traversal going instead of aborting at the first failure. + +Git exports five shell variables into ``. `$sm_path` and `$displaypath` name the same +directory from different vantage points and are not interchangeable: + +| Variable | Meaning | +|---|---| +| `$name` | Logical submodule name (the `.gitmodules` section name, which need not match the path) | +| `$sm_path` | Path relative to the superproject root | +| `$displaypath` | Path relative to the current working directory | +| `$sha1` | Commit SHA the superproject has recorded for this submodule | +| `$toplevel` | Absolute path of the superproject's root | diff --git a/plugins/git/.apm/skills/git-submodules/references/urls-and-config.md b/plugins/git/.apm/skills/git-submodules/references/urls-and-config.md index 5d59691..596724b 100644 --- a/plugins/git/.apm/skills/git-submodules/references/urls-and-config.md +++ b/plugins/git/.apm/skills/git-submodules/references/urls-and-config.md @@ -10,7 +10,7 @@ source_keys: - **`.gitmodules`** — version-controlled, shared with collaborators. Defines each submodule's logical name, path, and canonical URL. -- **`.git/config`** — local only, populated by `git submodule init`. Local URL overrides live here +- **`.git/config`** — local only, populated by `rtk git submodule init`. Local URL overrides live here and never propagate to another clone. The submodule's own `.git` directory lives at `.git/modules//` in the superproject and is @@ -38,9 +38,9 @@ linked to the submodule's working tree by a `.git` pointer file. ## Rebind a URL or branch ```bash -git submodule sync --recursive # push .gitmodules URLs into .git/config -git submodule set-url # change the canonical URL -git submodule set-branch -b # set the branch used by update --remote +rtk git submodule sync --recursive # push .gitmodules URLs into .git/config +rtk git submodule set-url # change the canonical URL +rtk git submodule set-branch -b # set the branch used by update --remote ``` Run `sync` after an upstream rename: existing clones keep the stale URL in `.git/config` until @@ -49,9 +49,9 @@ they do. ## Override a URL locally (private mirror) ```bash -git submodule init +rtk git submodule init # edit .git/config: submodule..url = -git submodule update +rtk git submodule update ``` Local-only, invisible to collaborators, and overwritten by the next `sync`. @@ -65,15 +65,15 @@ everywhere else. ## Custom `update` commands are security-gated A `.gitmodules` entry of `update = !some-command` is never copied into `.git/config` by -`git submodule init`. That is deliberate: it stops a hostile clone from silently executing +`rtk git submodule init`. That is deliberate: it stops a hostile clone from silently executing arbitrary code. Setting it locally in `.git/config` is the only way to enable it. ## Relocate an embedded `.git` directory ```bash -git submodule absorbgitdirs [...] +rtk git submodule absorbgitdirs [...] ``` Moves a submodule's own `.git` directory into `.git/modules//` and leaves a `.git` pointer file behind. Needed when a nested repository was created or copied in without going through -`git submodule add`. +`rtk git submodule add`. diff --git a/plugins/git/.apm/skills/git-workflow/README.md b/plugins/git/.apm/skills/git-workflow/README.md index 607924f..10659fd 100644 --- a/plugins/git/.apm/skills/git-workflow/README.md +++ b/plugins/git/.apm/skills/git-workflow/README.md @@ -4,7 +4,7 @@ Human-friendly interface for interactive git workflows with conversational promp ## What it does -This skill wraps the `git-orchestrate` agent to provide an interactive, educational interface for humans performing git workflows. It handles commits, branch management, history inspection, submodules, worktrees, and remotes. The skill parses user intent, gathers session context, invokes the orchestrator, and presents results in plain language with inline help, progress updates, and explanations of what's happening. It enforces confirmation gates for destructive operations (force-push, branch deletion, rebasing with history loss, force-checkout) and provides best-practices guidance throughout. The org's non-negotiable git rules live in `references/hard-rules.md` and are loaded only when a request could conflict with one. +This skill wraps the `git-orchestrate` agent to provide an interactive, educational interface for humans performing git workflows. It is the router for the six local-git domain skills — `git-commits`, `git-branches`, `git-history`, `git-remotes`, `git-submodules` and `git-worktrees` — and `SKILL.md` carries a table mapping each of them to the requests it owns, so an ambiguous request resolves to exactly one domain before anything runs. The skill parses user intent, gathers session context, invokes the orchestrator, and presents results in plain language with inline help, progress updates, and explanations of what's happening. It enforces confirmation gates for destructive operations (force-push, branch deletion, rebasing with history loss, force-checkout) and provides best-practices guidance throughout. The org's non-negotiable git rules live in `references/hard-rules.md` and are loaded only when a request could conflict with one. ## Usage @@ -18,7 +18,7 @@ Describe your git workflow: commit, create a branch, rebase, inspect history, ma | File | Purpose | |------|---------| -| `SKILL.md` | Skill instructions for agents | +| `SKILL.md` | Skill instructions for agents — the six-domain routing table, the workflow steps, and the interaction style | | `README.md` | This file | | `references/hard-rules.md` | The org's non-negotiable git rules; read when a request creates, amends, or rewrites a commit, pushes, or touches hooks, config, or credentials | | `references/README.md` | Describes the references directory contents | diff --git a/plugins/git/.apm/skills/git-workflow/SKILL.md b/plugins/git/.apm/skills/git-workflow/SKILL.md index e7e5034..40422fb 100644 --- a/plugins/git/.apm/skills/git-workflow/SKILL.md +++ b/plugins/git/.apm/skills/git-workflow/SKILL.md @@ -3,8 +3,9 @@ name: git-workflow description: > Use when a human's local git request is general or ambiguous — it routes to the owning - domain skill. Not an unambiguous commit -> `git-commits`. Not an unambiguous branch -> - `git-branches`. Not an agent caller -> `git-orchestrate`. Not Gitea -> `gitea-workflow`. + domain skill: `git-commits`, `git-branches`, `git-history`, `git-remotes`, `git-submodules` + or `git-worktrees`. An unambiguous request goes straight to its domain skill instead. Not an + agent caller -> `git-orchestrate`. Not Gitea -> `gitea-workflow`. metadata: category: git @@ -25,10 +26,27 @@ metadata: mandated org wrapper, not a style preference. Submodule-specific commands run from inside the submodule's own directory instead. +## Domains + +Every request resolves to exactly one of these six. An unambiguous one should have gone straight +to the domain skill; this skill exists for the ones that did not. + +| The request is about | Domain | +|---|---| +| Writing, amending, squashing, or cherry-picking a commit, and its message | `git-commits` | +| Creating, switching, deleting, renaming, tracking, or merging a local branch | `git-branches` | +| When a change landed, which commit broke something, what to revert or backport | `git-history` | +| Anything touching a remote — remote config, fetch, push, pull — even unnamed | `git-remotes` | +| A nested repository pinned inside this one by a recorded commit | `git-submodules` | +| Several branches checked out at once, in separate directories, without stashing | `git-worktrees` | + +`git-orchestrate` executes whatever this resolves to (step 5); the table only decides which domain +owns the request. + ## Workflow -1. **Parse intent** — extract the operation (commit, create branch, rebase, inspect history, …) - and any options the user named. +1. **Parse intent** — extract the operation and, from the table above, the domain that owns it, + plus any options the user named. 2. **Check the hard rules** — if the request creates, amends, or rewrites a commit, pushes, or touches hooks, config, or credentials, read `references/hard-rules.md`. Raise the relevant rule before acting, not after. diff --git a/plugins/git/.apm/skills/git-worktrees/SKILL.md b/plugins/git/.apm/skills/git-worktrees/SKILL.md index f89dcfe..15a89fc 100644 --- a/plugins/git/.apm/skills/git-worktrees/SKILL.md +++ b/plugins/git/.apm/skills/git-worktrees/SKILL.md @@ -18,7 +18,7 @@ metadata: - **A branch can be checked out in only one worktree at a time.** `git worktree add` on an already-checked-out branch fails; `--force` is the only override, so use it only deliberately. - **Never `rm -rf` a worktree directory.** That strands metadata in `$GIT_DIR/worktrees/`. Use `git worktree remove`, or `git worktree prune` afterwards. - **Submodules break worktree support.** A worktree containing submodules cannot be moved at all, and needs `--force` to remove. -- **`extensions.worktreeConfig = true` is a one-way door.** It costs compatibility with older Git and forces `core.bare`/`core.worktree` into `config.worktree`. Leave it off unless per-worktree config is needed. +- **`extensions.worktreeConfig = true` is a one-way door.** Without it, `git config --worktree` errors; with it, that flag writes to the worktree's own `config.worktree` file, and `core.bare`/`core.worktree` are forced there too. It also breaks older Git. Leave it off unless per-worktree config is needed. ## Step 1 — Dispatch diff --git a/plugins/git/.apm/skills/pc-run/SKILL.md b/plugins/git/.apm/skills/pc-run/SKILL.md index bc29166..82ebc7a 100644 --- a/plugins/git/.apm/skills/pc-run/SKILL.md +++ b/plugins/git/.apm/skills/pc-run/SKILL.md @@ -47,6 +47,9 @@ Determine intent from the user's request, then execute the matching operation. W | "clean", "wipe cache", "rebuild from scratch" | `pre-commit clean` — read `references/clean.md` | | "hooks aren't running", "hook never fires", "why did a hook fail", a hook failure whose cause is unclear | Diagnose — read `references/failure-patterns.md` | +If the intent is ambiguous, default to `pre-commit run --all-files` — do not stop to ask, and do +not fall through to a narrower row on a guess. + ## Run Default to `pre-commit run --all-files`; never silently narrow to staged files. Run `pre-commit run` (staged only) or `pre-commit run ` (one named hook) when the user asks for it. diff --git a/plugins/git/skills/git-branches/SKILL.md b/plugins/git/skills/git-branches/SKILL.md index 7a2e715..ca98aaf 100644 --- a/plugins/git/skills/git-branches/SKILL.md +++ b/plugins/git/skills/git-branches/SKILL.md @@ -20,7 +20,7 @@ metadata: ## Gotchas - **Uncommitted changes abort a switch.** `git switch` refuses rather than clobbering conflicting local edits. Offer to stash and retry — forcing the checkout past it is how work disappears. -- **A branch and a tag can carry the same name.** Prefer `git switch` over `git checkout`, and where a command accepts either ref, disambiguate with `refs/heads/` or `refs/tags/`. +- **A branch and a tag can carry the same name.** Detect it before acting — `git branch --list ` and `git tag --list `; output from both means the name is ambiguous. Prefer `git switch` over `git checkout`, and where a command accepts either ref, disambiguate with `refs/heads/` or `refs/tags/`. - **`main` and `master` are a refusal, not a gate.** Force-pushing, force-deleting, or renaming them is rejected even when the caller passes `confirm: true` — no flag makes the remote's history recoverable. Offer a new branch instead. ## Step 1 — Determine the branching pattern diff --git a/plugins/git/skills/git-commits/SKILL.md b/plugins/git/skills/git-commits/SKILL.md index 4cc71c2..3b9683c 100644 --- a/plugins/git/skills/git-commits/SKILL.md +++ b/plugins/git/skills/git-commits/SKILL.md @@ -57,8 +57,17 @@ For an agent caller, return: "semver_impact": "MAJOR|MINOR|PATCH|none", "breaking_change": false, "confirmation_required": false, - "details": { "type": "feat", "scope": "api", "description": "add user authentication" } + "details": { + "type": "feat", + "scope": "api", + "description": "add user authentication", + "body": "optional body text, or null", + "footers": ["Fixes: #123", "Refs: #456", "Co-authored-by: Bob "] + } } ``` +`details.footers` is an array of the resolved trailer lines, empty when there are none — never a +single joined string, and never omitted. Downstream agents index it. + For a human caller, show the same fields as a prose preview with a confirmation prompt. diff --git a/plugins/git/skills/git-history/SKILL.md b/plugins/git/skills/git-history/SKILL.md index a4ab045..bfb1fa9 100644 --- a/plugins/git/skills/git-history/SKILL.md +++ b/plugins/git/skills/git-history/SKILL.md @@ -2,10 +2,10 @@ name: git-history description: > - Use when investigating git history — querying logs, tracing when a change - landed, bisecting the commit that broke something, or locating one to - revert or backport. Not authoring or rebasing commits -> `git-commits`. - Not history on a Gitea server -> `gitea-branches`. + Use when investigating git history — pickaxe (`-S`/`-G`) or `-L` line-range log + queries, tracing when a change landed, bisecting what broke something, or + locating a commit to revert or backport. Not authoring or rebasing commits -> + `git-commits`. Not a Gitea server's history -> `gitea-branches`. metadata: category: git diff --git a/plugins/git/skills/git-remotes/SKILL.md b/plugins/git/skills/git-remotes/SKILL.md index 3cb6a01..5f457c1 100644 --- a/plugins/git/skills/git-remotes/SKILL.md +++ b/plugins/git/skills/git-remotes/SKILL.md @@ -6,6 +6,7 @@ description: > remote, even when the user does not name it. Not local commits -> `git-commits`. Not local branches -> `git-branches`. + Not log or bisect queries -> `git-history`. Not submodule pointers -> `git-submodules`. metadata: diff --git a/plugins/git/skills/git-submodules/README.md b/plugins/git/skills/git-submodules/README.md index 06aa066..4b1d2b9 100644 --- a/plugins/git/skills/git-submodules/README.md +++ b/plugins/git/skills/git-submodules/README.md @@ -29,7 +29,7 @@ conflicts, and a recovery `next_step` when applicable). |------|---------| | `SKILL.md` | Skill instructions for agents — gotchas, shared working rules, and the task dispatch table | | `references/README.md` | Describes contents of references/ | -| `references/setup-and-update.md` | Loaded when cloning a superproject, adding a submodule, or initializing, updating, or re-pinning one — includes the full `add` and `update` flag tables and the pinning workflows | +| `references/setup-and-update.md` | Loaded when cloning a superproject, adding a submodule, initializing, updating, or re-pinning one, or running a command across all of them — includes the full `add` and `update` flag tables, the pinning workflows, and the `foreach` shell-variable table | | `references/urls-and-config.md` | Loaded when changing where a submodule points or how it is configured — `.gitmodules` vs `.git/config` anatomy, both key tables, `sync`/`set-url`/`set-branch`, local mirror overrides, relative URLs, the custom-`update` security gate, and `absorbgitdirs` | | `references/removal.md` | Loaded when removing or deinitializing a submodule — why `deinit` is not removal, and the four-step removal sequence | | `references/sources.md` | Research sources and provenance | diff --git a/plugins/git/skills/git-submodules/SKILL.md b/plugins/git/skills/git-submodules/SKILL.md index e274475..297f6a2 100644 --- a/plugins/git/skills/git-submodules/SKILL.md +++ b/plugins/git/skills/git-submodules/SKILL.md @@ -34,7 +34,9 @@ them pins a state nobody else can reproduce. To run one command across every submodule: `rtk git submodule foreach --recursive ''`. Inside ``, Git sets `$name`, `$sm_path`, `$displaypath`, `$sha1` and `$toplevel`; append `|| :` to -continue past a failure instead of aborting the traversal. +continue past a failure instead of aborting the traversal. `$sm_path` and `$displaypath` name the +same directory from different vantage points — if which one you want is not obvious, read the +variable table in `references/setup-and-update.md` before writing the command. ## Dispatch @@ -42,7 +44,7 @@ Read only the row that matches the request. | Task | Reference | |---|---| -| Clone a superproject with submodules, or add, initialize, update or re-pin one | `references/setup-and-update.md` | +| Clone a superproject with submodules; add, initialize, update or re-pin one; run a command across all of them with `foreach` | `references/setup-and-update.md` | | Change where a submodule points — `sync`, `set-url`, `set-branch`, a local mirror override, `absorbgitdirs`, or any `.gitmodules` / `.git/config` key | `references/urls-and-config.md` | | Remove a submodule, or `deinit` one without removing it | `references/removal.md` | diff --git a/plugins/git/skills/git-submodules/references/README.md b/plugins/git/skills/git-submodules/references/README.md index 19b9784..0df0d93 100644 --- a/plugins/git/skills/git-submodules/references/README.md +++ b/plugins/git/skills/git-submodules/references/README.md @@ -10,8 +10,9 @@ One file per task branch in SKILL.md's dispatch table. Load only the one that ma ## setup-and-update.md Cloning a superproject that has submodules, adding a dependency as a submodule, initializing -without cloning, and updating or re-pinning. Carries the `add` and `update` flag tables and the -keep-pinned and move-the-pin-forward workflows. +without cloning, updating or re-pinning, and running one command across every submodule. Carries +the `add` and `update` flag tables, the keep-pinned and move-the-pin-forward workflows, and the +`foreach` shell-variable table (`$name`, `$sm_path`, `$displaypath`, `$sha1`, `$toplevel`). ## urls-and-config.md diff --git a/plugins/git/skills/git-submodules/references/removal.md b/plugins/git/skills/git-submodules/references/removal.md index 4bee62e..0b7d331 100644 --- a/plugins/git/skills/git-submodules/references/removal.md +++ b/plugins/git/skills/git-submodules/references/removal.md @@ -11,7 +11,7 @@ Both operations are destructive. Confirm with the user before executing either. ## `deinit` is not removal ```bash -git submodule deinit # --all for every submodule, -f if locally modified +rtk git submodule deinit # --all for every submodule, -f if locally modified ``` `deinit` clears the submodule's section from `.git/config` and empties its working tree. The @@ -22,11 +22,11 @@ or to reset a broken checkout, not to delete a dependency. ## Full removal, in order ```bash -git submodule deinit -f # unregister from .git/config -git rm # drop the .gitmodules entry and the gitlink from the index -rm -rf .git/modules// # stale git dir: not tracked, not cleaned up by git -git commit -m "chore: remove submodule" +rtk git submodule deinit -f # unregister from .git/config +rtk git rm # drop the .gitmodules entry and the gitlink from the index +rm -rf .git/modules// # stale git dir: not tracked, not cleaned up by git +rtk git commit -m "chore: remove submodule" ``` -The third step is the one that gets skipped. `.git/modules//` survives `git rm`, and while it +The third step is the one that gets skipped. `.git/modules//` survives `rtk git rm`, and while it is present Git refuses to add a submodule at the same path again. diff --git a/plugins/git/skills/git-submodules/references/setup-and-update.md b/plugins/git/skills/git-submodules/references/setup-and-update.md index e7bae51..dfb9c75 100644 --- a/plugins/git/skills/git-submodules/references/setup-and-update.md +++ b/plugins/git/skills/git-submodules/references/setup-and-update.md @@ -9,16 +9,16 @@ source_keys: ## Clone a superproject that already has submodules ```bash -git clone --recurse-submodules # Git 2.13+, one step +rtk git clone --recurse-submodules # Git 2.13+, one step # or, against an existing clone -git submodule update --init --recursive +rtk git submodule update --init --recursive ``` ## Add a dependency as a submodule ```bash -git submodule add -git commit -m "chore: add as submodule" +rtk git submodule add +rtk git commit -m "chore: add as submodule" ``` `add` stages a `.gitmodules` entry and a gitlink — the commit is still required. Flags: @@ -32,14 +32,14 @@ git commit -m "chore: add as submodule" ## Initialize without cloning -`git submodule init [...]` copies submodule URLs from `.gitmodules` into `.git/config` and +`rtk git submodule init [...]` copies submodule URLs from `.gitmodules` into `.git/config` and does nothing else. This is the point at which a local URL override can be edited before any fetch happens. If a local mirror override is wanted, read `references/urls-and-config.md` before running `update`. Use `update --init` to run both steps at once. ## Update -`git submodule update --init --recursive` is the common case: it clones what is missing and checks +`rtk git submodule update --init --recursive` is the common case: it clones what is missing and checks out the commit the superproject recorded, in detached HEAD. | Flag | Meaning | @@ -59,16 +59,38 @@ out the commit the superproject recorded, in detached HEAD. ## Keep submodules pinned to the recorded commit ```bash -git submodule update --recursive # after every git pull -git config submodule.recurse true # or do it automatically on pull/push/checkout +rtk git submodule update --recursive # after every rtk git pull +rtk git config submodule.recurse true # or do it automatically on pull/push/checkout ``` ## Move the pin forward to the tracked branch tip ```bash -git submodule update --remote --merge --recursive -git commit -am "chore: update submodules to latest" +rtk git submodule update --remote --merge --recursive +rtk git commit -am "chore: update submodules to latest" ``` `--remote` requires `submodule..branch`; without it Git falls back to the remote's default branch. Commit the superproject afterwards or the new pin is lost on the next `update`. + +## Run one command across every submodule + +```bash +rtk git submodule foreach --recursive '' +rtk git submodule foreach 'git pull origin main || :' # || : continues past a failure +``` + +`` runs inside each submodule's own working tree, so the git calls in it are the +submodule's own — that is the one place a bare `git` is correct. Append `|| :` to keep the +traversal going instead of aborting at the first failure. + +Git exports five shell variables into ``. `$sm_path` and `$displaypath` name the same +directory from different vantage points and are not interchangeable: + +| Variable | Meaning | +|---|---| +| `$name` | Logical submodule name (the `.gitmodules` section name, which need not match the path) | +| `$sm_path` | Path relative to the superproject root | +| `$displaypath` | Path relative to the current working directory | +| `$sha1` | Commit SHA the superproject has recorded for this submodule | +| `$toplevel` | Absolute path of the superproject's root | diff --git a/plugins/git/skills/git-submodules/references/urls-and-config.md b/plugins/git/skills/git-submodules/references/urls-and-config.md index 5d59691..596724b 100644 --- a/plugins/git/skills/git-submodules/references/urls-and-config.md +++ b/plugins/git/skills/git-submodules/references/urls-and-config.md @@ -10,7 +10,7 @@ source_keys: - **`.gitmodules`** — version-controlled, shared with collaborators. Defines each submodule's logical name, path, and canonical URL. -- **`.git/config`** — local only, populated by `git submodule init`. Local URL overrides live here +- **`.git/config`** — local only, populated by `rtk git submodule init`. Local URL overrides live here and never propagate to another clone. The submodule's own `.git` directory lives at `.git/modules//` in the superproject and is @@ -38,9 +38,9 @@ linked to the submodule's working tree by a `.git` pointer file. ## Rebind a URL or branch ```bash -git submodule sync --recursive # push .gitmodules URLs into .git/config -git submodule set-url # change the canonical URL -git submodule set-branch -b # set the branch used by update --remote +rtk git submodule sync --recursive # push .gitmodules URLs into .git/config +rtk git submodule set-url # change the canonical URL +rtk git submodule set-branch -b # set the branch used by update --remote ``` Run `sync` after an upstream rename: existing clones keep the stale URL in `.git/config` until @@ -49,9 +49,9 @@ they do. ## Override a URL locally (private mirror) ```bash -git submodule init +rtk git submodule init # edit .git/config: submodule..url = -git submodule update +rtk git submodule update ``` Local-only, invisible to collaborators, and overwritten by the next `sync`. @@ -65,15 +65,15 @@ everywhere else. ## Custom `update` commands are security-gated A `.gitmodules` entry of `update = !some-command` is never copied into `.git/config` by -`git submodule init`. That is deliberate: it stops a hostile clone from silently executing +`rtk git submodule init`. That is deliberate: it stops a hostile clone from silently executing arbitrary code. Setting it locally in `.git/config` is the only way to enable it. ## Relocate an embedded `.git` directory ```bash -git submodule absorbgitdirs [...] +rtk git submodule absorbgitdirs [...] ``` Moves a submodule's own `.git` directory into `.git/modules//` and leaves a `.git` pointer file behind. Needed when a nested repository was created or copied in without going through -`git submodule add`. +`rtk git submodule add`. diff --git a/plugins/git/skills/git-workflow/README.md b/plugins/git/skills/git-workflow/README.md index 607924f..10659fd 100644 --- a/plugins/git/skills/git-workflow/README.md +++ b/plugins/git/skills/git-workflow/README.md @@ -4,7 +4,7 @@ Human-friendly interface for interactive git workflows with conversational promp ## What it does -This skill wraps the `git-orchestrate` agent to provide an interactive, educational interface for humans performing git workflows. It handles commits, branch management, history inspection, submodules, worktrees, and remotes. The skill parses user intent, gathers session context, invokes the orchestrator, and presents results in plain language with inline help, progress updates, and explanations of what's happening. It enforces confirmation gates for destructive operations (force-push, branch deletion, rebasing with history loss, force-checkout) and provides best-practices guidance throughout. The org's non-negotiable git rules live in `references/hard-rules.md` and are loaded only when a request could conflict with one. +This skill wraps the `git-orchestrate` agent to provide an interactive, educational interface for humans performing git workflows. It is the router for the six local-git domain skills — `git-commits`, `git-branches`, `git-history`, `git-remotes`, `git-submodules` and `git-worktrees` — and `SKILL.md` carries a table mapping each of them to the requests it owns, so an ambiguous request resolves to exactly one domain before anything runs. The skill parses user intent, gathers session context, invokes the orchestrator, and presents results in plain language with inline help, progress updates, and explanations of what's happening. It enforces confirmation gates for destructive operations (force-push, branch deletion, rebasing with history loss, force-checkout) and provides best-practices guidance throughout. The org's non-negotiable git rules live in `references/hard-rules.md` and are loaded only when a request could conflict with one. ## Usage @@ -18,7 +18,7 @@ Describe your git workflow: commit, create a branch, rebase, inspect history, ma | File | Purpose | |------|---------| -| `SKILL.md` | Skill instructions for agents | +| `SKILL.md` | Skill instructions for agents — the six-domain routing table, the workflow steps, and the interaction style | | `README.md` | This file | | `references/hard-rules.md` | The org's non-negotiable git rules; read when a request creates, amends, or rewrites a commit, pushes, or touches hooks, config, or credentials | | `references/README.md` | Describes the references directory contents | diff --git a/plugins/git/skills/git-workflow/SKILL.md b/plugins/git/skills/git-workflow/SKILL.md index e7e5034..40422fb 100644 --- a/plugins/git/skills/git-workflow/SKILL.md +++ b/plugins/git/skills/git-workflow/SKILL.md @@ -3,8 +3,9 @@ name: git-workflow description: > Use when a human's local git request is general or ambiguous — it routes to the owning - domain skill. Not an unambiguous commit -> `git-commits`. Not an unambiguous branch -> - `git-branches`. Not an agent caller -> `git-orchestrate`. Not Gitea -> `gitea-workflow`. + domain skill: `git-commits`, `git-branches`, `git-history`, `git-remotes`, `git-submodules` + or `git-worktrees`. An unambiguous request goes straight to its domain skill instead. Not an + agent caller -> `git-orchestrate`. Not Gitea -> `gitea-workflow`. metadata: category: git @@ -25,10 +26,27 @@ metadata: mandated org wrapper, not a style preference. Submodule-specific commands run from inside the submodule's own directory instead. +## Domains + +Every request resolves to exactly one of these six. An unambiguous one should have gone straight +to the domain skill; this skill exists for the ones that did not. + +| The request is about | Domain | +|---|---| +| Writing, amending, squashing, or cherry-picking a commit, and its message | `git-commits` | +| Creating, switching, deleting, renaming, tracking, or merging a local branch | `git-branches` | +| When a change landed, which commit broke something, what to revert or backport | `git-history` | +| Anything touching a remote — remote config, fetch, push, pull — even unnamed | `git-remotes` | +| A nested repository pinned inside this one by a recorded commit | `git-submodules` | +| Several branches checked out at once, in separate directories, without stashing | `git-worktrees` | + +`git-orchestrate` executes whatever this resolves to (step 5); the table only decides which domain +owns the request. + ## Workflow -1. **Parse intent** — extract the operation (commit, create branch, rebase, inspect history, …) - and any options the user named. +1. **Parse intent** — extract the operation and, from the table above, the domain that owns it, + plus any options the user named. 2. **Check the hard rules** — if the request creates, amends, or rewrites a commit, pushes, or touches hooks, config, or credentials, read `references/hard-rules.md`. Raise the relevant rule before acting, not after. diff --git a/plugins/git/skills/git-worktrees/SKILL.md b/plugins/git/skills/git-worktrees/SKILL.md index f89dcfe..15a89fc 100644 --- a/plugins/git/skills/git-worktrees/SKILL.md +++ b/plugins/git/skills/git-worktrees/SKILL.md @@ -18,7 +18,7 @@ metadata: - **A branch can be checked out in only one worktree at a time.** `git worktree add` on an already-checked-out branch fails; `--force` is the only override, so use it only deliberately. - **Never `rm -rf` a worktree directory.** That strands metadata in `$GIT_DIR/worktrees/`. Use `git worktree remove`, or `git worktree prune` afterwards. - **Submodules break worktree support.** A worktree containing submodules cannot be moved at all, and needs `--force` to remove. -- **`extensions.worktreeConfig = true` is a one-way door.** It costs compatibility with older Git and forces `core.bare`/`core.worktree` into `config.worktree`. Leave it off unless per-worktree config is needed. +- **`extensions.worktreeConfig = true` is a one-way door.** Without it, `git config --worktree` errors; with it, that flag writes to the worktree's own `config.worktree` file, and `core.bare`/`core.worktree` are forced there too. It also breaks older Git. Leave it off unless per-worktree config is needed. ## Step 1 — Dispatch diff --git a/plugins/git/skills/pc-run/SKILL.md b/plugins/git/skills/pc-run/SKILL.md index bc29166..82ebc7a 100644 --- a/plugins/git/skills/pc-run/SKILL.md +++ b/plugins/git/skills/pc-run/SKILL.md @@ -47,6 +47,9 @@ Determine intent from the user's request, then execute the matching operation. W | "clean", "wipe cache", "rebuild from scratch" | `pre-commit clean` — read `references/clean.md` | | "hooks aren't running", "hook never fires", "why did a hook fail", a hook failure whose cause is unclear | Diagnose — read `references/failure-patterns.md` | +If the intent is ambiguous, default to `pre-commit run --all-files` — do not stop to ask, and do +not fall through to a narrower row on a guess. + ## Run Default to `pre-commit run --all-files`; never silently narrow to staged files. Run `pre-commit run` (staged only) or `pre-commit run ` (one named hook) when the user asks for it.