Repository navigation
Description
Problem
Complex shell is frozen by operator direction. Replace its behavior with tested Go, delete the shell implementation being replaced, and retain a thin exec shim only where an existing executable path must remain.
Baseline: origin/main at 226a50c0b33c0b2733b2886dec2d72d711e362de, confirmed against git ls-remote origin refs/heads/main. The existing checkout matched that commit. Inspection was read-only with GH_CONFIG_DIR=~/.config/gh-agent; no 1Password access or publication occurred.
The inventory contains 100 maintained shell files and 14,183 physical lines, including comments and blank lines. It excludes generated skill copies, Bats files, test fixtures, vendored dependencies, and inline task bodies. Two coupled Python helpers are listed separately because leaving them behind would leave the gate and merge implementation fragmented.
Existing Go implementations provide a starting point:
agentrepo checks evaluate/internal/checks: saved check evaluation.agentrepo review run/internal/review: reviewer deadlines and process cleanup.agentrepo config/internal/config: machine and repository configuration.commit-lint/internal/commitlint: message shape, trailers, identity policy, and outgoing commit checks.gh-post/internal/ghpost: scanned GitHub content publication.guard-markdown/internal/markdownandinternal/hookio: Markdown checks and Write/Edit hook handling.ssh-sign/internal/signing: signing infrastructure, rather than the complete unattended commit verification workflow.
agenthooks, agentcontext, and agentstore currently expose version commands only; they are command skeletons, not completed shell replacements.
Acceptance criteria
- AC1: Every inventoried complex shell implementation is replaced by Go tests and Go code. Replaced algorithms are deleted; required executable paths contain only forwarding shims.
- AC2: Each migration ports the relevant Bats behavior into Go tests and retains sufficient integration coverage to verify arguments, streams, exit statuses, and generated entry points.
- AC3: Gates and the merge path migrate first, hooks second, and remaining workflows and tooling third.
- AC4: Authority remains machine-selected. Confirmation precedence, exact-head approvals, owner overrides, trusted review policy, stamp bindings, signing checks, and evidence retention remain covered by tests.
- AC5: Empty or unreadable checks cannot become success. Protected writes remain pinned to reviewed state, and uncertain writes are never retried automatically.
- AC6: Canonical sources generate both harness packages and their deployments without hand edits. Removed helpers disappear from generated output.
- AC7: Replacement binaries are available before matching skill deployments require their commands. No new shell fallback duplicates migrated Go behavior.
- AC8: Required Go, integration, generation, lint, and packaging checks pass, and the replacement enforcement code is covered by golden-file protection (build(agents): protect replacement Go enforcement paths #753) before operational rollout.
Scope and non-goals
Inventory risk: H affects enforcement, authority, Git state, publication, cleanup, or sensitive scanning; M affects reports, generation, or tool execution; L is an existing forwarding shim. G marks paths matched by the current golden and owner-path patterns.
Counterparts below are partial unless explicitly stated otherwise. — means no implemented Go counterpart was found. hookio supplies hook infrastructure, not the listed guard’s rules.
| Path | Lines | Risk | Existing Go counterpart |
|---|---|---|---|
packages/agents/source/lib/lib.sh |
827 | H/G | agentrepo config, agentrepo review run, commit-lint, gh-post |
packages/agents/source/lib/agent.sh |
117 | H/G | agentrepo config repository |
packages/agents/source/lib/signing.sh |
91 | H | ssh-sign; verification workflow remains shell |
packages/agents/source/lib/worktree-ready.sh |
42 | H | — |
packages/agents/source/skills/agent-commit/shared/scripts/commit.sh |
6 | L | Shell forwarding shim |
packages/agents/source/skills/agent-commit/shared/scripts/preflight.sh |
6 | L | Shell forwarding shim |
packages/agents/source/skills/agent-commit/shared/scripts/review.sh |
6 | L | Shell forwarding shim |
packages/agents/source/skills/agent-pr/shared/scripts/check.sh |
5 | L | Shell forwarding shim |
packages/agents/source/skills/agent-pr/shared/scripts/preflight.sh |
5 | L | Shell forwarding shim |
packages/agents/source/skills/agent-pr/shared/scripts/publish.sh |
5 | L | Shell forwarding shim |
packages/agents/source/skills/agent-pr/shared/scripts/review.sh |
5 | L | Shell forwarding shim |
packages/agents/source/skills/agent-merge-pr/shared/scripts/lint-squash-msg.sh |
5 | L | Shell forwarding shim |
packages/agents/source/skills/agent-merge-pr/shared/scripts/merge.sh |
11 | H | Shell forwarding plus argument refusal |
packages/agents/source/skills/agent-merge-pr/shared/scripts/preflight.sh |
5 | L | Shell forwarding shim |
packages/agents/source/skills/agent-merge-pr/shared/scripts/review.sh |
5 | L | Shell forwarding shim |
packages/agents/source/skills/agent-merge-pr/shared/scripts/squash-message.sh |
5 | L | Shell forwarding shim |
packages/agents/source/skills/commit/shared/scripts/commit.sh |
285 | H | commit-lint, ssh-sign |
packages/agents/source/skills/commit/shared/scripts/preflight.sh |
337 | H | commit-lint, configuration readers |
packages/agents/source/skills/commit/shared/scripts/review.sh |
126 | H | Reviewer process control only |
packages/agents/source/skills/commit/claude/scripts/guard-git.sh |
186 | H/G | — |
packages/agents/source/skills/pr/shared/scripts/check.sh |
12 | H | Configuration readers |
packages/agents/source/skills/pr/shared/scripts/create-pr.sh |
189 | H | gh-post, configuration readers |
packages/agents/source/skills/pr/shared/scripts/description.sh |
109 | H | — |
packages/agents/source/skills/pr/shared/scripts/pr-agent.sh |
99 | H | Configuration readers |
packages/agents/source/skills/pr/shared/scripts/pr-checks.sh |
54 | H | — |
packages/agents/source/skills/pr/shared/scripts/preflight.sh |
396 | H | Configuration readers |
packages/agents/source/skills/pr/shared/scripts/properties.sh |
64 | H | — |
packages/agents/source/skills/pr/shared/scripts/publish.sh |
220 | H | gh-post |
packages/agents/source/skills/pr/shared/scripts/review.sh |
133 | H | Reviewer process control only |
packages/agents/source/skills/pr/shared/scripts/scaffold-description.sh |
90 | M | — |
packages/agents/source/skills/pr/shared/scripts/validate-description.sh |
506 | H | — |
packages/agents/source/skills/pr/claude/scripts/guard-gh.sh |
77 | H/G | — |
packages/agents/source/skills/merge-pr/shared/scripts/lint-squash-msg.sh |
37 | H | commit-lint covers part of downstream lint |
packages/agents/source/skills/merge-pr/shared/scripts/merge-agent.sh |
230 | H/G | internal/checks, configuration readers, gh-post |
packages/agents/source/skills/merge-pr/shared/scripts/populate-description.sh |
108 | M | — |
packages/agents/source/skills/merge-pr/shared/scripts/preflight.sh |
224 | H | internal/checks available; legacy judge remains |
packages/agents/source/skills/merge-pr/shared/scripts/pull-request.sh |
165 | H | internal/checks; separate shell judge remains |
packages/agents/source/skills/merge-pr/shared/scripts/review.sh |
154 | H | Reviewer process control only |
packages/agents/source/skills/merge-pr/shared/scripts/squash-merge.sh |
376 | H | commit-lint, internal/checks, gh-post |
packages/agents/source/skills/merge-pr/shared/scripts/squash-message.sh |
278 | H | commit-lint sign-off checks |
packages/agents/source/skills/merge-pr/claude/scripts/guard-merge.sh |
75 | H/G | — |
packages/agents/source/skills/rebase/shared/scripts/continue-rebase.sh |
169 | H | — |
packages/agents/source/skills/rebase/shared/scripts/marker-scan.sh |
84 | H | — |
packages/agents/source/skills/rebase/shared/scripts/preflight.sh |
340 | H | — |
packages/agents/source/skills/rebase/shared/scripts/rebase-status.sh |
157 | M | — |
packages/agents/source/skills/rebase/shared/scripts/start-rebase.sh |
165 | H | — |
packages/agents/source/skills/rebase/shared/scripts/verify-rebase.sh |
269 | H | — |
packages/agents/source/skills/rebase/claude/scripts/guard-rebase.sh |
194 | H/G | — |
packages/agents/source/skills/resolve-rebase-conflicts/shared/scripts/classify-conflicts.sh |
193 | H | — |
packages/agents/source/skills/resolve-rebase-conflicts/shared/scripts/resolve-union.sh |
184 | H | — |
packages/agents/source/skills/resolve-rebase-conflicts/shared/scripts/take-side.sh |
115 | H | — |
packages/agents/source/skills/resolve-rebase-conflicts/claude/scripts/guard-resolve.sh |
161 | H/G | — |
packages/agents/source/skills/watch-pr/shared/scripts/watch-checks.sh |
187 | H | internal/checks covers related rollup semantics, not watcher protocol |
packages/agents/source/skills/watch-pr/claude/scripts/guard-watch.sh |
65 | H/G | — |
packages/agents/source/skills/fix-pr/shared/scripts/diagnose.sh |
162 | M | — |
packages/agents/source/skills/fix-pr/shared/scripts/populate-description.sh |
108 | M | — |
packages/agents/source/skills/fix-pr/claude/scripts/guard-fix.sh |
79 | H/G | — |
packages/agents/source/skills/fix-prose/shared/scripts/check-suppressions.sh |
393 | H | — |
packages/agents/source/skills/fix-prose/shared/scripts/preflight.sh |
129 | H | — |
packages/agents/source/skills/fix-prose/claude/scripts/arm-guard.sh |
74 | H | — |
packages/agents/source/skills/fix-prose/claude/scripts/guard-target.sh |
130 | H/G | hookio infrastructure only |
packages/agents/source/skills/fix-prose/claude/scripts/release-once.sh |
73 | H | — |
packages/agents/source/skills/analyze-session/shared/scripts/new-retro.sh |
159 | M | — |
packages/agents/source/skills/analyze-session/shared/scripts/preflight.sh |
162 | M | Configuration readers |
packages/agents/source/skills/write-pr-description/shared/scripts/context.sh |
172 | M | — |
packages/agents/source/skills/write-prose-fix/shared/scripts/context.sh |
150 | M | — |
scripts/clear-commit-agentmsg.sh |
27 | H | — |
scripts/cspell-commit-msg.sh |
52 | H | — |
scripts/vale-commit-msg.sh |
80 | H | — |
.devtools/scripts/apm-sync.sh |
22 | M | — |
.devtools/scripts/check-leaks.sh |
573 | H | internal/ghpost.Scan overlaps text scanning only |
.devtools/scripts/filter-govulncheck-sarif.sh |
8 | M | — |
.devtools/scripts/fuzz.sh |
32 | M | — |
.devtools/scripts/go-ldflags.sh |
31 | M | — |
.devtools/scripts/gomodscan.sh |
62 | H | — |
.devtools/scripts/install-pre-push.sh |
119 | H | commit-lint --pre-push; installer and stdin handling remain |
.devtools/scripts/leak-skip.sh |
16 | H | — |
.devtools/scripts/lint-commit-msg.sh |
80 | H | internal/config, commit-lint; preview orchestration remains |
.devtools/scripts/lint-draft.sh |
120 | H | — |
.devtools/scripts/lint-types.sh |
40 | M | — |
.devtools/scripts/preapproval.sh |
48 | H | — |
.devtools/scripts/rust.sh |
97 | M | — |
tools/check-script-hygiene.sh |
172 | H | — |
tools/check-versions.sh |
158 | H | — |
tools/fuzz.sh |
4 | L | Shell forwarding shim |
tools/generate-skills.sh |
172 | H | — |
tools/go-ldflags.sh |
4 | L | Shell forwarding shim |
tools/lint-draft.sh |
120 | H | —; duplicate of deployed adapter |
tools/lint-types.sh |
4 | L | Shell forwarding shim |
tools/mise-bootstrap |
401 | H | — |
tools/release-dispatch.sh |
82 | H | — |
tools/release-readiness.sh |
183 | H | — |
tools/release-verify.sh |
237 | H | — |
tools/skill-limits.sh |
154 | H | — |
tools/skill-tokens.sh |
284 | M | — |
tools/test-guards.sh |
242 | M | Go hook tests provide a pattern, not equivalent coverage |
.claude/skills/release/scripts/guard-release.sh |
190 | H/G | — |
.claude/skills/release/scripts/release-clone.sh |
246 | H | — |
.claude/skills/release/scripts/watch-release.sh |
192 | M | — |
.claude/skills/review-release-version/scripts/context.sh |
181 | M | — |
Coupled non-shell implementations:
| Path | Lines | Risk | Existing Go counterpart |
|---|---|---|---|
packages/agents/source/lib/gates.py |
117 | H | — |
packages/agents/source/skills/merge-pr/shared/scripts/merge-policy.py |
551 | H/G | internal/checks covers check judgment only |
Out of scope: replacing Git, GitHub CLI, mise, prek, external linters, or tokenizers; changing repository policy as a side effect; rewriting unrelated Python analysis tools; changing vendored upstream code.
Published paths under scripts/ retain their filenames and calling conventions. Their replacement shims execute Go without maintaining a second implementation.
Approach
Use small migrations that remove complete leaf algorithms before retiring their containing libraries. The first two Features below modify disjoint maintained files and can be built in parallel. Remaining complex shell stays frozen during that transition.
Ordered Features:
- Port strict review-verdict parsing to Go — S. Remove
dt_verdictand port its Bats cases. - Port exact-head merge approval selection to Go — S. Remove
ma_approvedand port reviewer/owner approval cases. Build alongside Feature 1. - Replace the remaining shell check judge. Resolve and test compatibility differences before connecting attended merge reporting to
internal/checks. - Move gate execution and pass caching to Go. Replace
gates.py; preserve fingerprints, forced reruns, logs, invalidation, and clean-tree requirements. - Move shared gate readiness, review state, and confirmation into Go. Retire readiness shell, verdict/stamp orchestration, persistent bounds, and configuration fallbacks after binary rollout.
- Move pinned merge readers and policy inspection into Go. Cover review pagination, complete local diffs, required checks, base rulesets, APM ownership, and owner-path reporting.
- Move squash briefing and lint orchestration into Go. Preserve issue references, sign-off policy, attribution, and dictionaries read from the pinned PR head.
- Move merge execution and recovery into Go. Preserve live rechecks, dependent PR retargeting, exact-head writes, remote verification, reporting, and conservative cleanup. Delete the remaining merge shell and coupled policy helper.
- Replace Bash workflow guards with Go hooks. Preserve scoped allowlists, activation state, refusal messages, and exit-2 behavior.
- Replace public commit hooks and pre-push installation with Go. Preserve published paths, stdin replay, stages, and external linter invocation.
- Replace prose guard state and suppression checks with Go. Preserve canonical paths, single-edit release, dictionary snapshots, and refusal boundaries.
- Replace remaining commit and PR workflows with Go. Cover signing verification, preview lint, draft parsing, validation, properties, leased pushes, publication, and reports.
- Replace rebase and conflict-resolution shell with Go. Preserve pinned Git settings, marker exceptions, classifications, union verification, and recovery evidence.
- Replace watchers, diagnosis, and context gathering with Go. Preserve event streams, time bounds, error statuses, and worktree isolation.
- Replace remaining tooling and deployed adapters with Go. Include leak scanning, generation, hygiene, version checks, lint adapters, and language-task helpers.
- Replace release and bootstrap orchestration with Go. Preserve release authority and establish a distribution path that works before mise provisions a Go toolchain.
Each larger Feature is divided into XS/S implementation PRs before coding.
Generation is part of each migration. A normal shared skill script has one source and four tracked outputs, across the two packages and two local deployments. lib.sh is broader: one source and 20 tracked outputs across five skill families. Edit canonical sources, then run generation, token measurement, and deployment in the documented order. Never repair generated copies individually.
The first two Features change different generated script paths. Their shared merge-pr token metadata may overlap; regenerate that metadata from the combined tree instead of merging counts by hand.
Dependencies
- Existing Go command structure and configuration readers.
- Existing Bats suites as behavioral evidence, including failure and partial-output cases.
- A release/deployment sequence that installs new Go commands before deploying callers.
- One owner-approved edit to the pattern file (build(agents): protect replacement Go enforcement paths #753) that adds the replacement Go enforcement paths to the golden patterns before operational rollout; current shell path patterns do not automatically protect new Go files. Later changes to those paths take the golden-file route, where the required reviewer's exact-head
Loosens: noreview waives the finding and detected loosening or other holds still go to the operator. - An explicit compatibility decision for the legacy merge check judge: its malformed-input, unknown-state, tied-run, and status-context behavior differs from
internal/checks. - A bootstrap distribution decision before replacing
tools/mise-bootstrap.
Size
L epic
Verify plan
For each Feature:
- Port relevant Bats cases into Go tests before removing the implementation.
- Test arguments, output, statuses, malformed input, and subprocess failures using local fixtures and stubs.
- Run targeted Go and Bats suites against binaries built from the branch.
- Regenerate canonical package output, token records, and deployments; run
mise run check-generated-skills. - Run applicable lint, architecture, packaging, and scanner gates.
Before closing the epic, run the full repository checks, Go race tests where applicable, hook regressions, and deployment audits. Recount maintained shell and verify that retained entry points contain only forwarding logic. Perform no real commit, publication, merge, or release as a test.
Risks
The highest risks are changing authorization while translating it, accepting partial subprocess output, stale review bindings, repeating an uncertain write, and deleting valuable work during cleanup.
Go check evaluation is not a drop-in behavioral replacement for the remaining jq judge. That migration needs an explicit tested contract.
Mandatory Go commands introduce rollout dependencies. Generated copies multiply mechanical changes, and shared token metadata requires regeneration after parallel work integrates. Bootstrap replacement also cannot assume the toolchain it currently installs already exists.
Operator authority
A standing rule names the operator: the freeze and migration order are operator direction, and the single pattern-file edit in #753 needs the owner's exact-head review.
Changes to golden/owner-tier paths require the existing owner review process. Unattended merges involving golden files require an exact-head APPROVED review from machine-configured merge_owner; policy changes cannot authorize themselves. The Go replacements are covered by the golden-file route through #753, whose single pattern-file edit needs the owner's exact-head review.
This epic grants no commit, publication, merge, release, identity, or pre-approval authority.
Metadata
Metadata
Assignees
Labels
Type
Fields
Work type
Priority
Projects
- StatusShow more project fieldsBacklog
Activity
67 remaining items
tbhb-agent commentedon Nov 1, 2026
Status:
Done: #1028 merged at merge commit 3416703 after three review rounds (approved at the exact head), closing #950.
Next: reviews as PRs open on green heads; the next #588 children build from fresh main.
Blocked on: none.
tbhb-agent commentedon Nov 1, 2026
Status: PR 1023 reviewed at its new head; the #331 split is filed.
Done
Next
Blocked on: none.
tbhb-agent commentedon Nov 1, 2026
Status:
Done: #1023 merged at merge commit 37f71fd after the redesign lineage (approved at the exact head in round 2), closing #330.
Next: #886 and #1030 publishes, then the #331 children after the base slice merges.
Blocked on: none.
tbhb-agent commentedon Nov 1, 2026
Status: pull request 1033 merged.
Done: PR 1033 (prose check-suppressions state in the Go agentrepo command, fixes #886) squash-merged as d7a42bb after an approving independent review at its exact head fe76797 on the third review round, with all 25 checks green, a verified signature and 799 of 800 code lines. Coverage evidence from a local run of the repository coverage task on that head: file 75%, package 80% and total 85% floors passed, total 92.8%.
Next: slices BASE-1 and BASE-2 of #331 are built and committed or staged locally; the PR 1034 fix round is with the author. Follow-ups filed: #1044 (coverage floors not enforced when the coverage upload fails) and #1045 (per-AC evidence format versus the description review).
Blocked on: nothing from this merge.
tbhb-agent commentedon Nov 1, 2026
Status: pull request 1034 merged.
Done: PR 1034 (set an issue type through gh-post, fixes #1030) squash-merged as 8bcd565 after an approving independent review at its exact head e945fe2 on the second review round, with all 25 checks green, a verified signature and 487 of 800 code lines. #1030 has no parent issue, so it is not a child of #588 and the #588 count is unchanged.
Next: slice BASE-2 of #331 is built and awaits its commit; BASE-1 is next to publish.
Blocked on: nothing from this merge.
tbhb-agent commentedon Nov 1, 2026
Status: PR 1046 (
retro new, the BASE-1 slice of #331) merged.Done
Next
retro preflight) publishes rebased onto this merge and closes Port analyze-session's shell scripts to Python #331.Blocked on
tbhb-agent commentedon Nov 1, 2026
Status: BASE-2 of #331 merged.
Done: pull request 1048 (retro preflight) merged at fef5535 after an approving review at its exact head 14ddddd, green checks, 319 code lines. It was Related to #331, so #331 stays open.
Next: #1031, then #1032, then the activation issue #1002, each as its own pull request. #588 stays at 10 of the open sub-issue total until #331 closes.
Blocked on: none.
tbhb-agent commentedon Nov 1, 2026
Status: six dependency and test-helper pull requests merged.
Done: pull requests 1035, 1037, 1038, 1041 and 1054 and 1040 merged, each at its exact approved head with green checks and a signed head commit. Merge commits: 1035 c3a53a5, 1037 12a0a98, 1038 10bc506, 1041 8fbb75d, 1054 625ccfa, 1040 20a5da4. None touches a protected path.
Next: rebases of the open shell-port pull requests continue under the shell-edit freeze.
Blocked on: none.
feat(shell): add the shell command analyzer
tbhb-agent commentedon Nov 1, 2026
Status: pull request 849 merged.
Done: pull request 849 merged at its exact approved head with green checks and a signed head commit. Merge commit: 8c0efa8. It closes #450, which has no parent here, so the count of finished sub-issues stays at 10 of 49. It touched one workflow line (a tool install), no check added, removed or weakened.
Next: reviews and fix rounds of the open shell-port pull requests continue.
Blocked on: none.
tbhb-agent commentedon Nov 1, 2026
Status:
Done: PR 673 merged as a65bc95 (closes #593): the shell allowlist command in Go, vendor refresh excluded from the size gate by its own rule (720 code / 17 prose). #588 now 10 of 49 sub-issues closed.
Next: 787 (testenv hook-suite runner), then the 1055 Windows fix, 1061, 936.
Blocked on: none.
tbhb-agent commentedon Nov 2, 2026
Status:
Done: PR 1070 merged as 3147b50, closing #595 (shell burn-down report and consumer shipping of shell-allowlist).
Next: remaining #588 children.
Blocked on: none.
tbhb-agent commentedon Nov 2, 2026
Status: Done: PR 1067 merged as b5a2efd, closing #1053 (the merge-owner approval satisfies the required-reviewer check); Next: remaining #588 children; Blocked on: none.