[Bug]: preset-provided scripts are never resolved — `type: script` and `$CORE_SCRIPT` have no effect
Maintainer antworten meist innerhalb von 1 Tag
Bewertung
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Anfängerfreundlichkeit
- 58/100
Rechercherichtung
Beginne mit dem aufgeführten Scaffold und der Reproduktion des Re-Scaffoldings und verfolge dann den Aufrufer in specify_cli/presets/_commands.py:495 bis zur Skriptverarbeitung in specify_cli/presets/init.py. Vergleiche die .md-only-Auflösungspfade in core_pack/scripts/bash/common.sh:509 und core_pack/scripts/python/common.py:308 mit der vorhandenen Logik zur Skriptkomposition und ihrer Unit-Test-Abdeckung. Als erledigt gilt die Aufgabe, wenn das dokumentierte Skriptverhalten von Ende zu Ende funktioniert oder nicht unterstützte Skriptdeklarationen abgewiesen und die Dokumentation korrigiert werden.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Bug Description
The preset reference documents scripts as a first-class layer of the resolution stack:
"Presets can provide command files, template files (like
plan-template.md), and script files.
Templates and scripts are looked up from the stack when Spec Kit needs them.
Scripts support replace and wrap; script wrappers use$CORE_SCRIPTas the placeholder."
and lists the project-local override location as .specify/templates/overrides/scripts/.
None of this takes effect. A preset may declare type: script, and specify preset add accepts and
installs it without complaint, but nothing ever asks the resolver for a script, so the file that
actually runs is always the core one.
Three independent places in the shipped code show why:
- No caller requests the script type. The only production call into preset composition
determines the type as
template_type = "command" if is_command else "template"
(specify_cli/presets/_commands.py:495). The value"script"is never passed, so
PresetResolver.resolve()/collect_all_layers()are never invoked for scripts — even though
both handletemplate_type == "script"(specify_cli/presets/__init__.py:5524,5531,5613,
and the$CORE_SCRIPTsubstitution at:6168). - The Bash runtime resolves only
.md.resolve_template()in
core_pack/scripts/bash/common.sh:509looks for"$base/overrides/${template_name}.md", and
every subsequent tier appends.mdas well. There is no.shbranch and no
overrides/scripts/lookup anywhere in the file. - The Python twin mirrors that.
core_pack/scripts/python/common.py:308documents its order as
"mirrors resolve_template in scripts/bash/common.sh" and resolves
overrides/f"{template_name}.md"only.
So the composition engine for scripts exists and is reachable by unit test, but is not wired to
anything that runs.
This looks like the script half of #2132 / #2133 never landed on the runtime side, while #3143
documented it as shipped. I could not find an existing report: no open issue or PR with "script" in
the title covers it (#1964 is adjacent but is about extensions and has been open since March 2026),
and #4443 / #4445 concern PyYAML availability, not resolution.
runs the command.
Suggestion. Either wire a caller for template_type="script" and add .sh resolution to
common.sh and its Python twin, or — if scripts are not meant to be resolvable yet — adjust
docs/reference/presets.md and have preset.yml validation reject type: script so the
declaration fails loudly instead of silently.
Steps to Reproduce
# 1. Scaffold a project
mkdir demo && cd demo && git init
specify init . --integration claude --script sh --force
# 2. Record the core script's hash
sha256sum .specify/scripts/bash/setup-plan.sh
# 3a. Try the documented project-local override
mkdir -p .specify/templates/overrides/scripts
printf '#!/usr/bin/env bash\necho "OVERRIDE RAN"\n' \
> .specify/templates/overrides/scripts/setup-plan.sh
chmod +x .specify/templates/overrides/scripts/setup-plan.sh
# 3b. Or try a preset that provides the script
mkdir -p /tmp/p/scripts
cat > /tmp/p/preset.yml <<'YAML'
schema_version: "1.0"
preset:
id: "gate"
name: "Gate"
version: "1.0.0"
description: "Wraps setup-plan."
requires:
speckit_version: ">=1.0.0"
provides:
templates:
- type: "script"
name: "setup-plan"
file: "scripts/setup-plan.sh"
strategy: "wrap"
YAML
printf '#!/usr/bin/env bash\necho "BEFORE"\n$CORE_SCRIPT "$@"\n' > /tmp/p/scripts/setup-plan.sh
specify preset add --dev /tmp/p
# 4. Re-scaffold and compare
specify init . --integration claude --script sh --force
sha256sum .specify/scripts/bash/setup-plan.sh
Expected Behavior
.specify/scripts/bash/setup-plan.sh is composed from the stack, so the wrapper runs first and
delegates to the core script through $CORE_SCRIPT — matching the documented behaviour that
"templates and scripts are looked up from the stack when Spec Kit needs them".
Actual Behavior
The hash in step 4 is identical to step 2 and still matches
.specify/integrations/speckit.manifest.json. The override file and the preset-provided script are
never read. specify preset add reports success and specify preset list shows the preset as
enabled, so there is no signal that the declared script is inert.
Tried additionally, all without effect: strategy: replace as well as wrap,
specify integration upgrade, specify init --here --force. Same result on 1.0.1.
Specify CLI Version
1.0.6
AI Agent
Claude Code
Operating System
macOS 26.6.2
Python Version
Python 3.11.15
Error Logs
# There is no error output — that is part of the problem.
# A preset declaring a script installs cleanly and is reported as active:
$ specify preset add --dev /tmp/p
Installing preset from /tmp/p...
✓ Preset 'Gate' v1.0.0 installed (priority 10)
$ specify preset list
Installed Presets (in resolution order — highest precedence first)
Gate (gate) v1.0.0 — enabled — priority 10
Wraps setup-plan.
Templates: 1
# …while the script it provides is never resolved or executed.
Additional Context
Why this matters. The documented mechanism is the natural way to add a step in front of a core
script: the preset wraps setup-plan.sh, the core script stays untouched underneath, and Spec Kit
maintains the relationship. Any preset that needs to run a check, a fetch, or a validation before
the command body reads its inputs wants exactly this.
Current workaround, for anyone hitting the same wall. Override the command instead of the
script. A preset providing speckit.plan with strategy: "wrap" and a five-line body:
---
scripts:
sh: scripts/bash/setup-plan-wrapper.sh --json
---
{CORE_TEMPLATE}
points the materialised command at a project-owned script, which ends with
exec "$ROOT/.specify/scripts/bash/setup-plan.sh" "$@". This works and survives upgrades, because
{CORE_TEMPLATE} keeps pulling the command body from core.
It has two costs that the documented mechanism would remove:
- two artefacts instead of one. The script cannot travel inside the preset, so it lives beside
it as a separate committed file, and it needs a distinct filename because it cannot replace
setup-plan.sh. - nothing validates the link. A preset whose frontmatter names a script that does not exist
installs without any warning and is listed as healthy; the dead path only surfaces when a user
runs the command.
Suggestion. Either wire a caller fortemplate_type="script"and add.shresolution to
common.shand its Python twin, or — if scripts are not meant to be resolvable yet — adjust
docs/reference/presets.mdand havepreset.ymlvalidation rejecttype: scriptso the
declaration fails loudly instead of silently.
- Vorherrschende Sprache
- Python
- Sterne
- 140k
- Forks
- 12.6k
- Ø Merge
- 2 T. 11 Std.
- Gemergte PRs (30 T.)
- 186
Entwicklungsumgebung
Startet den Dev-Container des Projekts im Browser, mit Ihrem eigenen GitHub-Konto.
- Kein Dockerfile und keine Docker-Compose-Datei
- Hat eine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus github/spec-kit
-
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 66/100
Maintainer antworten meist innerhalb von 1 Tag
-
feature-assess feature-go triage-can-wait
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
github/spec-kit#4804 · 6 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
-
needs-triage triage-nice-to-have
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
github/spec-kit#4527 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
[Bug]: specify init writes speckit.manifest.json without the speckit-converge skill it just installedEvtl. wieder frei Ein Pull Request dazu wurde ohne Merge geschlossen. Offenbug-assess severity-medium
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
github/spec-kit#4273 · 3 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
-
[Bug]: /speckit-implement counts checkbox markers inside fenced code blocks — example checkboxes can falsely block implementationEvtl. vergeben @ntdatt812 hat das vor 31 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 84/100
Maintainer antworten meist innerhalb von 1 Tag
Alle Issues in github/spec-kit
Ähnliche Issues
-
Schwierigkeit 1/5 1-3 Stunden Anfängerfreundlichkeit 87/100
adri0/scadustats#128 ·
Maintainer antworten meist innerhalb von 1 Tag
-
`TIMESTAMP`, `TIMESTAMP_NTZ`, `TINYINT` and the other `TypeDecorator`s don't declare `python_type`Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
-
RPBCOffenawaiting policy acceptance precheck-passed
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 78/100
Bioconductor/BiocContributions#240 · 1 Kommentar ·
-
bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
Maintainer antworten meist innerhalb von 1 Tag
-
documentation good first issue launch
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 83/100
FlologixAI/etchwork#4 ·