* feat(dev): add integration scaffolder * fix(dev): address integration scaffold review feedback * fix(dev): address scaffold follow-up review * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * fix(dev): default scaffolded integrations to multi_install_safe = False The scaffold template emitted `multi_install_safe = True` alongside a placeholder `context_file = "AGENTS.md"`. Registered as-is, that violates the registry contract (test_safe_integrations_have_distinct_context_files): codex already pairs AGENTS.md with multi_install_safe = True, so the generated boilerplate would collide on first registration. Default the scaffold to False (matching IntegrationBase) so generated code is registry-test-friendly out of the box; contributors opt in once they pick a unique context_file. Aligns the generated test skeleton and both scaffold tests, which previously contradicted each other (one expected True, one False). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(dev): harden scaffold writes and accept case-insensitive --type - Guard scaffold_integration() against symlinked target directories: walk each path component under the repo root and refuse symlinked dirs, then confirm the write destination resolves inside the repo (mirrors the manifest directory guard). Prevents scaffolding outside the repo when a contributor's integrations/tests path is symlinked. - Make the `--type` click.Choice case-insensitive so `--type YAML` is accepted, matching scaffold_integration()'s strip()/lower() normalization instead of rejecting at the CLI layer. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(dev): report scaffold filesystem failures as a clean CLI error The `dev integration scaffold` command only caught FileExistsError/ValueError, so an OSError raised during mkdir()/write_text() (permission denied, read-only checkout, a path component that is a file, ...) bubbled up as a traceback instead of a clean error + exit code. Broaden the handler to OSError (which also covers FileExistsError) and add coverage for the filesystem-error path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(dev): move scaffold command under integration * fix(dev): roll back partial scaffold writes * fix(dev): correct lint docs and generated test docstring - local-development.md: ruff check src/ is enforced in CI, not absent - scaffolded test docstring: drop misleading 'scaffold' wording * fix(scaffold): create only leaf integration directory --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.8 KiB
Local Development Guide
This guide shows how to iterate on the specify CLI locally without publishing a release or committing to main first.
Scripts now have both Bash (
.sh) and PowerShell (.ps1) variants. The CLI auto-selects based on OS unless you pass--script sh|ps.
1. Clone and Switch Branches
git clone https://github.com/github/spec-kit.git
cd spec-kit
# Work on a feature branch
git checkout -b your-feature-branch
2. Run the CLI Directly (Fastest Feedback)
You can execute the CLI via the module entrypoint without installing anything:
# From repo root
python -m src.specify_cli --help
python -m src.specify_cli init demo-project --integration claude --ignore-agent-tools --script sh
If you prefer invoking the script file style (uses shebang):
python src/specify_cli/__init__.py init demo-project --script ps
3. Use Editable Install (Isolated Environment)
Create an isolated environment using uv so dependencies resolve exactly like end users get them:
# Create & activate virtual env (uv auto-manages .venv)
uv venv
source .venv/bin/activate # or on Windows PowerShell: .venv\Scripts\Activate.ps1
# Install project in editable mode
uv pip install -e .
# Now 'specify' entrypoint is available
specify --help
Re-running after code edits requires no reinstall because of editable mode.
4. Invoke with uvx Directly From Git (Current Branch)
uvx can run from a local path (or a Git ref) to simulate user flows:
uvx --from . specify init demo-uvx --integration copilot --ignore-agent-tools --script sh
You can also point uvx at a specific branch without merging:
# Push your working branch first
git push origin your-feature-branch
uvx --from git+https://github.com/github/spec-kit.git@your-feature-branch specify init demo-branch-test --script ps
4a. Absolute Path uvx (Run From Anywhere)
If you're in another directory, use an absolute path instead of .:
uvx --from /mnt/c/GitHub/spec-kit specify --help
uvx --from /mnt/c/GitHub/spec-kit specify init demo-anywhere --integration copilot --ignore-agent-tools --script sh
Set an environment variable for convenience:
export SPEC_KIT_SRC=/mnt/c/GitHub/spec-kit
uvx --from "$SPEC_KIT_SRC" specify init demo-env --integration copilot --ignore-agent-tools --script ps
(Optional) Define a shell function:
specify-dev() { uvx --from /mnt/c/GitHub/spec-kit specify "$@"; }
# Then
specify-dev --help
5. Testing Script Permission Logic
After running an init, check that shell scripts are executable on POSIX systems:
ls -l scripts | grep .sh
# Expect owner execute bit (e.g. -rwxr-xr-x)
On Windows you will instead use the .ps1 scripts (no chmod needed).
6. Scaffold a Built-In Integration
Use the integration scaffold command to create the initial Python package and test skeleton for a new built-in integration:
specify integration scaffold my-agent --type markdown
specify integration scaffold my-agent --type toml
specify integration scaffold my-agent --type yaml
specify integration scaffold my-agent --type skills
Hyphenated keys are converted to Python-safe package names, for example
my-agent creates src/specify_cli/integrations/my_agent/ and
tests/integrations/test_integration_my_agent.py.
The scaffold does not register the integration automatically. Review the
generated metadata, then add the import and _register() call in
src/specify_cli/integrations/__init__.py.
7. Run Lint / Basic Checks
CI enforces ruff check src/ (see .github/workflows/test.yml), so run it locally before pushing:
uvx ruff check src/
You can also quickly sanity check importability:
python -c "import specify_cli; print('Import OK')"
8. Build a Wheel Locally (Optional)
Validate packaging before publishing:
uv build
ls dist/
Install the built artifact into a fresh throwaway environment if needed.
9. Using a Temporary Workspace
When testing init --here in a dirty directory, create a temp workspace:
mkdir /tmp/spec-test && cd /tmp/spec-test
python -m src.specify_cli init --here --integration claude --ignore-agent-tools --script sh # if repo copied here
Or copy only the modified CLI portion if you want a lighter sandbox.
10. Debug Network / TLS Issues
Deprecated: The
--skip-tlsflag is a no-op and has no effect. It was previously used to bypass TLS validation during local testing. If you encounter TLS errors (e.g., on a corporate network), configure your environment's certificate store or proxy instead.For example, set
SSL_CERT_FILEor configureHTTPS_PROXY/HTTP_PROXY.
11. Rapid Edit Loop Summary
| Action | Command |
|---|---|
| Run CLI directly | python -m src.specify_cli --help |
| Editable install | uv pip install -e . then specify ... |
| Local uvx run (repo root) | uvx --from . specify ... |
| Local uvx run (abs path) | uvx --from /mnt/c/GitHub/spec-kit specify ... |
| Git branch uvx | uvx --from git+URL@branch specify ... |
| Build wheel | uv build |
12. Cleaning Up
Remove build artifacts / virtual env quickly:
rm -rf .venv dist build *.egg-info
13. Common Issues
| Symptom | Fix |
|---|---|
ModuleNotFoundError: typer |
Run uv pip install -e . |
| Scripts not executable (Linux) | Re-run init or chmod +x scripts/*.sh |
| Git commands unavailable | Install the git extension with specify extension add git |
| Wrong script type downloaded | Pass --script sh or --script ps explicitly |
| TLS errors on corporate network | Configure your environment's certificate store or proxy. The --skip-tls flag is deprecated and has no effect. |
14. Next Steps
- Update docs and run through Quick Start using your modified CLI
- Open a PR when satisfied
- (Optional) Tag a release once changes land in
main