Skip to content

refactor(claude-ops): precompute installed CC version via ! injection - #793

Merged
kyle-sexton merged 3 commits into
mainfrom
refactor/precompute-context-sweep
Jul 21, 2026
Merged

refactor(claude-ops): precompute installed CC version via ! injection#793
kyle-sexton merged 3 commits into
mainfrom
refactor/precompute-context-sweep

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

M2 ! precompute sweep across all plugins' skills. The mandate was to convert deterministic, read-only, render-time-valid context-gathering shell blocks to ! dynamic-context injection (per plugins/playbooks/skills/skill-authoring/reference/precompute-context.md), under-converting and skipping ambiguous cases.

Outcome: exactly one sound conversion repo-wide — claude-ops/changelog. The sweep was deliberately conservative; every other fenced shell block was disqualified.

What changed

  • claude-ops/changelog — version probe converted. The version-awareness step ran claude --version as a body instruction (a per-invocation tool round-trip on every apply/diff). It now injects at load time:

    !`claude --version || echo "(CC version unavailable)"`

    Deterministic, read-only, needed up front, judgement-independent, cheap + stable output. Carries the mandated || echo fallback (Q14). The bash-only 2>/dev/null redirect was dropped so the command and fallback stay valid on both the bash default and the Windows PowerShell fallback host (no shell: frontmatter needed once portable).

  • claude-ops bumped 0.15.3 → 0.15.4 + CHANGELOG entry (rebased above feat(claude-ops): document lane mid-session staleness & restart cadence (#514) #791's 0.15.3, merged forward from origin/main mid-review). Description unchanged → no root-catalog regen.

Why the list is so short

The check-18 precompute detector (skill-quality) emits zero WARNs repo-wide. By construction it fail-closes on bash script.sh (unknown head command) and on 2>/dev/null (its > guard), so a clean git status/git diff preamble — the shape it would flag — simply does not exist in these skills. Every remaining fenced block is in the judgement-call tail the UNDER-CONVERT mandate targets, and the manual pass rejected all of them.

Skipped-candidate ledger

Every non-vendor, non-setup skill with a fenced shell block was manually reviewed. Disqualification reasons:

| Skill(s) | Reason skipped |

|---|---|

| kindle-dedrm/manage | Reverted a prior-session conversion. status.sh spawns 3 powershell.exe subprocesses + a full Calibre Library find (not cheap/bounded, under undocumented ! timeout) and emits a captured_at timestamp + changing book counts (unstable output → CC re-appends full rendered skill each invocation, v2.1.202+). |

| claude-ops/lanes, session-flow/handoff | Mutating (spawns/kills sessions). |

| claude-ops/morning-brief, claude-ops/plugins, repo-fleet-hygiene/audit, skill-quality/check, ai-briefing/generate | The skill's core action/deliverable, not a context preamble; also argument-dependent. |

| claude-ops/observability | Conditional on $1; exec/delegate logic. |

| claude-config/audit-permission-grants | Core action (produces the report), requires jq, not a preamble. |

| claude-config/audit-automation-gaps, testing/plan, context7/lookup, firecrawl/firecrawl | Illustrative templates / Claude-derived args (<tool-command>, HEAD~N, <name>/<question>, URLs). |

| code-tidying/batch-simplify | Conditional mode branch; Claude-derived NORMALIZED_TIME_WINDOW. |

| code-tidying/tidy, docs-hygiene/compress, work-items/decompose, source-control/commit | Mutating (gh pr comment, mktemp/cp, create-item, git commit). |

| planning/draft-goal-condition, work-items/work | Argument-dependent (<LIMIT>, <path>, <id>). |

| repo-hygiene/clean, session-flow/retro, toolchain/check, toolchain/lint, source-control/pull-request, work-items/scan-todos, knowledge/course-digest | Procedural VAR=$(...) assignments consumed by later body steps (single-pass injection can't feed a later step) and/or Claude-derived-argument extraction. |
| knowledge/youtube-digest | Already precomputes — carries ! injection for its toolchain deps (video-digestion/yt-dlp/ffmpeg/ImageMagick) with || echo fallbacks. Its 13 fenced blocks are all Claude-derived-argument node run.mjs <script.js> <url>/<slice-dir> action invocations (many mutating), not context preambles. Pre-existing observation, not touched here: those injections use bash-only 2>/dev/null | head -1 without a shell: declaration — a portability inconsistency for a future pass. |
| playwright/playwright (top-level, non-vendor) | Illustrative quick-start; playwright-cli commands are Claude-derived-argument (<flow>, <url>, element refs like e42 read from a prior snapshot) and kill-all is mutating. |

| */vendor/* (playbooks/boris, playwright/vendor, context7/lookup) | Upstream-synced materializations — hard-excluded (check 8 byte-identity + CLAUDE.md managed-file rule). |

| */setup skills | One-time provisioning, not every-invocation context. |

Verification

  • skill-quality:check changelogPASS, 0 errors. Check 18 is silent on the converted skill (it now injects with !). The one WARN ("no Gotchas surface") is pre-existing and unrelated to this change — out of scope for this precompute-only sweep.

  • origin/main merged forward before work (was 2 behind; fast-forward, no force-push).

  • kindle-dedrm files restored byte-identical to HEAD.

Related

No linked issue. Part of the Skill M program (better precomputed context — ! executions in skill .md). Companion to the M1 authoring-guidance + detector work already shipped in #773 (skill-quality 0.7.0). This PR is item 1 (the one-time sweep over own plugins' skills).

🤖 Generated with Claude Code

The `changelog` skill's version-awareness step previously told Claude to
run `claude --version` as a body instruction — a per-invocation tool
round-trip on every `apply`/`diff`. Convert it to `!` dynamic-context
injection so the probe runs once at load time and its output is inlined
before Claude sees the skill.

The probe qualifies under every precompute criterion: deterministic,
read-only, needed up front, independent of Claude's judgement, and cheap
with stable output. It carries the mandated `|| echo "(CC version
unavailable)"` defensive fallback, and drops the bash-only `2>/dev/null`
redirect so the command and its fallback stay valid on both the bash
default shell and the Windows PowerShell fallback host.

Scope note: this was a repo-wide sweep, but `changelog` is the only sound
conversion. The check-18 precompute detector emits no warnings repo-wide
(it fail-closes on `bash script.sh` and `2>/dev/null`), and the manual
pass over every other fenced shell block found only mutating, argument-
derived, procedural variable-assignment, core-action, or illustrative
blocks — none injectable. An earlier kindle-dedrm `status.sh` conversion
was reverted: it spawns multiple `powershell.exe` subprocesses and emits
a changing timestamp + book counts, failing the cheap/bounded and
stable-output criteria.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01U9zbRxtRuTx1WsQavFc2Gi

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

kyle-sexton and others added 2 commits July 21, 2026 01:14
Resolve claude-ops CHANGELOG conflict with #791 (which claimed 0.15.3):
rebase the changelog precompute entry to 0.15.4 above main's 0.15.3, and
bump plugin.json 0.15.3 -> 0.15.4 accordingly.
Phase 0 step 1 of the `changelog` apply pipeline re-ran
`claude --version 2>/dev/null` inline, duplicating the probe now inlined
at load by the Version-awareness `!` injection and undoing the
round-trip the conversion removed. Point it at the precomputed value
instead, and drop the non-portable `2>/dev/null` redirect.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01U9zbRxtRuTx1WsQavFc2Gi

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 57s —— View job


Security Review — PR #793

  • Gather context
  • Read changed files
  • Analyze for security issues
  • Post findings

Findings

No security issues found.

The three changed files are a plugin version bump (plugin.json), a changelog entry (CHANGELOG.md), and the one meaningful change in SKILL.md. All three are clean.

SKILL.md! injection of claude --version

The converted line (L34):

- Installed CC version: !`claude --version || echo "(CC version unavailable)"`

Checked against the relevant attack surfaces:

  • Command injection / untrusted input: The command is a fully static literal — no variable interpolation, no $ARGUMENTS, no consumer-config values are spliced in. There is no injection surface.
  • Output used unsafely: The version string is injected as read-only AI context for a version comparison decision. It is never interpolated into a subsequent shell command or template. Worst-case adversarial output (e.g., a PATH-hijacked claude binary returning a crafted version string) produces a misleading version warning to the user — a purely informational, non-exploitable outcome.
  • Binary trust: claude --version runs the same trusted CC binary that is already executing the session. No third-party binary or network call is introduced.
  • Cross-platform: Dropping 2>/dev/null and using || echo is correct — 2>/dev/null is bash-only and would silently fail or produce unexpected output on the Windows PowerShell host. The || fallback is portable and the fallback string is static.
  • plugin.json / CHANGELOG.md: Version bump and documentation only. No executable content, no secret material, no permission changes.

@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 40s —— View job


PR Review

  • Read changed files
  • Review SKILL.md changes (the core conversion)
  • Review plugin.json version bump
  • Review CHANGELOG.md entry
  • Post final review findings

Summary

This is a focused, conservative precompute sweep. The one conversion it makes (changelog skill version probe) is sound. Everything else was deliberately left as a body instruction — the skipped-candidate ledger is thorough and well-reasoned. No issues blocking merge; one nit and one minor observation below.


SKILL.md — the core change

Conversion quality: correct. Checked against all four criteria in precompute-context.md:

Criterion Check
Deterministic & read-only claude --version is read-only
Needed up front, every time ✅ version compare is Phase 0 of every apply/diff
Independent of Claude's judgement ✅ no derived argument needed
Cheap & bounded ✅ single version string

Defensive fallback (|| echo "(CC version unavailable)") is present per the mandatory convention.

Portability: dropping 2>/dev/null is the right call. The redirect is bash-only, and || echo already handles the failure case portably across both the bash default and PowerShell fallback host.

disableSkillShellExecution graceful degradation: if the killswitch fires, the skill renders:

- Installed CC version: [shell command execution disabled by policy]

The model can infer that version comparison is unavailable, which is a clean degradation. No correctness dependency on injection succeeding.

Minor nit — status action description still references claude --version directly.

Line 166:

current `claude --version`, and the gap if installed > last-applied

After this change the version shown by status is the load-time precomputed value, not a fresh claude --version call. The Action Router description is slightly misleading — it reads as though status runs the command itself. The full steps live in context/read-actions.md (not changed here), so there may be a matching call there too. Not a bug (the model will use the precomputed value regardless), but worth a follow-up for documentation consistency. Fix this →


plugin.json — version bump

Version is 0.15.4. The PR description says "0.15.2 → 0.15.3" but the actual diff is 0.15.3 → 0.15.4 — the description was written before the 0.15.3 lanes changes were merged from origin/main. The code is correct; the description is stale. No action needed beyond awareness.


CHANGELOG.md

Entry is accurate and well-written. Correctly placed under [0.15.4] with a Changed heading. The explanation of what was removed (2>/dev/null) and why (cross-platform portability) is clear. No structural issues.


Verdict

LGTM. The conversion is mechanically correct, follows all precompute conventions, and the conservatism of the sweep (one conversion, well-documented skips) is the right call given the UNDER-CONVERT mandate. The status description nit above is a minor follow-up, not a blocker.

@kyle-sexton
kyle-sexton merged commit d2efdf4 into main Jul 21, 2026
26 checks passed
@kyle-sexton
kyle-sexton deleted the refactor/precompute-context-sweep branch July 21, 2026 05:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant