fix(#3151): stop emitting effort: into skill frontmatter (cache invalidation) (#3425)

Claude Code applies SKILL.md effort: as output_config.effort; any change from
the session baseline invalidates the prompt cache at BOTH scope boundaries
(entry + exit, the latter often machine-fired via subagent-completion
notification). The reporter's owned measurement confirms it: /gsd-progress
(effort:low) in a medium session → cache_creation 63,404 (entry) + 18,589
(exit), while a no-effort skill shows none. ~76% of invocations paid in full.

Fix (trek-e AC#2/AC#4): convertClaudeCommandToClaudeSkill no longer emits
effort: into Claude-runtime skill frontmatter (src/runtime-artifact-conversion.cts
+ duplicated bin/install.js). normalizeClaudeSkillEffort removed (dead). The six
declaring skills (plan-phase/execute-phase/autonomous/next/progress/stats) no
longer carry effort. Source command files keep effort (input, used elsewhere);
the separate agent-effort surface (#3160) is untouched.

Tests: install-runtime-artifacts #769 block flipped to assert effort is ABSENT
from installed SKILL.md + converter output (the AC#4 behavioral coverage).

Co-authored-by: sim <sim@local>
This commit is contained in:
Tom Boucher
2026-08-13 22:00:26 -04:00
committed by GitHub
parent d30c99bc92
commit b9adedbc86
13 changed files with 118 additions and 262 deletions

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3425
---
**GSD skills no longer override the caller's effort level** (#3151) — invoking `/gsd-plan-phase`, `/gsd-execute-phase`, `/gsd-autonomous`, `/gsd-next`, `/gsd-progress`, or `/gsd-stats` previously set `output_config.effort` to a static value baked into the skill frontmatter; when that differed from the session's effort (which it did ~76% of the time), it invalidated the entire prompt cache at both scope boundaries (skill entry and exit). These skills now run at the session's existing effort level (no `effort:` emitted into SKILL.md). The elevated-effort intent is preserved on the source command files; only the skill-frontmatter emission is dropped. The separate agent-effort surface is unaffected.

View File

@@ -2091,12 +2091,6 @@ function skillFrontmatterName(skillDirName) {
return skillDirName;
}
function normalizeClaudeSkillEffort(effort) {
// #3039: `max` is rejected by Anthropic models when extended thinking is disabled.
if (effort === 'xhigh' || effort === 'max') return 'high';
return effort;
}
/**
* Qwen Code skills accept an optional numeric `priority` frontmatter field.
* Per the Qwen skills spec (qwen-code/docs/users/features/skills.md, verified
@@ -2153,10 +2147,11 @@ function convertClaudeCommandToClaudeSkill(content, skillName, runtime = null, c
const description = extractFrontmatterField(frontmatter, 'description') || '';
const argumentHint = extractFrontmatterField(frontmatter, 'argument-hint');
const agent = extractFrontmatterField(frontmatter, 'agent');
// #769: preserve context: and effort: from source command files so they
// are emitted into the installed SKILL.md frontmatter unchanged.
// #769: preserve context: from source command files so it is emitted into
// the installed SKILL.md frontmatter unchanged. (#3151: effort: is no longer
// emitted into skill frontmatter — a static effort value invalidates the
// caller's prompt cache at both scope boundaries.)
const context = extractFrontmatterField(frontmatter, 'context');
const effort = extractFrontmatterField(frontmatter, 'effort');
// Preserve allowed-tools as YAML multiline list (Claude native format)
const toolsMatch = frontmatter.match(/^allowed-tools:\s*\n((?:\s+-\s+.+\n?)*)/m);
@@ -2190,12 +2185,13 @@ function convertClaudeCommandToClaudeSkill(content, skillName, runtime = null, c
}
if (argumentHint) fm += `argument-hint: ${yamlQuote(argumentHint)}\n`;
if (agent) fm += `agent: ${agent}\n`;
// #769: emit context: and effort: when present so the runtime can honour
// them natively (context: fork = isolated subagent window; effort: =
// token-budget tier). Fields are Claude-specific; unknown frontmatter
// fields are silently ignored by other runtimes (backward-compatible).
// #769: emit context: when present so the runtime can honour it natively
// (context: fork = isolated subagent window). Claude-specific; unknown
// frontmatter fields are silently ignored by other runtimes (backward-compatible).
// (#3151: effort: is intentionally NOT emitted into skill frontmatter — a
// static effort value changes output_config.effort on invocation and
// invalidates the caller's prompt cache at both scope boundaries.)
if (context) fm += `context: ${context}\n`;
if (effort) fm += `effort: ${normalizeClaudeSkillEffort(effort)}\n`;
if (toolsBlock) fm += toolsBlock;
fm += '---';

View File

@@ -2,7 +2,6 @@
name: gsd-autonomous
description: "Run all remaining phases autonomously — discuss→plan→execute per phase"
argument-hint: "[--from N] [--to N] [--only N] [--interactive] [--converge]"
effort: high
allowed-tools:
- Read
- Write

View File

@@ -2,7 +2,6 @@
name: gsd-execute-phase
description: "Execute all plans in a phase with wave-based parallelization"
argument-hint: "<phase-number> [--wave N] [--gaps-only] [--interactive] [--tdd]"
effort: high
allowed-tools:
- Read
- Write

View File

@@ -1,7 +1,6 @@
---
name: gsd-next
description: "Smart entry — detect project state and route to the right next GSD action."
effort: low
allowed-tools:
- Read
- Bash

View File

@@ -2,7 +2,6 @@
name: gsd-plan-phase
description: "Create detailed phase plan (PLAN.md) with verification loop"
argument-hint: "[phase] [--auto] [--research] [--skip-research] [--research-phase <N>] [--view] [--gaps] [--skip-verify] [--skip-ui] [--prd <file>] [--ingest <path-or-glob>] [--ingest-format <auto|nygard|madr|narrative>] [--reviews] [--text] [--bounce] [--skip-bounce] [--chunked] [--tdd] [--mvp] [--granularity <coarse|standard|fine>] [--no-tracer] [--no-reversibility-gates]"
effort: high
allowed-tools:
- Read
- Write

View File

@@ -2,7 +2,6 @@
name: gsd-progress
description: "Check progress, advance workflow, or dispatch freeform intent — the unified GSD situational command"
argument-hint: "[--forensic | --next [--auto] [--converge] | --do \\\"task description\\\"]"
effort: low
allowed-tools:
- Read
- Bash

View File

@@ -1,7 +1,6 @@
---
name: gsd-stats
description: "Display project statistics — phases, plans, requirements, git metrics, and timeline"
effort: low
allowed-tools:
- Read
- Bash

View File

@@ -392,16 +392,6 @@ function skillFrontmatterName(skillDirName) {
return skillDirName;
}
function normalizeClaudeSkillEffort(effort) {
// #3039: `max` is rejected by Anthropic models when extended thinking is
// disabled (400: output_config.effort 'max' is not supported when thinking
// is disabled). The frontmatter is static at install time and the installer
// cannot know whether thinking will be on or off at invocation. `high` is the
// maximum value that works in both states on all supported models.
if (effort === 'xhigh' || effort === 'max') return 'high';
return effort;
}
/**
* Qwen Code skills accept an optional numeric `priority` frontmatter field.
* Per the Qwen skills spec (qwen-code/docs/users/features/skills.md, verified
@@ -458,10 +448,13 @@ function convertClaudeCommandToClaudeSkill(content, skillName, runtime = null, c
const description = extractFrontmatterField(frontmatter, 'description') || '';
const argumentHint = extractFrontmatterField(frontmatter, 'argument-hint');
const agent = extractFrontmatterField(frontmatter, 'agent');
// #769: preserve context: and effort: from source command files so they
// are emitted into the installed SKILL.md frontmatter unchanged.
// #769: preserve context: from source command files so it is emitted into
// the installed SKILL.md frontmatter unchanged. (#3151: effort: is no longer
// emitted into skill frontmatter — a static effort value changes
// output_config.effort on invocation and invalidates the caller's prompt
// cache at both scope boundaries; the reporter's owned measurement confirms
// the mechanism. The separate agent-effort surface is tracked by #3160.)
const context = extractFrontmatterField(frontmatter, 'context');
const effort = extractFrontmatterField(frontmatter, 'effort');
// Preserve allowed-tools as YAML multiline list (Claude native format)
const toolsMatch = frontmatter.match(/^allowed-tools:\s*\n((?:\s+-\s+.+\n?)*)/m);
@@ -498,12 +491,13 @@ function convertClaudeCommandToClaudeSkill(content, skillName, runtime = null, c
}
if (argumentHint) fm += `argument-hint: ${yamlQuote(argumentHint)}\n`;
if (agent) fm += `agent: ${agent}\n`;
// #769: emit context: and effort: when present so the runtime can honour
// them natively (context: fork = isolated subagent window; effort: =
// token-budget tier). Fields are Claude-specific; unknown frontmatter
// fields are silently ignored by other runtimes (backward-compatible).
// #769: emit context: when present so the runtime can honour it natively
// (context: fork = isolated subagent window). Claude-specific; unknown
// frontmatter fields are silently ignored by other runtimes (backward-compatible).
// (#3151: effort: is intentionally NOT emitted into skill frontmatter — a
// static effort value changes output_config.effort on invocation and
// invalidates the caller's prompt cache at both scope boundaries.)
if (context) fm += `context: ${context}\n`;
if (effort) fm += `effort: ${normalizeClaudeSkillEffort(effort)}\n`;
if (toolsBlock) fm += toolsBlock;
fm += '---';

View File

@@ -1,147 +0,0 @@
{
"version": 1,
"paths": {
"commands/gsd-add-tests.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-ai-integration-phase.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-audit-fix.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-audit-milestone.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-audit-uat.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-autonomous.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-capture.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-cleanup.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-code-review.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-complete-milestone.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-config.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-debug.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-discuss-phase.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-docs-update.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-eval-review.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-execute-phase.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-explore.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-extract-learnings.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-fast.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-forensics.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-graphify.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-health.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-help.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-import.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-inbox.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-ingest-docs.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-manager.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-map-codebase.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-mempalace-capture.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-mempalace-recall.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-milestone-summary.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-mvp-phase.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-new-milestone.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-new-project.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-next.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-ns-context.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-ns-ideate.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-ns-manage.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-ns-project.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-ns-review.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-ns-workflow.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-onboard.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-pause-work.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-phase.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-plan-phase.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-plan-review-convergence.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-pr-branch.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-profile-user.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-progress.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-quick.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-resume-work.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-review-backlog.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-review.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-secure-phase.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-settings.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-ship.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-sketch.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-spec-phase.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-spike.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-stats.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-surface.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-thread.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-ui-phase.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-ui-review.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-ultraplan-phase.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-undo.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-update.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-validate-phase.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-verify-work.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-workspace.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"commands/gsd-workstreams.md": "Cursor deliberately retires its duplicate commands surface in favor of skills (#2644).",
"skills/gsd-add-tests/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-ai-integration-phase/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-audit-fix/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-audit-milestone/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-audit-uat/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-autonomous/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644). #3039: normalizeClaudeSkillEffort clamps max to high \u2014 this Claude-runtime SKILL.md now carries effort: high instead of effort: max.",
"skills/gsd-capture/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-cleanup/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-code-review/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-complete-milestone/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-config/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-debug/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-discuss-phase/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-docs-update/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-eval-review/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-execute-phase/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644). #3039: normalizeClaudeSkillEffort clamps max to high \u2014 this Claude-runtime SKILL.md now carries effort: high instead of effort: max.",
"skills/gsd-explore/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-extract-learnings/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-fast/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-forensics/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-graphify/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-health/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-help/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-import/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-inbox/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-ingest-docs/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-manager/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-map-codebase/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-mempalace-capture/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-mempalace-recall/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-milestone-summary/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-mvp-phase/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-new-milestone/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-new-project/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-next/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-ns-context/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-ns-ideate/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-ns-manage/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-ns-project/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-ns-review/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-ns-workflow/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-onboard/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-pause-work/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-phase/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-plan-phase/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644). #3039: normalizeClaudeSkillEffort clamps max to high \u2014 this Claude-runtime SKILL.md now carries effort: high instead of effort: max.",
"skills/gsd-plan-review-convergence/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-pr-branch/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-profile-user/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-progress/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-quick/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-resume-work/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-review-backlog/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-review/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-secure-phase/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-settings/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-ship/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-sketch/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-spec-phase/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-spike/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-stats/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-surface/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-thread/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-ui-phase/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-ui-review/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-ultraplan-phase/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-undo/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-update/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-validate-phase/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-verify-work/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-workspace/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644).",
"skills/gsd-workstreams/SKILL.md": "Cursor skill frontmatter deliberately drops the unsupported user-invocable field while retaining model invocation (#2644)."
}
}

View File

@@ -1,11 +0,0 @@
{
"version": 1,
"paths": {
"skills/gsd-ns-workflow/skills/autonomous/SKILL.md": "#3039: normalizeClaudeSkillEffort now clamps max/xhigh to high \u2014 every emitted SKILL.md that carried effort: max now carries effort: high (max rejected by Anthropic when thinking disabled).",
"skills/gsd-ns-workflow/skills/execute-phase/SKILL.md": "#3039: normalizeClaudeSkillEffort now clamps max/xhigh to high \u2014 every emitted SKILL.md that carried effort: max now carries effort: high (max rejected by Anthropic when thinking disabled).",
"skills/gsd-ns-workflow/skills/plan-phase/SKILL.md": "#3039: normalizeClaudeSkillEffort now clamps max/xhigh to high \u2014 every emitted SKILL.md that carried effort: max now carries effort: high (max rejected by Anthropic when thinking disabled).",
"skills/gsd/gsd-ns-workflow/skills/autonomous/SKILL.md": "#3039: normalizeClaudeSkillEffort now clamps max/xhigh to high \u2014 every emitted SKILL.md that carried effort: max now carries effort: high (max rejected by Anthropic when thinking disabled).",
"skills/gsd/gsd-ns-workflow/skills/execute-phase/SKILL.md": "#3039: normalizeClaudeSkillEffort now clamps max/xhigh to high \u2014 every emitted SKILL.md that carried effort: max now carries effort: high (max rejected by Anthropic when thinking disabled).",
"skills/gsd/gsd-ns-workflow/skills/plan-phase/SKILL.md": "#3039: normalizeClaudeSkillEffort now clamps max/xhigh to high \u2014 every emitted SKILL.md that carried effort: max now carries effort: high (max rejected by Anthropic when thinking disabled)."
}
}

View File

@@ -0,0 +1,59 @@
{
"version": 1,
"paths": {
"skills/gsd-autonomous/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-execute-phase/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-next/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-ns-manage/skills/stats/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-ns-workflow/skills/autonomous/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-ns-workflow/skills/execute-phase/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-ns-workflow/skills/next/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-ns-workflow/skills/plan-phase/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-ns-workflow/skills/progress/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-plan-phase/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-progress/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd-stats/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd/gsd-ns-manage/skills/stats/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd/gsd-ns-workflow/skills/autonomous/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd/gsd-ns-workflow/skills/execute-phase/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd/gsd-ns-workflow/skills/next/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd/gsd-ns-workflow/skills/plan-phase/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
},
"skills/gsd/gsd-ns-workflow/skills/progress/SKILL.md": {
"reason": "#3151: convertClaudeCommandToClaudeSkill no longer emits effort: into skill frontmatter (a static effort value invalidates the caller's prompt cache at both scope boundaries). The converter (src/runtime-artifact-conversion.cts + duplicate bin/install.js) changed, moving these emitted skill hashes without a source-command change; this ack covers that converter-driven emission drop across all runtime layouts (per ADR-2719/#3039 precedent)."
}
}
}

View File

@@ -3388,50 +3388,22 @@ describe('#769/#1319 convertClaudeCommandToClaudeSkill: preserves context and em
`SKILL.md frontmatter must include context: fork\nActual frontmatter:\n${fm}`);
});
test('normalizes effort: xhigh/max to effort: high in emitted SKILL.md frontmatter (#1319/#3039)', () => {
const input = [
'---',
'name: gsd:test-heavy',
'description: Test heavy skill',
'context: fork',
'effort: xhigh',
'allowed-tools:',
' - Read',
' - Bash',
'---',
'',
'Heavy skill body.',
].join('\n');
const result = convertClaudeCommandToClaudeSkill(input, 'test-heavy');
const end = result.indexOf('---', 3);
const fm = result.substring(3, end);
assert.match(fm, /^effort:[ \t]*high$/m,
`SKILL.md frontmatter must include portable effort: high (#3039)\nActual frontmatter:\n${fm}`);
assert.doesNotMatch(fm, /^effort:[ \t]*(xhigh|max)$/m,
`SKILL.md frontmatter must not include rejected effort: xhigh or max (#1319/#3039)\nActual frontmatter:\n${fm}`);
});
test('preserves effort: low in emitted SKILL.md frontmatter', () => {
const input = [
'---',
'name: gsd:test-light',
'description: Test light skill',
'effort: low',
'allowed-tools:',
' - Read',
'---',
'',
'Light skill body.',
].join('\n');
const result = convertClaudeCommandToClaudeSkill(input, 'test-light');
const end = result.indexOf('---', 3);
const fm = result.substring(3, end);
assert.match(fm, /^effort:[ \t]*low$/m,
`SKILL.md frontmatter must include effort: low\nActual frontmatter:\n${fm}`);
test('#3151: does NOT emit effort: into SKILL.md frontmatter (a static effort value invalidates the caller\'s prompt cache)', () => {
// Whatever effort the source command declares, the installed SKILL.md must
// NOT carry it: Claude Code applies SKILL.md `effort:` as output_config.effort,
// and any change from the session baseline invalidates the prompt cache at both
// scope boundaries (entry + exit). Verified by the reporter's owned measurement.
const inputs = [
['xhigh source', '---\nname: gsd:test-heavy\ndescription: Heavy\ncontext: fork\neffort: xhigh\nallowed-tools:\n - Read\n---\n\nBody.\n'],
['low source', '---\nname: gsd:test-light\ndescription: Light\neffort: low\nallowed-tools:\n - Read\n---\n\nBody.\n'],
];
for (const [label, input] of inputs) {
const result = convertClaudeCommandToClaudeSkill(input, label === 'xhigh source' ? 'test-heavy' : 'test-light');
const end = result.indexOf('---', 3);
const fm = result.substring(3, end);
assert.doesNotMatch(fm, /^effort:/m,
`SKILL.md frontmatter must NOT include effort: for ${label} (#3151)\nActual frontmatter:\n${fm}`);
}
});
test('does NOT emit context: or effort: when absent from source', () => {
@@ -3461,7 +3433,7 @@ describe('#769/#1319 convertClaudeCommandToClaudeSkill: preserves context and em
// #921/#922: after install, spawning orchestrators must NOT carry context: fork
// in their emitted SKILL.md. #1319: heavyweight skills must use portable max effort.
describe('#769/#921/#1319 Claude global install: spawning-orchestrator SKILL.md files have effort: high (clamped from max) but NOT context: fork', () => {
describe('#769/#921/#3151 Claude global install: SKILL.md files emit NO effort (#3151 — static effort invalidates caller cache) and NOT context: fork', () => {
let tmpDir;
let claudeHome;
@@ -3483,14 +3455,12 @@ describe('#769/#921/#1319 Claude global install: spawning-orchestrator SKILL.md
`gsd-autonomous is a spawning orchestrator; its SKILL.md must NOT have context: fork (#921)\nActual:\n${fm}`);
});
test('gsd-autonomous SKILL.md has effort: max after global install (#1319)', () => {
test('gsd-autonomous SKILL.md does NOT emit effort: after global install (#3151)', () => {
runClaudeGlobalInstall(claudeHome);
const skillPath = flatSkillPath(path.join(claudeHome, 'skills'),'autonomous');
const fm = readFrontmatter(skillPath);
assert.match(fm, /^effort:[ \t]*high$/m,
`gsd-autonomous SKILL.md must have effort: high\nActual:\n${fm}`);
assert.doesNotMatch(fm, /^effort:[ \t]*xhigh$/m,
`gsd-autonomous SKILL.md must not have rejected effort: xhigh or max (#1319/#3039)\nActual:\n${fm}`);
assert.doesNotMatch(fm, /^effort:/m,
`gsd-autonomous SKILL.md must NOT emit effort: (#3151 — a static value invalidates the caller's prompt cache)\nActual:\n${fm}`);
});
test('gsd-execute-phase SKILL.md does NOT have context: fork after global install (#921)', () => {
@@ -3501,14 +3471,12 @@ describe('#769/#921/#1319 Claude global install: spawning-orchestrator SKILL.md
`gsd-execute-phase is a spawning orchestrator; its SKILL.md must NOT have context: fork (#921)\nActual:\n${fm}`);
});
test('gsd-execute-phase SKILL.md has effort: max after global install (#1319)', () => {
test('gsd-execute-phase SKILL.md does NOT emit effort: after global install (#3151)', () => {
runClaudeGlobalInstall(claudeHome);
const skillPath = flatSkillPath(path.join(claudeHome, 'skills'),'execute-phase');
const fm = readFrontmatter(skillPath);
assert.match(fm, /^effort:[ \t]*high$/m,
`gsd-execute-phase SKILL.md must have effort: high\nActual:\n${fm}`);
assert.doesNotMatch(fm, /^effort:[ \t]*xhigh$/m,
`gsd-execute-phase SKILL.md must not have rejected effort: xhigh or max (#1319/#3039)\nActual:\n${fm}`);
assert.doesNotMatch(fm, /^effort:/m,
`gsd-execute-phase SKILL.md must NOT emit effort: (#3151)\nActual:\n${fm}`);
});
test('gsd-plan-phase SKILL.md does NOT have context: fork after global install (#921)', () => {
@@ -3519,30 +3487,28 @@ describe('#769/#921/#1319 Claude global install: spawning-orchestrator SKILL.md
`gsd-plan-phase is a spawning orchestrator; its SKILL.md must NOT have context: fork (#921)\nActual:\n${fm}`);
});
test('gsd-plan-phase SKILL.md has effort: max after global install (#1319)', () => {
test('gsd-plan-phase SKILL.md does NOT emit effort: after global install (#3151)', () => {
runClaudeGlobalInstall(claudeHome);
const skillPath = flatSkillPath(path.join(claudeHome, 'skills'),'plan-phase');
const fm = readFrontmatter(skillPath);
assert.match(fm, /^effort:[ \t]*high$/m,
`gsd-plan-phase SKILL.md must have effort: high\nActual:\n${fm}`);
assert.doesNotMatch(fm, /^effort:[ \t]*xhigh$/m,
`gsd-plan-phase SKILL.md must not have rejected effort: xhigh or max (#1319/#3039)\nActual:\n${fm}`);
assert.doesNotMatch(fm, /^effort:/m,
`gsd-plan-phase SKILL.md must NOT emit effort: (#3151)\nActual:\n${fm}`);
});
test('gsd-progress SKILL.md has effort: low after global install', () => {
test('gsd-progress SKILL.md does NOT emit effort: after global install (#3151)', () => {
runClaudeGlobalInstall(claudeHome);
const skillPath = flatSkillPath(path.join(claudeHome, 'skills'),'progress');
const fm = readFrontmatter(skillPath);
assert.match(fm, /^effort:[ \t]*low$/m,
`gsd-progress SKILL.md must have effort: low\nActual:\n${fm}`);
assert.doesNotMatch(fm, /^effort:/m,
`gsd-progress SKILL.md must NOT emit effort: (#3151)\nActual:\n${fm}`);
});
test('gsd-stats SKILL.md has effort: low after global install', () => {
test('gsd-stats SKILL.md does NOT emit effort: after global install (#3151)', () => {
runClaudeGlobalInstall(claudeHome);
const skillPath = flatSkillPath(path.join(claudeHome, 'skills'),'stats');
const fm = readFrontmatter(skillPath);
assert.match(fm, /^effort:[ \t]*low$/m,
`gsd-stats SKILL.md must have effort: low\nActual:\n${fm}`);
assert.doesNotMatch(fm, /^effort:/m,
`gsd-stats SKILL.md must NOT emit effort: (#3151)\nActual:\n${fm}`);
});
});
});