You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Bug: SPECS_DIR key in setup-plan.sh JSON output contains FEATURE_DIR value #4017
The JSON output of scripts/bash/setup-plan.sh exposes a key named SPECS_DIR but populates it with the $FEATURE_DIR value (the per-feature subdirectory, e.g. specs/001-my-feature) rather than the actual specs root directory (specs/).
Affected file
scripts/bash/setup-plan.sh
Bug locations
Line ~71 (jq path):
# Current (wrong):
--arg specs_dir "$FEATURE_DIR"# Should be:
--arg feature_dir "$FEATURE_DIR"
Line ~73 (jq JSON key):
# Current (wrong):'{FEATURE_SPEC:$feature_spec,IMPL_PLAN:$impl_plan,SPECS_DIR:$specs_dir,BRANCH:$branch}'# Should be:'{FEATURE_SPEC:$feature_spec,IMPL_PLAN:$impl_plan,FEATURE_DIR:$feature_dir,BRANCH:$branch}'
Line ~75 (printf fallback):
# Current (wrong):printf'{"FEATURE_SPEC":"%s","IMPL_PLAN":"%s","SPECS_DIR":"%s","BRANCH":"%s"}\n'# Should be:printf'{"FEATURE_SPEC":"%s","IMPL_PLAN":"%s","FEATURE_DIR":"%s","BRANCH":"%s"}\n'
Line ~81 (text-mode output):
# Current (wrong):echo"SPECS_DIR: $FEATURE_DIR"# Should be:echo"FEATURE_DIR: $FEATURE_DIR"
Impact
Consumers of the JSON output who treat SPECS_DIR as the specs root directory will receive the wrong path instead of the feature subdirectory.
Fix
Rename the key from SPECS_DIR to FEATURE_DIR in all 4 locations listed above.
Confirmed on main. Adding some scope that the report misses — the same defect exists in the PowerShell and Python ports, and there is a consumer that has to move with it.
All three script implementations emit the mislabelled key:
Fixing only the four bash locations listed in the description would leave the three ports disagreeing with each other, which is worse than the current state.
setup-plan is the only script in the suite that uses this name. Every sibling emits FEATURE_DIR for exactly the same value:
scripts/bash/setup-tasks.sh:75 FEATURE_DIR:$feature_dir
scripts/bash/check-prerequisites.sh:122 FEATURE_DIR:$feature_dir
scripts/bash/check-prerequisites.sh:208 FEATURE_DIR:$feature_dir
scripts/bash/setup-plan.sh:75 SPECS_DIR:$specs_dir <-- odd one out
The name is also already taken, with a different meaning. In create-new-feature.sh:
SPECS_DIR="$REPO_ROOT/specs"# the specs root
FEATURE_DIR="$SPECS_DIR/$BRANCH_NAME"# one feature inside it
So SPECS_DIR means specs/ in one script and specs/001-my-feature/ in another.
There is one consumer, templates/commands/plan.md:62:
Run {SCRIPT} from repo root and parse JSON for FEATURE_SPEC, IMPL_PLAN, SPECS_DIR, BRANCH.
It has to be updated in the same change or /speckit.plan starts looking for a key that no longer exists. That makes the full surface 7 script locations across 3 languages, plus the template.
One decision worth settling before anyone writes code: the JSON output is a public-ish contract, so a straight rename is technically breaking for anyone parsing it outside this repo. Two options:
Rename outright — plan.md is the only in-repo consumer and ships alongside the scripts, so they stay in sync automatically. Clean, no lingering wart.
Emit FEATURE_DIR and keep SPECS_DIR as a deprecated alias for a release or two.
I lean towards (1), since the value was never the specs root and anything relying on it was already reading the wrong path. Happy to go with (2) if you would rather not break external parsers.
I am glad to put up a PR covering all three ports plus the template — just let me know which option you prefer.
Disclosure: I used an AI assistant (Claude) to help trace the call sites and draft this comment. The findings above were verified against main.
Covers the full surface rather than just the four bash lines — the same key is emitted by all three ports, plus templates/commands/plan.md, which parses it by name and would break if the scripts moved without it:
Verified all three variants now emit ['BRANCH', 'FEATURE_DIR', 'FEATURE_SPEC', 'IMPL_PLAN']. create-new-feature.sh is untouched, since SPECS_DIR correctly means the specs root there.
I went with the straight rename rather than a deprecated alias, for the reasons in the PR — happy to switch if you would rather not break external parsers.
Could you assign this issue to me so ownership is clear? Happy to revise on feedback.
Disclosure: I used an AI assistant (Claude) to help investigate this, implement the change, and draft this comment. The verification described above was produced by running the code, and I reviewed the change before submitting.
Activity
Yash-Chindam commentedon Sep 1, 2026
Confirmed on
main. Adding some scope that the report misses — the same defect exists in the PowerShell and Python ports, and there is a consumer that has to move with it.All three script implementations emit the mislabelled key:
Fixing only the four bash locations listed in the description would leave the three ports disagreeing with each other, which is worse than the current state.
setup-planis the only script in the suite that uses this name. Every sibling emitsFEATURE_DIRfor exactly the same value:The name is also already taken, with a different meaning. In
create-new-feature.sh:So
SPECS_DIRmeansspecs/in one script andspecs/001-my-feature/in another.There is one consumer,
templates/commands/plan.md:62:It has to be updated in the same change or
/speckit.planstarts looking for a key that no longer exists. That makes the full surface 7 script locations across 3 languages, plus the template.One decision worth settling before anyone writes code: the JSON output is a public-ish contract, so a straight rename is technically breaking for anyone parsing it outside this repo. Two options:
plan.mdis the only in-repo consumer and ships alongside the scripts, so they stay in sync automatically. Clean, no lingering wart.FEATURE_DIRand keepSPECS_DIRas a deprecated alias for a release or two.I lean towards (1), since the value was never the specs root and anything relying on it was already reading the wrong path. Happy to go with (2) if you would rather not break external parsers.
I am glad to put up a PR covering all three ports plus the template — just let me know which option you prefer.
Disclosure: I used an AI assistant (Claude) to help trace the call sites and draft this comment. The findings above were verified against
main.mnriem commentedon Sep 1, 2026
@Yash-Chindam Feel free to create a PR with a fix as I consider it a bug
Yash-Chindam commentedon Sep 1, 2026
PR up: #4397
Covers the full surface rather than just the four bash lines — the same key is emitted by all three ports, plus
templates/commands/plan.md, which parses it by name and would break if the scripts moved without it:Verified all three variants now emit
['BRANCH', 'FEATURE_DIR', 'FEATURE_SPEC', 'IMPL_PLAN'].create-new-feature.shis untouched, sinceSPECS_DIRcorrectly means the specs root there.I went with the straight rename rather than a deprecated alias, for the reasons in the PR — happy to switch if you would rather not break external parsers.
Could you assign this issue to me so ownership is clear? Happy to revise on feedback.
Disclosure: I used an AI assistant (Claude) to help investigate this, implement the change, and draft this comment. The verification described above was produced by running the code, and I reviewed the change before submitting.
fix(scripts): name setup-plan's feature directory key FEATURE_DIR
fix(scripts): name setup-plan's feature directory key FEATURE_DIR
fix(scripts): name setup-plan's feature directory key FEATURE_DIR (gi…