You can define shell commands to run before and after structure generation using the pre_hooks and post_hooks keys in your YAML configuration. These are optional and allow you to automate setup or cleanup steps.
Hooks execute shell commands with shell=True, which can be powerful but also risky. StructKit provides several safety mechanisms:
- Interactive Confirmation: When running interactively, StructKit prompts for confirmation before executing hooks
- Skip Hooks: Use
--no-hooksflag orSTRUCTKIT_NO_HOOKS=trueto disable all hooks - Allowlist: Create a
.struct-hooks-allowlistfile to restrict which commands can run - MCP Safety: MCP calls skip hooks by default (
no_hooks=true)
- pre_hooks: List of shell commands to run before generation. If any command fails (non-zero exit), generation is aborted.
- post_hooks: List of shell commands to run after generation completes. If any command fails, an error is shown.
pre_hooks:
- echo "Preparing environment..."
- ./scripts/prep.sh
post_hooks:
- echo "Generation complete!"
- ./scripts/cleanup.sh
files:
- README.md:
content: |
# My Project- Execute in the order defined
- Run before any files or folders are created
- If any command returns non-zero exit code, generation stops
- Useful for environment preparation, validation, or dependency checks
- Execute after all files and folders are created
- Run even if some file operations fail
- Errors are reported but don't stop execution
- Useful for cleanup, initialization, or notification tasks
- Output from hooks (stdout and stderr) is shown in the terminal
- Hook execution is logged with appropriate log levels
- Failed hooks display error messages with exit codes
pre_hooks:
- python -m venv .venv
- source .venv/bin/activate
- pip install --upgrade pip
post_hooks:
- source .venv/bin/activate
- pip install -r requirements.txt
- echo "Virtual environment ready!"
files:
- requirements.txt:
content: |
flask==2.3.0
requests==2.31.0pre_hooks:
- git --version # Verify git is available
post_hooks:
- git init
- git add .
- git commit -m "Initial commit from StructKit"
- echo "Git repository initialized"
files:
- .gitignore:
file: github://github/gitignore/main/Python.gitignore
- README.md:
content: |
# {{@ project_name @}}
Generated with StructKitpre_hooks:
- docker --version
- echo "Setting up Docker environment..."
post_hooks:
- docker build -t {{@ project_name | slugify @}} .
- echo "Docker image built successfully"
files:
- Dockerfile:
content: |
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
- docker-compose.yml:
content: |
version: '3.8'
services:
app:
build: .
ports:
- "8000:8000"pre_hooks:
- echo "Checking database connection..."
- pg_isready -h localhost -p 5432
post_hooks:
- python manage.py migrate
- python manage.py collectstatic --noinput
- echo "Database migrations complete"
files:
- manage.py:
content: |
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)pre_hooks:
- echo "Validating prerequisites..."
- node --version
- npm --version
post_hooks:
- npm install
- npm run lint
- npm test
- echo "All tests passed!"
files:
- package.json:
content: |
{
"name": "{{@ project_name | slugify @}}",
"version": "1.0.0",
"scripts": {
"test": "jest",
"lint": "eslint src/"
}
}You can disable hooks entirely using the --no-hooks flag or environment variable:
# Using CLI flag
structkit generate .struct.yaml --no-hooks
# Using environment variable
export STRUCTKIT_NO_HOOKS=true
structkit generate .struct.yamlThis is recommended for:
- CI/CD pipelines where hooks shouldn't run
- MCP/automation contexts
- Untrusted structure definitions
By default, StructKit prompts for confirmation before running hooks in interactive mode:
$ structkit generate .struct.yaml
⚠️ The following pre-hooks will be executed:
- echo "Preparing environment..."
- ./scripts/prep.sh
Do you want to run these pre-hooks? [y/N]:To skip the prompt:
- Use
--non-interactiveflag - Set
STRUCTKIT_NON_INTERACTIVE=true
Note: Non-interactive mode without --no-hooks will execute hooks without confirmation.
Create a .struct-hooks-allowlist file in your project directory to restrict which commands can run:
# .struct-hooks-allowlist
# One command per line. Lines starting with # are comments.
echo
git
npm
python
./scripts/prep.sh
./scripts/cleanup.sh
When an allowlist exists:
- Only commands in the allowlist can run
- Both exact matches and base commands (first word) are checked
- Blocked hooks cause generation to fail
You can also specify a custom allowlist path:
structkit generate .struct.yaml --hooks-allowlist /path/to/allowlist.txt
# Or via environment variable
export STRUCTKIT_HOOKS_ALLOWLIST=/path/to/allowlist.txt
structkit generate .struct.yamlWhen using StructKit through MCP (Model Context Protocol), hooks are disabled by default for security:
{
"name": "generate_structure",
"arguments": {
"structure_definition": "project/python",
"base_path": "/tmp/myproject",
"no_hooks": true // Default for MCP calls
}
}To enable hooks in MCP calls (not recommended), explicitly set no_hooks: false.
- Keep hooks simple: Use external scripts for complex operations
- Handle errors gracefully: Check for tool availability in pre-hooks
- Use absolute paths: Hooks run in the target directory context
- Log important actions: Use echo statements for user feedback
- Test independently: Ensure hook commands work outside StructKit
- Consider dependencies: Order hooks based on their requirements
- Use allowlists: For production environments, always use an allowlist
- Disable in CI/CD: Use
--no-hooksin automated environments unless hooks are required and safe
pre_hooks:
- echo "Checking Python version..."
- python --version || (echo "Python not found!" && exit 1)
- echo "Python check passed"post_hooks:
- npm install || echo "Warning: npm install failed"
- git add . || echo "Warning: git add failed"
- echo "Setup complete (some warnings may have occurred)"# .struct.yaml
pre_hooks:
- echo "Preparing environment..."
- python -c "import sys; print(sys.version)"
post_hooks:
- echo "Generation complete!"
- git --version
files:
- README.md:
content: |
# My Project# .struct-hooks-allowlist
echo
python
git
With this setup:
- Only
echo,python, andgitcommands can run - Interactive users will be prompted for confirmation
- Use
--no-hooksto skip entirely - Use
--non-interactiveto run without prompts (requires allowlist or trust)
You can use template variables in hook commands:
pre_hooks:
- echo "Setting up {{@ project_name @}}"
- mkdir -p "{{@ project_name | slugify @}}"
post_hooks:
- echo "{{@ project_name @}} setup complete!"
- echo "Project created in: $(pwd)"
variables:
- project_name:
description: "Name of the project"
type: string
default: "MyProject"