How Template Flattening Works in Spec-Kit: Extracting Nested Directory Structures

Template flattening in Spec-Kit collapses nested directory hierarchies into a single level by copying files using only their basename, discarding parent folder paths during release package generation.

Spec-Kit is an open-source CLI tool developed by GitHub that standardizes AI agent command templates across multiple platforms. When the project generates distribution packages for agents like Claude, Gemini, or OpenCode, it must extract command files from deeply nested source directories and consolidate them into flat release archives. This article explains how template flattening works when extracting these nested directory structures based on the actual implementation in the github/spec-kit repository.

The Flattening Implementation in release-packages.sh

The core logic resides in .github/workflows/scripts/create-release-packages.sh within the generate_commands function. This bash script processes hidden agent directories (e.g., .claude, .opencode) and flattens their nested command structures into a single output directory.

The function executes four distinct operations:

  1. Locate the agent directory using find to discover hidden folders matching the agent name pattern
  2. Resolve the command subdirectory by extracting the commands_subdir value from src/specify_cli/__init__.py using grep and awk
  3. Recursively find template files matching *.md or *.toml extensions within the command subdirectory
  4. Flatten and copy each file to the destination using basename to strip directory paths

The Basename Technique

The critical operation that enables flattening occurs in the file copy command:

cp "$file" "$dest_dir/$(basename "$file")"

By wrapping the source file path in $(basename ...), the command discards all parent directory information. Regardless of whether a file resides at .claude/commands/implement/spec.md or .claude/commands/spec.md, the output becomes simply spec.md in the destination folder.

Source Configuration and Agent Detection

The script dynamically determines where command templates live by reading configuration from the Python source. In src/specify_cli/__init__.py, the AGENT_CONFIG dictionary defines the commands_subdir path for each supported agent.

The release script extracts this value at runtime:

command_subdir=$(grep -i "commands_subdir" -R "${BASE_DIR}/src/specify_cli/__init__.py" | awk -F'"' '{print $2}')
command_subdir=${command_subdir:-commands}

If the grep fails to locate the configuration, the script defaults to "commands" as the subdirectory name. This flexibility allows Spec-Kit to support agents like cursor-agent, windsurf, kiro-cli, claude, gemini, copilot, qwen, and opencode while maintaining a consistent flattening behavior.

Practical Example: Before and After Flattening

Consider the source structure for the OpenCode agent:


.opencode/
└── commands/
    ├── implement/
    │   └── feature-spec.md
    └── refactor/
        └── code-cleanup.md

After running generate_commands with the flattening logic:


opencode-package/
├── feature-spec.md
└── code-cleanup.md

The nested folders implement/ and refactor/ are eliminated, while the Markdown files surface at the package root. This flat structure ensures downstream distribution archives contain only the essential template files without redundant directory nesting.

Summary

  • Template flattening occurs during release package generation in .github/workflows/scripts/create-release-packages.sh
  • The generate_commands function uses find to locate agent-specific command templates
  • File paths are flattened using the basename shell command when copying to the destination directory
  • Configuration for subdirectory paths is extracted from src/specify_cli/__init__.py at build time
  • Supported agents include Claude, Gemini, Copilot, Cursor, Qwen, OpenCode, Windsurf, and Kiro CLI

Frequently Asked Questions

What is template flattening in Spec-Kit?

Template flattening is the process of removing directory hierarchy from nested command templates when creating release packages. Spec-Kit stores agent commands in organized subdirectories during development, but distributes them as a flat list of files to simplify installation and usage.

Which file types does the flattening process handle?

The release script specifically targets Markdown (.md) and TOML (.toml) files within agent command directories. The find command uses the pattern -name "*.md" -o -name "*.toml" to filter relevant templates while ignoring other file types.

How does Spec-Kit prevent filename collisions during flattening?

The current implementation does not explicitly handle duplicate basenames in the source analysis provided. If two files share identical names in different subdirectories, such as commands/build/spec.md and commands/deploy/spec.md, the second copy operation would overwrite the first. The repository structure avoids such collisions through unique naming conventions for each command template.

Where is the command subdirectory configuration defined?

The subdirectory path is defined in the AGENT_CONFIG dictionary within src/specify_cli/__init__.py under the key commands_subdir. The release script extracts this value using grep, defaulting to "commands" if the configuration cannot be parsed.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →