specify init does not copy templates/commands/ to .specify/templates/commands/
Problem
During specify init, the install_shared_infra function in shared_infra.py copies template files from the bundled templates/ directory to .specify/templates/. However, it only processes files at the top level (src.is_file() check), skipping subdirectories — specifically templates/commands/.
This means the core command templates (e.g., implement.md, specify.md, plan.md, etc.) are installed directly to the agent directory (e.g., .opencode/commands/speckit.implement.md) via the integration system, but they are not kept in .specify/templates/commands/ for the preset resolver to find.
Impact
Preset authors who use the wrap composition strategy for command overrides (e.g., wrapping speckit.implement with a preamble) cannot resolve the core command as a base layer. The PresetResolver.collect_all_layers() method looks for core commands at:
c = self.templates_dir / "commands" / f"{template_name}.md" # or stem fallback
Since .specify/templates/commands/ doesn't exist after specify init, the resolver finds no base layer, composition fails, and the command is silently not registered (registered_commands stays empty {}).
Reproduction
specify init --here --integration opencode --script sh --ignore-agent-tools
# .specify/templates/commands/ does NOT exist
# .opencode/commands/speckit.implement.md exists (installed by integration)
# Create a preset with a wrap strategy for speckit.implement
specify preset add --dev /path/to/my-preset
# registered_commands is {} — the wrap composition failed silently
Workaround
Manually copy command templates after init:
mkdir -p .specify/templates/commands
cp <spec-kit-source>/templates/commands/*.md .specify/templates/commands/
Suggested fix
In shared_infra.py, the install_shared_infra function should also copy the templates/commands/ subdirectory (with the same overwrite/manifest logic). Something like:
# After the top-level template files loop:
commands_src = templates_src / "commands"
if commands_src.is_dir():
dest_commands = dest_templates / "commands"
if _ensure_or_bucket_dir(dest_commands):
for src_path in commands_src.iterdir():
if not src_path.is_file() or src_path.name.startswith("."):
continue
dst = dest_commands / src_path.name
rel = dst.relative_to(project_path).as_posix()
# ... same overwrite/manifest logic as above ...
Alternatively, the PresetResolver could fall back to reading core commands from the agent directory (e.g., .opencode/commands/speckit.implement.md) when .specify/templates/commands/ doesn't have them.
Environment
- Spec Kit v0.11.3
- macOS Darwin arm64
- Integration: opencode
specify initdoes not copytemplates/commands/to.specify/templates/commands/Problem
During
specify init, theinstall_shared_infrafunction inshared_infra.pycopies template files from the bundledtemplates/directory to.specify/templates/. However, it only processes files at the top level (src.is_file()check), skipping subdirectories — specificallytemplates/commands/.This means the core command templates (e.g.,
implement.md,specify.md,plan.md, etc.) are installed directly to the agent directory (e.g.,.opencode/commands/speckit.implement.md) via the integration system, but they are not kept in.specify/templates/commands/for the preset resolver to find.Impact
Preset authors who use the
wrapcomposition strategy for command overrides (e.g., wrappingspeckit.implementwith a preamble) cannot resolve the core command as a base layer. ThePresetResolver.collect_all_layers()method looks for core commands at:Since
.specify/templates/commands/doesn't exist afterspecify init, the resolver finds no base layer, composition fails, and the command is silently not registered (registered_commandsstays empty{}).Reproduction
Workaround
Manually copy command templates after init:
Suggested fix
In
shared_infra.py, theinstall_shared_infrafunction should also copy thetemplates/commands/subdirectory (with the same overwrite/manifest logic). Something like:Alternatively, the
PresetResolvercould fall back to reading core commands from the agent directory (e.g.,.opencode/commands/speckit.implement.md) when.specify/templates/commands/doesn't have them.Environment