Skip to content

[AI-1915] Inject a SessionStart work-items nudge across all harnesses - #548

Merged
realtonyyoung merged 5 commits into
mainfrom
tonyyoung/ai-1915-workitems-nudge
Aug 13, 2026
Merged

[AI-1915] Inject a SessionStart work-items nudge across all harnesses#548
realtonyyoung merged 5 commits into
mainfrom
tonyyoung/ai-1915-workitems-nudge

Conversation

@realtonyyoung

Copy link
Copy Markdown
Collaborator

What

Registering kcap-workitems on every harness (AI-1914) is not enough on its own — no harness was told to use it. This adds a short, standing SessionStart work-items nudge: it tells the agent it is in a recorded Kurrent Capacitor session (with the current session id, rendered verbatim so a harness without an ambient KCAP_SESSION_ID can pass it explicitly), and to declare_work_item when it starts on a tracked item and declare_work_breakdown / declare_work_relation as it discovers structure. So work-item topology (Home "Blockers & dependencies", progress figures) stops being empty.

Design

  • WorkItemsNudgeEmitter builds the static nudge from the session id — a pure function, no server round-trip and no lease. The nudge contract names all three tools with explicit blocks/blocked_by directionality, and says to attach to the real issue key/PR (create-by-title only when there is genuinely no tracker item, never fabricating an id).
  • Isolation invariant (the load-bearing one): the nudge is composed at the output layer (SessionStartMemoryOutputAdapters.Render, marker-first when it stands alone) after the lease-gated memory/guidelines fragment is decided, so its presence never changes the acquire/complete/retry state of those lanes. A null nudge is byte-identical to the pre-nudge render (tested across all 8 non-Claude harnesses).
  • WorkItemsNudgeAvailability gates the nudge on the invoking harness's actual materialized MCP config carrying an enabled kcap-workitems entry (JSON mcpServers/mcp, Codex config.toml, Pi extension content; Claude always had it). Config-level, not a runtime health probe; fail-closed on absent/disabled/malformed/unreadable — a stale install is never nudged toward a tool it lacks.
  • Opt-out disable_workitems_nudge (default off), wired through kcap config and all nine hooks. OpenCode additionally respects its plugin fragment-capability gate.

