ci: onboard to the CI platform (ci-workflows + standards)#4
Merged
Conversation
feat(ci): onboard claude-code-plugins to the CI platform Stand up quality CI by consuming the ci-workflows composite actions and reusable workflows by pinned SHA (08a9343), aggregated behind a local ci-status gateway (D2), plus the standards drop-in configs adopted by copy (byte-identical to the upstream source). Lanes: markdown, typos, gitleaks, editorconfig, shellcheck, actionlint, check-jsonschema (plugin manifests + dependabot + workflows), the four repo hygiene lanes (exec-bit, machine-specific-paths, eol-renormalize, comment-hygiene), and zizmor (advisory). link-check runs as a separate scheduled, advisory reusable-workflow caller. Dependabot (github-actions, 7-day cooldown) keeps the SHA pins and version comments current. shellcheck is included now (not deferred) because the repo already tracks shell hooks and a .shellcheckrc. hook-utils.sh drops its vestigial shebang to match the standards sourced-library convention so the exec-bit lane passes (it is sourced, never executed; mode stays 100644). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> @
kyle-sexton
added a commit
that referenced
this pull request
Jun 24, 2026
…formatter producer (#5) * docs: add hook-telemetry envelope contract (schema_version 1.0) Publish the marketplace-wide hook-telemetry convention: a versioned public-API contract for plugin hooks (producers) to emit structured execution telemetry to a consumer-set sink (HOOK_TELEMETRY_SINK, fire-and-forget, opt-in; unset = no-op). Carries this hook's own duration_ms, outcome, and findings — the per-hook signal CC-native OTEL structurally cannot provide (it reports aggregate total_duration_ms and excludes third-party plugin content). docs/conventions/hook-telemetry/: - README.md: spec — mediator boundary, fire-and-forget, best-effort/lossy guarantee; 7-field common envelope; status enum ok|error|skipped|blocked; hook_event free string; per-hook data + data/<hook>.schema.json discovery keyed on hook; forward-compat (additive-only, ignore unknown keys AND tolerate unknown enum values); deprecation policy; SemVer versioning; schemas are contract-docs (not machine-enforced); adopt-by-copy. - envelope.schema.json: draft 2020-12; required = all 7 common fields; additionalProperties true; status enum (4); duration_ms integer >= 0. - data/markdown-format.schema.json: required [tool, file, findings]. - CHANGELOG.md: schema_version 1.0 initial. - examples/markdown-format.json: worked fixture, consistent with both schemas. Contract authoring only; no runtime code. markdown-formatter is the first implementer (emit lands Phase 2). Verified (Tier-0, all PASS): fixture shape (schema_version/status/hook_event/ duration_ms/data); envelope additionalProperties + 4-value status enum; README forward-compat/deprecation/not-machine-enforced text; all 3 JSON parse. Lint deferred — markdownlint-cli2 absent locally. Co-Authored-By: Claude <noreply@anthropic.com> * feat(markdown-formatter): emit hook telemetry (schema_version 1.0) First implementer of the hook-telemetry convention. The markdown-format hook now emits one telemetry envelope per run to a consumer-set sink (HOOK_TELEMETRY_SINK), fire-and-forget. Additive and opt-in: sink unset = no-op, with stdout and exit code byte-identical to before. hook-utils.sh: add hook::emit_telemetry <hook_id> <hook_event> <status> <start_epoch> <data_json>. Opt-in guard (sink unset -> return 0) + fail-open (jq absent -> return 0). duration_ms from $EPOCHREALTIME (locale-safe: handles . and , separators, 10# guards octal). timestamp via TZ=UTC printf (true UTC). Envelope built with jq -n (stderr -> /dev/null, never touches fd1). Background dispatch with the sink's stdout AND stderr -> /dev/null so it cannot block CC's stdout read to the 15s hook timeout (the C1 fd1-inheritance blocker) nor leak into additionalContext. markdown-format.sh: capture start before formatting; parse tool_name for data.tool; compute repo-relative data.file (cygpath -lm on Windows Git Bash to reconcile drive-letter vs mount form, plain prefix-strip on Linux/macOS, raw-path fallback); call hook::emit_telemetry LAST on the three post-format paths (markdownlint absent -> skipped; clean -> ok, findings []; residual -> ok, findings = violation lines filtered to the " MD<n>/" pattern). Pre-format exits (ext gate, missing file, kill switch) do not emit. stdin read once (INPUT=$(cat)) and fed to both the file_path and tool_name parses. Tests (TDD): markdown-format.test.sh PASS=41/0 (adds sink-set envelope validity, sink-unset additive-safety, non-zero sink, slow-sink C1 timing, stdout-leak); hook-utils.test.sh PASS=23/0 (sourced-lib unit). Shellcheck clean. Verified Tier-0 end-to-end: schema-valid envelope lands in sink; no fd1 leak; sink-unset produces no envelope with identical stdout; hook returns ~1.4s under a 3s sink (non-blocking). Co-Authored-By: Claude <noreply@anthropic.com> * feat(markdown-formatter): resolve relative HOOK_TELEMETRY_SINK producer-side Resolve a relative HOOK_TELEMETRY_SINK against the caller's repo root so the sink path is clone-portable and worktree-safe when wired via a tracked settings.json env value (CC injects env literally, no ${VAR} expansion). - hook::emit_telemetry: optional 6th repo_root arg ($CLAUDE_PROJECT_DIR fallback, fail-open skip if neither); absolute paths pass through. - Exec changed from unquoted $SINK to quoted "$sink": the sink is now a single executable path (wrap in a script to pass arguments). - markdown-format.sh passes its file-derived REPO_ROOT at all 3 emit sites (CC #9447: CLAUDE_PROJECT_DIR can be empty in plugin hooks). - Contract README gains "Sink path resolution"; CHANGELOG notes it under 1.0. No schema_version bump - envelope wire-format unchanged. - Tests: stub-script sinks replace command-with-args sinks + 4 resolution cases (hook-utils 27/0, markdown-format 41/0). Co-Authored-By: Claude <noreply@anthropic.com> * fix(hook-telemetry): relax status to documented open string; tighten contract docs A closed JSON-Schema enum on `status` contradicted the contract's own "consumers MUST tolerate unknown enum values" rule: a validator code-generated from the published schema would reject a future status value (JSON Schema 2020-12 sec 6.1.2). Relax `status` to a documented open string (mirrors `hook_event`), matching OpenTelemetry's open-enum pattern (`error.type`). - envelope.schema.json: drop the closed `status` enum; keep type:string and list the documented values in the description. - README: correct the `additionalProperties: true` claim (it encodes only unknown-keys-tolerated, not never-remove/rename — the rest is review/policy); record a deferred-with-trigger note for per-data versioning (CloudEvents `dataschema` precedent); add a consumer/sink adoption section. - CHANGELOG: 1.0 `status` documented as an open string, not a closed enum. Pre-publish correction — no schema_version bump. Validated against CloudEvents, OpenTelemetry semantic conventions, and JSON Schema 2020-12 (primary sources). Co-Authored-By: Claude <noreply@anthropic.com> * chore(hook-telemetry): conform to CI platform merged from main (#4) Bring the pre-CI-era telemetry files into conformance with the lanes #4 added: - hook-utils.test.sh: git mode 100644 -> 100755 (it carries a shebang; the exec-bit lane requires shebang scripts be 100755, matching its sibling). - Reword "mis-parse"/"mis-resolve" to plain English in the README sink-path note and two hook-utils.sh comments; the typos lane flags the bare "mis" token. Comment-only; no behavior change. Verified: hook-utils 27/0, markdown-format 41/0, shellcheck clean, typos clean. --------- Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Jun 29, 2026
This was referenced Jul 10, 2026
This was referenced Jul 11, 2026
kyle-sexton
added a commit
that referenced
this pull request
Jul 12, 2026
Address two more Codex P2 findings plus the analogous coaching case: - codebase-detection case (#2): the eval repo has no real auth-flow module, so grounding would fail or reward inventing sources. Reframe to the routing + graceful-degradation invariant — resolve to codebase mode, discover from live files, and ask the user to point when no grounding exists rather than inventing repo sources. - primary-source case (#5) and coaching case (#4): a fresh topic invocation runs the mission interview before teaching, so expecting immediate content rewarded skipping the mission gate. Make both gate-aware — respect the new-workspace mission flow while asserting the grounding / one-question-coaching invariants.
kyle-sexton
added a commit
that referenced
this pull request
Jul 17, 2026
…opy through standards SSOT Corrector #4 reason-dont-recite (incumbency discipline): inherited content is evidence of what is, never self-justifying authority; a choice supported only by precedent earns first-principles re-derivation, not compliance. A distinct axis from do-your-research (acquire external evidence you lack — this questions internal evidence you inherited). SSOT: the consuming project's incumbency / first-principles rule, degrading to a portable baseline. A standards disagreement it surfaces routes upstream via follow-our-standards (routing only — that skill now owns "never silent deviation, never silent conformance"; no doctrine duplicated). point-dont-copy SSOT correction: its re-anchor step now routes through the org standards' reference-don't-duplicate (in-repo facts: literal/semantic, describe/use/expose roles, stable anchors) and documentation-and-citations (external facts: cite + fetch at read time, no upstream-inventory recap, citation placement) conventions instead of restating that doctrine. The skill keeps only its own pins — threshold two (tighter than the convention's three-or-more smell signal), point-at-public-contracts, no-capability- enumeration — and the not-a-copy carve-outs. Metadata, README, CHANGELOG updated; root catalog regenerated via scripts/generate-catalog.mjs. Corrector #5 (terseness) body authored and held pending its locked name. Co-authored-by: Claude Fable 5 <noreply@anthropic.com> 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This was referenced Jul 17, 2026
This was referenced Jul 19, 2026
kyle-sexton
added a commit
that referenced
this pull request
Jul 19, 2026
Eval #4 exercised only the briefed-delegable open outcome. The closing invariant names status:needs-info as the other open outcome that must clear status:needs-triage, and its re-entry path differs (attention-view needs-info bucket on reporter reply, not the raw-marker bucket). Add eval #5 to prove an agent clears the raw marker on the needs-info outcome without orphaning the item. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
kyle-sexton
added a commit
that referenced
this pull request
Jul 20, 2026
…ard blank stderr Address PR #590 review observations: - #2 (required): emit `Unremovable: 0` before `exit 7` so the apply-path label contract is uniform between the clean success and clean-failure paths. - #3: guard the CLEAN_STDERR echo with `[[ -n ... ]]` so a clean that fails with empty stderr no longer prints a bare newline. - #4: assert RestoredTracked:/Unremovable: labels in the clean-failure test. - #1: one-line comment documenting the deferred mixed locked+unrelated-error fall-through (pre-existing heuristic, not a regression). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011V31qpAHP3jfs76B9d5Rfo
This was referenced Jul 20, 2026
77 tasks
kyle-sexton
added a commit
that referenced
this pull request
Jul 21, 2026
…oast - guard the /review:quality-gate cross-plugin ref with a degrade-to-prose fallback (bare unguarded cross-plugin ref is a defect per PLUGIN-PHILOSOPHY) - point-not-copy the fresh-context rationale at the shared method doc's rule instead of restating it; keep only the skill-specific "core step" delta - reframe the audit list as the brief handed to the fresh-context pass rather than a same-context self-audit - reword eval #4 to a disposition check (focus narrows aim, not a hard filter), removing the overreach that assumed a planted out-of-focus flaw with files:[] 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
kyle-sexton
added a commit
that referenced
this pull request
Jul 21, 2026
## Summary
Lane 1 of a locked 3-lane batch. One `session-flow` version bump (0.11.0
→ **0.12.0**), two changes:
1. **New `orient` skill** — read-only session orientation. Synthesizes
*where do we stand, what are we doing, and why* from both the live
conversation and the durable + off-thread state a conversation does not
hold: handoff save-points, the workflow checklist, running-retro ledgers
(via the plugin's topic-docs binding), git state, open PRs, and open
work-items. Strictly read-only — writes nothing, ends nothing, and
**routes rather than acts**: freshness → `reanchor`, off-thread recovery
→ `keep-going`, next-stage → `workflow`, learnings → `retro`.
2. **Hardened `keep-going`** — (a) broadened beyond "after an
interruption" to a live-session **poke** ("check the monitor", "poke
it", "is it stuck", "stop staring") with an active-verification protocol
that reads real output first, treats progress-vs-elapsed as *suspicion
only*, and gates killing/restarting as a side effect so live-but-slow
work is not killed on a hunch; (b) **usage-limit stall fix** — once a
limit lifts and the session is executing again, continue rather than
summarize-and-stall; (c) intent inferred from the conversation,
arguments optional. All prior recovery behavior and **all prior trigger
phrases preserved**.
The plugin now bundles nine skills. Both skills pass
`skill-quality:check` (0 errors, 0 warnings); `claude plugin validate
--strict` passes; `marketplace.json` untouched (it carries no
version/description shadow — only catalog metadata).
## Naming tournament (provisional — user picks)
Dogfooded `naming:name-it-better tournament`: 5 blind fresh-context
generators (responsibility-literal, moment-of-use, domain-lore,
verb-precision, newcomer-onboarding), each seeded only with the
structured brief and blind to the conversation; the main thread merged,
applied the syntactic shaping pass, and scored against the repo's
imperative-verb-phrase grammar and reserved-verb contract.
- **Winner (used provisionally): `orient`** → `/session-flow:orient`.
Converged across **all five** lenses (top pick of verb-precision; top of
moment-of-use and newcomer-onboarding after the `-me` normalization
below). Semantic accuracy first: *orientation is the responsibility*.
One-word imperative verb, temporal-neutral (valid loaded at session
start, unlike `reanchor`/`reorient` which presuppose a prior fix),
collides with no reserved verb or sibling, and is directly cued by the
"orient me" trigger.
- **Runners-up (rejection reasons):**
- `take-stock` — 4 lenses; accurate and temporal-neutral ("stock" can be
empty at start), but leans toward *assessment/evaluation* over pure
orientation and is less directly cued by the firing phrases.
- `brief` — 4 lenses and a strong "brief me" trigger, but collides with
the planning **Brief** artifact (an established noun in this
marketplace: `planning:interview` locks a PLAN.md *Brief*), and carries
verb/adjective ambiguity ("brief" = short).
- `get-bearings` — the newcomer lens's top pick, but two words, a weak
"get", "bearings" faintly presupposes mid-journey (temporal-neutrality
ding), and its nautical family brushes `reanchor`'s anchor metaphor.
- Also surfaced and cut: `read-in` (intel jargon, low general
recognition), `situate` (accurate, lower trigger utility), `size-up` /
`survey-*` (tilt to assessment/scan).
- **Syntactic shaping:** the moment-of-use and newcomer lenses proposed
`orient-me` / `brief-me` / `catch-me-up`; normalized to bare imperative
verbs per the house grammar (the namespace and conversation supply the
object — no sibling bakes a pronoun into its name).
- **Blocklist enforced:** `recap` (built-in `/recap` collision),
`resume`/`continue` (`keep-going` owns), `next` (`workflow` owns).
**@user — final name is yours;** `orient` is provisional. If you prefer
a runner-up, it is a directory rename on this branch before merge.
## Fact-check verdicts (fresh-docs mandate; fetched 2026-07-21)
1. **Can a skill invoke the built-in `/recap`? — NO.** Airtight
citation: the skills doc allowlist — *"A few built-in commands are also
available through the Skill tool, including `/init`, `/review`, and
`/security-review`. Other built-in commands such as `/compact` are
not."* ([skills](https://code.claude.com/docs/en/skills)). `/recap` is
not on that allowlist, so `orient` synthesizes a recap-equivalent
**inline** and adds the durable/off-thread layer recap can't see. (My
commands-doc fetch did not positively confirm `/recap` as a built-in, so
the design cites the allowlist mechanism, not "/recap is built-in".)
2. **Rate-limit / reset info accessible in-session? — Only the message
text; no programmatic surface.** The reset time appears in the limit
**message** (e.g. `resets 3:45pm`), the interactive `/usage` view, the
Desktop usage ring, and custom-statusline `rate_limits` fields — there
is **no env var, file, or API** a skill body can read
([errors](https://code.claude.com/docs/en/errors),
[costs](https://code.claude.com/docs/en/costs),
[statusline](https://code.claude.com/docs/en/statusline)). So
`keep-going` reads the reset from the message text and never fabricates
a window.
## Open design thread — RESOLVED (limit-window not yet reset)
The two options ("schedule a wakeup + auto-continue" vs "summarize +
hand back") are **not mutually exclusive — both sit on a handoff
artifact**:
- **Built-in default (this PR):** while a limit still holds,
`keep-going` cannot progress in-session, so it **hands back via
`/session-flow:handoff`** — no work lost — and stops. It does **not**
build or arm its own scheduler.
- **Auto-continue = an external scheduler's job**, launched to resume
from that same handoff at the reset time. Two forms, each with caveats:
- *Desktop scheduled task* — local, loads plugin/personal skills, but
requires the app open + machine awake
([desktop-scheduled-tasks](https://code.claude.com/docs/en/desktop-scheduled-tasks)).
- *Cloud routine* — runs even when the machine is off, but starts from a
fresh clone and loads only repo-committed / plugin-declared skills,
**not** `~/.claude/skills`
([routines](https://code.claude.com/docs/en/routines),
[skills](https://code.claude.com/docs/en/skills)).
- Both need the reset time parsed from the message text (no API) and the
skill reachable in the launched session.
Rationale (per the independent-reviewer steer): if `keep-going` is
*executing*, the block is already over — there is nothing to wait for in
a single session; the time-vs-window check therefore earns its place
only in the **orchestration** case (inspecting a limited worker), which
the skill scopes it to. This is a resolved default with a documented
deferred path, **not a blocking question**.
## Gates
- [x] `skill-quality:check` PASS on `orient` (new) and `keep-going`
(rewrite; all 8 prior trigger phrases preserved)
- [x] Evals: `orient` 4 cases; `keep-going` 6 cases (4 prior verbatim +
`limit-lifted-go-not-summarize` + `live-poke-evidence-before-kill`).
Eval #4 (`does-not-diagnose-limit-type`) kept **verbatim** — the
anti-stall directive is orthogonal to it.
- [x] `claude plugin validate --strict` PASS
- [x] Version bump in `plugin.json` only (one bump, both changes)
- [x] `marketplace.json` **untouched** — deliberate call: its `tags` are
a curated subset, not a per-skill mirror (`running-retro` is untagged
too), the lane constraint is "untouched unless schema requires", and
`plugin.json` `keywords` already carry `orient`/`orientation` for
discovery.
- [x] **Plugin-acceptance security review (light):** no new trust
surface. `orient` is a read-only prompt skill (no hooks, MCP, scripts,
`userConfig`, `bin/`); it reads only the consumer's memory-tier dirs
under the project and the plugin's own bundled reference via
`${CLAUDE_PLUGIN_ROOT}` — no `../` reach-out, no egress. `keep-going`
remains prompt-only; the new kill/restart guidance is model-facing
prose, gated as a side effect. Surfaces 2/5/6/7 untouched → no SSOT
record required.
- [x] **Independent code review** (fresh-context reviewer) complete — no
CRITICAL, all behavioral MUSTs met. Findings folded (commit `1752bfb`):
plugin `README.md` (nine skills, `orient` row + section,
hardened-`keep-going` section, `orient` added to the Network list) and
`reference/topic-docs.md` (read-only `orient` reader note). The
`marketplace.json` tag suggestion was the deliberate no-change above.
## Related
No linked issue — this PR lands two locked batch-3 decision-ledger items
(the `orient` orientation skill and the `keep-going` hardening) tracked
in the project's private planning ledger, not a GitHub issue.
Do **not** merge — opened for review per lane instructions.
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
kyle-sexton
added a commit
that referenced
this pull request
Jul 21, 2026
## What Adds **`scrutinize-dont-coast`** to the `re-anchor` plugin (0.4.0 → 0.5.0): a drift corrector for **adversarial self-scrutiny** — the general "don't coast on your own recent output" re-look, distinct from the plugin's content-axis correctors (research, incumbency, terseness, …). The user hits the brakes; the skill stops, re-examines whether the recent output is actually sound (not merely confidently produced), and remediates with the user. ## Design Re-anchors a **meta** discipline rather than a single content axis. It runs the shared re-anchor / audit / correct-forward loop (`context/re-anchor-audit-correct.md`) with **two deliberate, documented deltas** — flagged in the SKILL.md rather than silently diverging: 1. **Stop first.** The failure mode is over-confident forward momentum, so it halts the trajectory before auditing. No sibling prepends a stop. 2. **Remediate _with_ the user, not autonomously.** The shared loop's step 3 corrects forward on its own; here it becomes collaborative — the remedy for runaway momentum can't be _more_ unilateral momentum. The load-bearing adversarial pass is **delegated to a fresh-context (non-fork) subagent blind to the reasoning that produced the output**, satisfying the philosophy's fresh-eyes rule that a same-context self-check cannot. Findings return and remediation proceeds _with_ the user — composing the fresh-eyes constraint and the collaborative-remediation intent instead of trading one off. An optional focus scopes the pass without suppressing a serious out-of-focus flaw. **Negative routing (explicit in the skill):** pre-implementation plan stress-tests → `/planning:devils-advocate` (guarded, degrades to prose when absent); review checkpoints → `/review:quality-gate`; single-axis flaws → the sibling that owns them. ## Naming tournament Research-backed tournament via `naming:name-it-better` — **5 blind fresh-context generators** (responsibility-literal, moment-of-use, domain-lore, physical-metaphor, family-idiom-fit), each seeded only with a structured brief (temporal-neutrality constraint, sentence-form test, negative boundary vs devils-advocate/quality-gate, word blocklist: audit/gate/review/devil/advocate/bare-check). - **Winner (provisional, user-confirmable pre-merge): `scrutinize-dont-coast`** — top-2 in 3 of 5 lenses, including the two most decision-relevant (responsibility-literal, family-idiom-fit). Verb-dont-verb family shape (shared with reason-dont-recite, point-dont-copy, reuse-or-replace); temporally neutral (a standing principle, not a presupposition of existing flawed work); names both the action and the failure mode. - **Runners-up:** `distrust-your-momentum` (co-convergent — top-2 in 3 lenses; evocative, but names the cause not the action and reads weaker at the call site); `red-team-your-own-work` (exact term of art, but longer and security-jargon-tinged). Also surfaced: prove-it-holds, pump-the-brakes, stop-and-look-hard. - **My-pick-vs-tournament note:** my own same-context pick before the blind round was `stop-and-scrutinize`; it did not surface in any lens, and the judging confirms the convergent winner scores higher on family-idiom fit, temporal-neutrality, and sentence-form. Dogfooding the blind method overrode the author's anchored pick — exactly this skill's own thesis. ## Gates - `claude plugin validate .` — PASS - `skill-quality check scrutinize-dont-coast` — PASS (0 errors, 0 warnings; markdownlint clean; 133/500 lines; description 529/1536 chars) - evals: 5 cases (trigger+fresh-context happy path, clean-guardrail, devils-advocate negative-routing, focus-scoping, conversation-start posture), schema-valid - Independent fresh-context review (blind to author rationale): verdict SHIP-WITH-FIXES, no CRITICAL; all findings folded (quality-gate ref guarded; fresh-context rationale pointed-not-copied at the method doc; audit list reframed as the fresh-pass brief; eval #4 reworded to a disposition check). The review's skill-quality dimension is the `check-skill.sh` PASS above. - **Plugin-acceptance security review: ACCEPT** — prompt-only skill, zero trust surface added (no hooks/scripts/MCP/userConfig/bin/settings-agent; only internal `${CLAUDE_PLUGIN_ROOT}` ref). Additive 0.4.0→0.5.0 bump touches no trust surface. ## Scope `plugins/re-anchor/skills/scrutinize-dont-coast/{SKILL.md,evals/evals.json}` (new); `plugin.json` (version, description, keywords); `README.md` catalog entry; `plugins/re-anchor/CHANGELOG.md`. `marketplace.json` untouched (version lives in plugin.json; adding a skill to an existing plugin does not change its catalog entry). ## Open questions for the user 1. **Precedent — first family skill to override shared-loop steps (needs a user ruling).** This is the first corrector to declare deltas to the shared re-anchor / audit / correct loop: it prepends a STOP and makes step 3 collaborative ("remediate _with_ the user") where every sibling corrects forward autonomously. Resolved here as documented per-skill deltas — `context/re-anchor-audit-correct.md` was NOT touched. Two ways to settle the precedent, your call: **(a) sanction** declared per-skill step-overrides by adding an allowance to the shared method doc (so future correctors may do this cleanly), or **(b) reconsider** — fold the behavior back to the autonomous family default. If instead STOP-first + collaborative-remediation should become the family norm, that's a method-doc change touching all 13 skills — a separate decision, not made unilaterally here. 2. **Name.** `scrutinize-dont-coast` is the provisional tournament winner; `distrust-your-momentum` is the co-convergent alternative. Confirm or swap before merge (trivial rename). ## Cross-lane note Lane 3's `planning:devils-advocate` incumbent extension is in flight concurrently. This skill's boundary text keys on the stable contract (devils-advocate = plans/proposals _before_ implementation; this = output _already produced_, mid-flight), which is robust to that extension — no coordination edit needed. ## Related - **No linked issue** — this skill was locked from the batch-3 interview ledger (re-anchor item 2); it was never tracked as a GitHub issue, so this PR closes nothing. - Plugin `plugins/re-anchor` (0.4.0 → 0.5.0). - Concurrent batch-3 lanes (independent PRs): session-flow orientation + keep-going hardening; `planning:devils-advocate` incumbent extension — see the cross-lane note above. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 21, 2026
kyle-sexton
added a commit
that referenced
this pull request
Jul 21, 2026
## What Folds the four naming-tournament lessons recorded during the running-retro naming round (batch ledger, "Naming-skill lessons this round") into `name-it-better`; naming 0.2.0 → 0.3.0. - **Terms-of-art brief field** — the field's established names for the act with researched, not recalled, meanings. Evidence: running-retro r4 found `reflect` (agent-lit: output-critique-retry), `introspect` (type inspection), and `self-review` (repo-colonized for diff review) all misleading; the honest field term was `retrospective` minus cadence. - **Blocklist provenance** — every word-level blocklist entry records user-stated vs agent-inferred origin; inferred entries are proposals to confirm. Evidence: the "retro" blocklist entry was agent-assumed, never user-decided, and was reversed on re-derivation. - **Sentence-form test** as an early merge filter for utterance names (skills/commands): the imperative you would actually say, cold-readable. Evidence: filtered contentless idioms (`take-stock`, bare `check`) across r1-r2. - **Temporal-neutrality constraint** for skills loadable as primed context: name must read valid before any work exists (`critique-your-own-run` failure class). ## Gates - `claude plugin validate .` — PASS - `markdownlint-cli2` — 0 errors - `skill-quality check name-it-better` — PASS (0 errors; 1 pre-existing soft line-target warning, file was already over 200 before this change) ## Related - No linked issue — ledger-tracked follow-up (re-anchor round 2 ledger, task #4); closes nothing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
kyle-sexton
added a commit
that referenced
this pull request
Jul 21, 2026
…857) ## What Adds a bundled **`jira`** adapter to the work-item-tracker seam (`plugins/work-items/tools/work-item-tracker/adapters/jira/`), alongside the shipped `github` and `local-markdown` adapters. GitHub stays the default. Scoped to the **read/resolve path** per the #379 maintainer decisions ([15:48](#379 (comment)), [re-intake](#379 (comment))). Closes #379. ## Adapter surface Consume-only by default (issue #379 hard constraint) — the manifest declares: | Verb | Supported | Notes | |---|---|---| | `get-item` | ✅ | `GET /rest/api/3/issue/{key}` → normalized item | | `list-items` | ✅ | `POST /rest/api/3/search/jql`, `nextPageToken` pagination, JQL scoped to `project_keys` | | `capabilities` | ✅ | cats the manifest | | `create-item`, `claim`, `renew-lease`, `reclaim`, `link-blocks`, `add-sub-item` | ❌ exit 6 | writes — no code path mutates a Jira ticket | | `list-sub-items` | ❌ exit 6 | Jira epic-child/subtask enumeration is the deferred #6 link-type question; `list-frontier --parent` degrades to exit 6 | **No code path creates, claims, or mutates a Jira ticket by default.** `/work-items:work`, `track start`, and `list-frontier --parent` are consequently unavailable on a Jira binding — an accepted gap. Branch/PR `SW2-*` linkage and opt-in writes are sequenced follow-ups. ## Read-path normalization `state` (statusCategory → open/closed), `assignees` (single assignee → accountId), `labels` (verbatim), `type` (issue-type name), open-only `blocked_by_count` (inward blocker links; linked-issue status inlined in `issuelinks`, so one call), `parent_id` (`fields.parent`), `url` (browse link). ID grammar: `jira:<site>/<PROJECTKEY>#<number>` ⇄ native key `PROJECTKEY-number`. ## Auth & config Basic auth (email + API token). The token is read from the env var **named** by `config.jira.auth_env` — never stored in the tracked binding, and passed to curl via a stdin config (`-K -`) so it never appears in argv. Required config: `config.jira.{site, project_keys[], auth_email, auth_env}`. The blocker link type (`blocked_by_link_type`, default `Blocks`) and the "done" statusCategory key set (`done_category_keys`, default `["done","completed"]`) are configurable override seams for the two facts deferred to the live-instance pass, so the adapter is independent of them. ## Fresh-docs research (per CLAUDE.md fresh-docs mandate) Every endpoint/field was verified this session against the **official Atlassian OpenAPI spec** (`https://dac-static.atlassian.com/cloud/jira/platform/swagger-v3.v3.json`) and official docs — not training-data recall: - **Enhanced JQL search** `POST /rest/api/3/search/jql` (request `jql`/`fields`/`maxResults`≤5000/`nextPageToken`; response `issues[]`/`nextPageToken`/`isLast`): https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-search/#api-rest-api-3-search-jql-post - **Get issue** `GET /rest/api/3/issue/{issueIdOrKey}` (`fields` query param): https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-get - **Bulk blocked_by_count is schema-supported**: `IssueBean.fields.issuelinks[].inwardIssue` is a `LinkedIssue` whose `fields` uses the `Fields` schema, which includes `status.statusCategory.key` — so a single search call deep-populates each blocker's status (no second round-trip). Verified in the spec's component schemas. - **statusCategory key ambiguity (why `done_category_keys` defaults to both)**: the spec's own `GET /statuscategory` example returns keys `in-flight`/`completed`, while real Jira Cloud instances widely return `new`/`indeterminate`/`done` (community-flagged doc gap) — only the live instance settles it. https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-workflow-status-categories/#api-rest-api-3-statuscategory-get - **Basic auth** (email + API token, passwords deprecated, `Authorization: Basic base64(email:token)`): https://developer.atlassian.com/cloud/jira/platform/basic-auth-for-rest-apis/ · tokens at https://id.atlassian.com/manage/api-tokens ## Tests - Adapter unit tests mock `curl` via a `WIT_JIRA_CURL` seam — the read path (normalization, OPEN-only blocked_by_count, done-exclusion, parent qualification, pagination across two `nextPageToken` pages, error → exit-code mapping) is exercised **fully offline, no live Jira call**. - A `jira` conformance binding runs the abstract seam suite **offline in CI** (the consume-only manifest makes every suite-exercised path pre-network), and re-runs it under a `gh`/`curl`-blocking PATH shim to prove zero network. - All 38 work-item-tracker seam tests, `shellcheck --rcfile=.shellcheckrc`, changelog-parity, plugin validation, skill-portability, and markdownlint pass locally. ## Independent review Audited by a fresh-context reviewer (producer ≠ critic). It found — and this branch fixes — a **JQL-injection CRITICAL**: `list-items` assembled the `project in (...)` / `statusCategory in (...)` clauses by string concatenation without escaping embedded quotes, so a `--repo` or configured key containing `"` could inject arbitrary JQL. Fixed by allowlist-validating every JQL-interpolated value before assembly (configured keys → exit 3 at config load; `--repo` key → exit 2 at parse; both before any HTTP call), with tests asserting the literal JQL payload and hostile-input rejection. Advisory nits (null-accountId assignee → `[]`, up-front rejection of a malformed project key in an id, a hardcoded date in the conformance binding) also folded in. Everything else — consume-only structure, token hygiene, exit codes, pagination — verified clean. ## Contract gaps found - **Provider-config injection** (`lib/binding.sh` carries a `local-markdown`-specific `storage_dir` leak; adapters must re-resolve the binding to read their own `config.<provider>`). The Jira adapter reads `config.jira` itself rather than growing that leak. Filed as scoped follow-up **#852**. - **Live-instance facts deferred** (#4 exact "done" key, #6 blocker/sub-item link type) — handled via configurable defaults, not blocking. ## Not in scope (sequenced follow-ups) Opt-in writes; branch/PR `SW2-*` linkage (spans two plugins' source, forbidden by this issue's acceptance); container-scoped frontier (`list-sub-items`). ## Related Related work this PR does **not** close: - **#852** — scoped follow-up filed from this PR: the seam should export the resolved binding path so adapters read `config.<provider>` without re-resolving (retires the `lib/binding.sh` provider-config leak). Not required for this adapter. - **#440** — outward write-mode / posture decision that a future opt-in-writes change for this adapter will key on (this PR ships writes-off, so it does not depend on #440 yet). - **#416 / #418** — seam-agnosticism prerequisites (skills that hardcode `gh` bypass the seam). Independent of this adapter landing, but they bound how broadly a non-GitHub provider is reachable across all consumers. - Live-instance confirmations deferred to the work-laptop pass — the exact `statusCategory` "done" key (#379 decision #4) and the authoritative blocker/sub-item link type (#379 decision #6); both have configurable defaults here. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 23, 2026
This was referenced Jul 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
@
Stands up quality CI for
claude-code-plugins, the next consumer in the dedup-program rollout (Phase 6 / greenfield). CI consumes theci-workflowsbuilding blocks by pinned SHA behind a localci-statusgateway, and adopts thestandardsdrop-in configs by copy (byte-identical to upstream).Step 0 resolution (visibility)
The rollout prompt assumed
ci-workflowswas private (which would block a public caller per architecture D6). Live state:ci-workflowsis already public, souses: melodic-software/ci-workflows/...@sharesolves from this public repo — the standard consume-by-reference model works, no architectural change needed. (Follow-ups below reconcile the IaC/doc drift this surfaced.)Lanes (all dogfooded green locally)
markdown,typos,gitleaks,editorconfig,shellcheck,actionlint,check-jsonschema(plugin manifests via schemastore +dependabot.yml+ workflows), the four hygiene lanes (exec-bit,machine-specific-paths,eol-renormalize,comment-hygiene), andzizmor(advisory).link-check.ymlis a separate scheduled, advisory reusable-workflow caller (issues: write, files a rolling tracking issue). Dependabot (github-actions, 7-day cooldown) keeps the SHA pins + version comments current.Deviations from the tracker, driven by live tracked files
shellcheckincluded now (tracker said "later") — the repo already tracks shell hooks and a.shellcheckrc.hook-utils.shdrops its vestigial shebang →# shellcheck shell=bash, matching the standards sourced-library convention, soexec-bitpasses (it is sourced, never executed; mode stays100644). This is a one-line line-1 change, disjoint from the concurrentfeat/hook-telemetry-conventionwork on the same file (which adds a function lower down) — they 3-way merge cleanly.osv-scanneromitted — no dependency lockfiles exist to scan..editorconfig/.gitattributes/.shellcheckrcreplaced with the canonical standards copies.Follow-ups (separate PRs, after this is green)
Program.csstill declaresci-workflowsprivate), enable free public-repo secret scanning + push protection on this repo, and tag itrequires-cito arm the orgci-gate(sequenced so a greenci-statusexists onmainfirst).@