Wired into all 9 SessionStart hooks (Claude via BuildEnvelope's variadic slot; the 8 others via Render), preserving each hook's existing no-content byte-identity.

Tests

WorkItemsNudge*Tests (20): emitter contract (session-id verbatim, all three tools + directionality, opt-out/unavailable suppression), the availability gate per representative harness (present / absent / malformed / disabled → fail-closed), and the Render composition + isolation (marker-first when alone; null nudge == baseline). All 266 existing SessionStart hook/memory tests still pass unchanged.

Spec + codex spec-review (clean, 5 rounds) recorded on the Linear issue.

Ships in the same release as AI-1914.

Fixes AI-1915

Registering kcap-workitems everywhere (its companion change) is not enough on
its own: no harness was told to USE it. This adds a short, standing SessionStart
nudge that tells the agent it is in a recorded session (with the current session
id, rendered verbatim so a harness without an ambient KCAP_SESSION_ID can pass it
explicitly) and to register the session with declare_work_item and declare its
structure with declare_work_breakdown / declare_work_relation as it works.

Design:
- WorkItemsNudgeEmitter builds the static nudge from the session id — a pure
  function, no server round-trip and no lease.
- It is composed at the OUTPUT layer (SessionStartMemoryOutputAdapters.Render,
  marker-first when it stands alone) AFTER the lease-gated memory/guidelines
  fragment is decided, so its presence never changes the acquire/complete/retry
  state of those lanes. A null nudge is byte-identical to the pre-nudge render.
- WorkItemsNudgeAvailability gates the nudge on the invoking harness's ACTUAL
  materialized MCP config carrying an enabled kcap-workitems entry (config-level,
  not a runtime health probe); fail-closed on absent/disabled/malformed/unreadable
  so a stale install is never nudged toward a tool it lacks. Claude always had it.
- disable_workitems_nudge profile opt-out (default off), wired through kcap config
  and all nine hooks; OpenCode additionally respects its plugin fragment-capability
  gate.

Wired into all 9 SessionStart hooks (Claude via BuildEnvelope; the 8 others via
Render), preserving each hook's existing no-content byte-identity.

Tests: emitter contract (session-id verbatim, all three tools + blocks/blocked_by
directionality, opt-out/unavailable suppression), the availability gate per
representative harness (present/absent/malformed/disabled, fail-closed), and the
Render composition + isolation (marker-first-alone; null nudge == baseline).

Ships in the same release as AI-1914.

Fixes AI-1915

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Aug 12, 2026

Copy link
Copy Markdown

AI-1915

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Inject SessionStart work-items nudge across all harness hooks

✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Inject a static SessionStart work-items nudge with verbatim session id and declare_* guidance.
• Gate nudge on kcap-workitems being materialized in each harness config, with fail-closed behavior.
• Add disable_workitems_nudge opt-out and tests for availability, rendering, and byte-identity.
Diagram

graph TD
A["SessionStart hooks"] --> B["WorkItemsNudgeEmitter.Resolve"] --> E["SessionStartMemoryOutputAdapters.Render"] --> F["Hook stdout payload"]
B --> C["WorkItemsNudgeAvailability"] --> D[("Harness MCP config")]
G[("kcap profile config")] --> B
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Runtime health probe for kcap-workitems
  • ➕ More accurate than config inspection when configs are stale or server fails to start
  • ➕ Could surface actionable diagnostics instead of silently suppressing the nudge
  • ➖ Too expensive/risky at hook time (spawns/handshakes add latency and failure modes)
  • ➖ Would violate the ‘no server round-trip’ design goal and increase flakiness
2. Persist a first-class ‘workitems registered’ marker during setup/doctor
  • ➕ Avoids per-harness config parsing differences and reduces brittleness to format changes
  • ➕ Could be faster than reading/parsing multiple config formats
  • ➖ Marker can drift from reality if users manually edit/disable MCP entries
  • ➖ Adds extra state that must be kept consistent across installers and upgrades
3. Compose the nudge upstream with the lease-gated memory/guidelines fragment
  • ➕ Single composition point for all SessionStart injections
  • ➕ Potentially simpler call sites (only one fragment to render)
  • ➖ Risks changing lease acquire/complete/retry behavior (breaks isolation invariant)
  • ➖ Harder to guarantee byte-identical output when nudge is absent

Recommendation: Keep the PR’s approach: build the nudge as a pure function and merge it only in SessionStartMemoryOutputAdapters.Render, preserving lease semantics and enabling byte-identity guarantees. The fail-closed, config-level availability gate is an appropriate tradeoff for hook-time reliability; runtime probes or extra persistent markers would increase complexity and operational risk.

Files changed (16) +458 / -40

Enhancement (12) +248 / -40
AntigravityHookCommand.csInject work-items nudge into Antigravity SessionStart output +7/-5

Inject work-items nudge into Antigravity SessionStart output

• Extends pre-invocation output rendering to accept an optional work-items nudge. Resolves the nudge per session and profile opt-out, then merges via SessionStartMemoryOutputAdapters.Render.

src/Capacitor.Cli/Commands/AntigravityHookCommand.cs

ClaudeHookCommand.csAdd work-items nudge to Claude additional-context envelope +7/-1

Add work-items nudge to Claude additional-context envelope

• Resolves the static work-items nudge (Claude always has kcap-workitems; only opt-out can suppress) and passes it into the variadic SessionStartAdditionalContext.BuildEnvelope composition.

src/Capacitor.Cli/Commands/ClaudeHookCommand.cs

CodexHookCommand.csInject work-items nudge while preserving Codex no-content byte identity +12/-4

Inject work-items nudge while preserving Codex no-content byte identity

• Adds optional work-items nudge support to the single-JSON SessionStart output path. Keeps the pre-existing constant output when both fragment and nudge are absent; otherwise renders through the shared adapter.

src/Capacitor.Cli/Commands/CodexHookCommand.cs

CopilotHookCommand.csInject work-items nudge into Copilot SessionStart output +7/-5

Inject work-items nudge into Copilot SessionStart output

• Extends SessionStart output writer to accept an optional nudge and remain silent when both fragment and nudge are absent. Resolves the nudge and renders via SessionStartMemoryOutputAdapters.Render.

src/Capacitor.Cli/Commands/CopilotHookCommand.cs

CursorHookCommand.csAppend work-items nudge at Cursor render step +7/-1

Append work-items nudge at Cursor render step

• Resolves the work-items nudge after memory orchestration completes (re-reading profile opt-out) and merges it in the render call to preserve lease isolation and fail-open behavior under surrounding catch.

src/Capacitor.Cli/Commands/CursorHookCommand.cs

GeminiHookCommand.csInclude work-items nudge in Gemini SessionStart payload rendering +7/-5

Include work-items nudge in Gemini SessionStart payload rendering

• Updates Gemini’s payload renderer to render when either a memory fragment or a nudge is present. Resolves and merges the nudge via the shared render adapter while retaining the allow-payload fallback on failure.

src/Capacitor.Cli/Commands/GeminiHookCommand.cs

KiroHookCommand.csInject work-items nudge into Kiro agent-spawn output +6/-4

Inject work-items nudge into Kiro agent-spawn output

• Extends the agent-spawn output writer to accept an optional nudge and renders both through SessionStartMemoryOutputAdapters.Render. Resolves the nudge using session id and profile opt-out before writing/flushing.

src/Capacitor.Cli/Commands/KiroHookCommand.cs

OpenCodeHookCommand.csGate work-items nudge on OpenCode stdout fragment capability +15/-8

Gate work-items nudge on OpenCode stdout fragment capability

• Introduces a canConsumeFragment gate so the nudge is only emitted when the installed plugin version captures stdout. Extends fragment writing/rendering helpers to accept an optional nudge and preserve zero-bytes behavior when both are absent.

src/Capacitor.Cli/Commands/OpenCodeHookCommand.cs

PiHookCommand.csInject work-items nudge into Pi SessionStart fragment output +10/-6

Inject work-items nudge into Pi SessionStart fragment output

• Extends Pi’s fragment render/write helpers to accept an optional nudge and preserve empty output when both are absent. Resolves the nudge and writes via the shared adapter to keep marker-gated capture behavior.

src/Capacitor.Cli/Commands/PiHookCommand.cs

SessionStartMemoryOutputAdapters.csMerge optional work-items nudge at the output layer +17/-1

Merge optional work-items nudge at the output layer

• Extends Render to accept an optional work-items nudge and merges it into the already-decided fragment. Ensures marker-first behavior when the nudge stands alone (for Pi/OpenCode capture) and keeps outputs byte-identical when nudge is null/whitespace.

src/Capacitor.Cli/SessionStartMemory/SessionStartMemoryOutputAdapters.cs

WorkItemsNudgeAvailability.csAdd fail-closed availability gate for kcap-workitems registration +99/-0

Add fail-closed availability gate for kcap-workitems registration

• Introduces a harness-specific check that kcap-workitems is actually materialized/enabled in on-disk MCP configuration (JSON, Codex TOML, or Pi extension content). Suppresses the nudge on absent/disabled/malformed/unreadable config; Claude is always treated as available.

src/Capacitor.Cli/WorkItemsNudgeAvailability.cs

WorkItemsNudgeEmitter.csImplement static SessionStart work-items nudge builder/resolver +54/-0

Implement static SessionStart work-items nudge builder/resolver

• Adds a pure nudge builder that embeds the session id verbatim with a defensive length cap. Provides a resolver that applies opt-out and availability gating before returning the final nudge text.

src/Capacitor.Cli/WorkItemsNudgeEmitter.cs

Tests (1) +197 / -0
WorkItemsNudgeTests.csAdd unit tests for nudge text, availability gating, and render isolation +197/-0

Add unit tests for nudge text, availability gating, and render isolation

• Adds coverage for nudge construction (session id behavior, tool naming, directionality) and resolver suppression conditions. Verifies availability gating across representative harness config shapes and asserts output-layer isolation/byte-identity and marker-first behavior when nudge-only.

test/Capacitor.Cli.Tests.Unit/WorkItemsNudgeTests.cs

Documentation (1) +1 / -0
help-config.txtDocument disable_workitems_nudge config key +1/-0

Document disable_workitems_nudge config key

• Extends config help text to include the new disable_workitems_nudge option for SessionStart behavior control.

src/Capacitor.Cli.Core/Resources/help-config.txt

Other (2) +12 / -0
ProfileConfig.csAdd disable_workitems_nudge profile option +9/-0

Add disable_workitems_nudge profile option

• Introduces a new optional profile flag to suppress SessionStart work-items nudge injection independently of other SessionStart injections. Documents intended behavior and separation from memory/guidelines opt-outs.

src/Capacitor.Cli.Core/Config/ProfileConfig.cs

ConfigCommand.csWire disable_workitems_nudge into config set/usage output +3/-0

Wire disable_workitems_nudge into config set/usage output

• Adds parsing/validation for disable_workitems_nudge in ApplySet and updates CLI usage text to expose the new key.

src/Capacitor.Cli/Commands/ConfigCommand.cs

- JSON gate: require the matching entry to be an object; a null/string/array
  value is malformed and suppresses. An explicit `enabled` must be a Boolean
  true — a false or a non-Boolean (e.g. "false") suppresses.
- Pi gate: match "workitems" inside the actual KCAP_MCP_SERVERS array literal,
  not any stray token (a comment mention no longer counts).
- Codex gate: use ReadMcpServerCommands (requires a command) so a malformed,
  command-less table does not count.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@qodo-code-review

qodo-code-review Bot commented Aug 12, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. README missing disable_workitems_nudge ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
This PR adds a new user-facing config key (disable_workitems_nudge) and introduces a SessionStart
work-items nudge, but README.md is not updated to document the new behavior/opt-out. This violates
the requirement that CLI surface changes update README.md in the same PR.
Code

src/Capacitor.Cli/Commands/ConfigCommand.cs[R172-173]

+            "disable_workitems_nudge" when bool.TryParse(value, out var b) => profile with { DisableWorkItemsNudge = b },
+            "disable_workitems_nudge" => throw new ArgumentException($"Invalid value for disable_workitems_nudge: '{value}'. Must be true or false."),
Evidence
The diff adds a new persisted config key (disable_workitems_nudge) and exposes it via `kcap
config help/handling, which is a user-facing CLI surface change. The root README.md` documents
other SessionStart injections and their opt-outs (e.g., disable_session_guidelines,
disable_memory_index) but contains no mention of disable_workitems_nudge or the work-items nudge
behavior, so documentation is now incomplete.

CLAUDE.md: User-facing CLI surface changes must update README.md in the same PR
src/Capacitor.Cli/Commands/ConfigCommand.cs[172-173]
src/Capacitor.Cli.Core/Resources/help-config.txt[19-19]
src/Capacitor.Cli.Core/Config/ProfileConfig.cs[64-71]
README.md[205-223]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new user-facing config key (`disable_workitems_nudge`) and a new SessionStart “work items” nudge were added, but the root `README.md` does not document the new injection or how to opt out.

## Issue Context
The PR updates CLI/config surface (`kcap config set disable_workitems_nudge ...` and config key listing) and changes SessionStart behavior across harnesses. Per compliance, these changes must be reflected in `README.md` in the same PR.

## Fix Focus Areas
- README.md[205-223]
- src/Capacitor.Cli/Commands/ConfigCommand.cs[172-173]
- src/Capacitor.Cli.Core/Resources/help-config.txt[19-19]
- src/Capacitor.Cli.Core/Config/ProfileConfig.cs[64-71]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Nudge gate never satisfied ✗ Dismissed 🐞 Bug ≡ Correctness
Description
WorkItemsNudgeAvailability only enables the nudge when a harness config contains a kcap-workitems
MCP entry, but current setup/registration lists explicitly omit that server for Codex and the JSON
harness projections. This makes WorkItemsNudgeEmitter.Resolve return null on those harnesses, so
the nudge will never emit even after kcap setup.
Code

src/Capacitor.Cli/WorkItemsNudgeAvailability.cs[R31-34]

+static class WorkItemsNudgeAvailability {
+    const string ServerName = "kcap-workitems";
+
+    /// <param name="home">Overrides the user home root for the JSON/Pi path helpers (test seam).</param>
Evidence
The new availability gate hard-codes kcap-workitems as the required server name. In the current
repo, the canonical MCP registration subsets used by setup/projections explicitly exclude
kcap-workitems, so those harness configs will not contain the entry and the gate will return
false.

src/Capacitor.Cli/WorkItemsNudgeAvailability.cs[31-52]
src/Capacitor.Cli.Core/Mcp/KcapMcpServers.cs[31-41]
src/Capacitor.Cli.Core/Mcp/HarnessMcpProjections.cs[43-52]
src/Capacitor.Cli/Commands/SetupCommand.cs[339-345]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`WorkItemsNudgeAvailability` requires a materialized `kcap-workitems` entry, but current registration subsets (`KcapMcpServers.ForCursor` / `ForCodex`) filter that server out, and setup/projections register exactly those subsets. This prevents the new nudge from ever being considered available for at least Codex and the JSON harnesses.

### Issue Context
The PR’s intended behavior is “nudge across all harnesses” gated on the MCP server actually being installed. Today, the installer paths shown in repo still omit `kcap-workitems`, so the availability gate will remain false.

### Fix Focus Areas
- src/Capacitor.Cli/WorkItemsNudgeAvailability.cs[31-55]
- src/Capacitor.Cli.Core/Mcp/KcapMcpServers.cs[31-41]
- src/Capacitor.Cli.Core/Mcp/HarnessMcpProjections.cs[43-52]
- src/Capacitor.Cli/Commands/SetupCommand.cs[339-345]

### What to change
- Decide the real desired model:
 - If `kcap-workitems` should now be registered for Codex + JSON harnesses, update `KcapMcpServers.ForCursor` and `ForCodex` (and any comments) to include it so `kcap setup`/`kcap plugin install` materialize the entry.
 - If some harnesses should still not register it, update the hook wiring to not attempt to resolve the nudge for those harnesses (or adjust the availability gate to match how/where it is truly installed for them).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Enabled flag not fail-closed ✓ Resolved 🐞 Bug ☼ Reliability
Description
WorkItemsNudgeAvailability.JsonBlockHasServer treats a matching entry as enabled unless enabled is
parsed as boolean false, so malformed enabled values (e.g. string/number) still mark the server as
available. This violates the documented fail-closed behavior and can nudge a harness toward tools it
will not load.
Code

src/Capacitor.Cli/WorkItemsNudgeAvailability.cs[R89-92]

+                if (entry is JsonObject o && o["enabled"] is JsonValue en &&
+                    en.TryGetValue<bool>(out var enabled) && !enabled)
+                    return false;
+                return true;
Evidence
The file claims malformed configs should suppress the nudge, but the implementation returns true for
a matching entry unless it can successfully parse enabled as a bool and finds it false.

src/Capacitor.Cli/WorkItemsNudgeAvailability.cs[14-29]
src/Capacitor.Cli/WorkItemsNudgeAvailability.cs[79-97]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`JsonBlockHasServer` is documented to fail-closed on malformed config, but it only returns false when it can parse `enabled` as a boolean `false`. If `enabled` exists but is not a boolean, it falls through to `return true`.

### Issue Context
This gate exists specifically to avoid nudging users toward tools they don’t have; treating malformed `enabled` as “enabled” undermines that safety property.

### Fix Focus Areas
- src/Capacitor.Cli/WorkItemsNudgeAvailability.cs[79-97]

### What to change
- Distinguish between:
 - `enabled` absent → treat as enabled by default (for harnesses where that’s correct),
 - `enabled` present and boolean false → disabled,
 - `enabled` present but non-boolean / unparseable → malformed → return false (fail closed).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Unescaped session id ✓ Resolved 🐞 Bug ☼ Reliability
Description
WorkItemsNudgeEmitter.Build inserts the session id verbatim inside Markdown backticks; session ids
containing backticks/newlines/control chars (e.g. Pi uses a session file path) can break formatting
and inject unintended text into the SessionStart context. This can corrupt the injected fragment and
undermine the nudge instructions.
Code

src/Capacitor.Cli/WorkItemsNudgeEmitter.cs[R43-46]

+            "## Work items\n" +
+            $"You are in a recorded Kurrent Capacitor session (id: `{id}`). When you start work on a " +
+            "tracked item, register this session with it using the kcap-workitems MCP tool " +
+            "`declare_work_item` — attach by the issue key, PR number, or existing work-item id you are " +
Evidence
The emitter directly interpolates {id} into a backtick-delimited Markdown snippet without
escaping. Pi explicitly uses a session file path as the SessionId, which can contain unusual
characters on some filesystems.

src/Capacitor.Cli/WorkItemsNudgeEmitter.cs[37-52]
src/Capacitor.Cli/Commands/PiHookCommand.cs[289-299]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`WorkItemsNudgeEmitter.Build` formats the session id as Markdown inline code using backticks, but does not escape backticks or strip control characters. Since some harnesses use non-UUID session ids (e.g. Pi uses a session file path), valid ids can contain characters that break the intended formatting.

### Issue Context
The nudge is injected into the agent’s prompt context, so preserving prompt integrity matters even when the id is “only” a string.

### Fix Focus Areas
- src/Capacitor.Cli/WorkItemsNudgeEmitter.cs[37-53]
- src/Capacitor.Cli/Commands/PiHookCommand.cs[289-299]

### What to change
- Sanitize/encode the id before interpolation. For example:
 - Replace backticks with an escaped representation (or choose a quoting strategy that cannot be terminated by the content), and
 - Remove/replace `\r`, `\n`, and other control chars.
- Keep the user-visible value copyable (the design wants “verbatim”), but ensure it can’t break the surrounding nudge formatting.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can type 'qodo, fix this' on a finding and the fix lands right on your PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/Capacitor.Cli/Commands/ConfigCommand.cs
Comment thread src/Capacitor.Cli/WorkItemsNudgeAvailability.cs
Comment thread src/Capacitor.Cli/WorkItemsNudgeEmitter.cs
Comment thread src/Capacitor.Cli/WorkItemsNudgeAvailability.cs Outdated
realtonyyoung and others added 3 commits August 12, 2026 18:36
The first-occurrence scan could select a commented-out KCAP_MCP_SERVERS
declaration before the real one. Now strip JS line/block comments first, find
the real declaration, and require "workitems" as an exact array element (not a
substring). Tests: commented declaration before the real one, block comment, and
a non-exact element all suppress.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- WorkItemsNudgeEmitter.Build now suppresses a session id carrying a backtick or
  any control char (newline/CR/tab) — it would otherwise break the Markdown code
  span or smuggle formatting into agent context. A uuid/hex/file-path id (Pi's is
  a file path) passes untouched. Tests added.
- README: document the SessionStart work-items nudge + disable_workitems_nudge
  opt-out, and correct the now-stale "kcap-workitems is Claude-Code-only" claims
  (it is registered on every harness as of the companion change).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ests

The Claude availability gate was hardcoded true, so the work-items nudge was
emitted in the ClaudeHookCommand SessionStart tests (which run against the real
~/.claude), breaking six byte-exact memory-output assertions on any machine with
the kcap plugin installed. Fixes:
- Claude gate now uses ClaudePluginInstaller.IsEffectivelyInstalled (matching the
  spec: available exactly when the plugin's bundled .mcp.json is loadable), so a
  plugin-free environment (CI, isolated test home) fails closed → no nudge.
- ClaudeHookCommandTests.Fixture isolates CLAUDE_CONFIG_DIR to its temp home
  (safe under the class's [NotInParallel("HomeEnvVarMutation")] lock), making the
  whole Claude config surface hermetic. The 6 tests pass unchanged.
- Availability tests: Claude no-plugin → false, effective-plugin fixture → true;
  the two Resolve tests use an explicit Codex config instead of ambient Claude.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@realtonyyoung
realtonyyoung merged commit 6432e8a into main Aug 13, 2026
6 checks passed
@realtonyyoung
realtonyyoung deleted the tonyyoung/ai-1915-workitems-nudge branch August 13, 2026 00:26
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