# Behavior traces — github/spec-kit

> Canonical page: https://codevetter.com/unpack/spec-kit/behavior-traces

# Behavior traces — github/spec-kit

Scanned commit 175adbcd826befdccce8c60faa07ae3d8bbc8d87 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Three flows traced end-to-end: `specify init` (bootstrap), `specify workflow run` (primary automation), and extension install plus agent-side command execution (persistence and runtime paths). Self-upgrade and the event-dispatch path were also walked. Each flow funnels through `_require_specify_project` or asset-resolution helpers before touching the filesystem, and all writes go through hash-tracked manifests or safe-write helpers.
- `specify init` ordered trace: `show_banner` → `get_integration` validation → `--here`/directory-exists handling (`--force` merge vs confirmation prompt vs non-interactive error) → agent selection (`select_with_arrows` or non-interactive default via `SPECKIT_INTEGRATION_DEFAULT`/copilot) → `check_tool` when `requires_cli` → script-type selection → `StepTracker`+`Live` phases: `IntegrationManifest` → `resolved_integration.setup()` → `_install_shared_infra_or_exit` → `ensure_executable_scripts` → `ensure_constitution_from_template` → bundled workflow install → `_install_extension_during_init` per `--extension` → `save_init_options`. — [src/specify_cli/commands/init.py#L398-700](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/commands/init.py#L398-L700) [src/specify_cli/__init__.py#L191-267](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/__init__.py#L191-L267)
- URL-based `--extension` installs during init are resolved for trust BEFORE the Rich `Live` display starts: `_confirm_extension_url_trust` shows an 'Untrusted Source' panel per URL, defaults to deny (and auto-denies when non-interactive), with `--trust-extension-urls` as the pre-authorization override. — [src/specify_cli/commands/init.py#L56-98,647-659](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/commands/init.py#L56-98,647-L659)
- `specify workflow run <src>` trace: decide file-source vs installed-ID → `_require_specify_project()` (or cwd for file sources) → `_reject_unsafe_workflow_storage` → `load_custom_steps(project_root)` → `WorkflowEngine.load_workflow` → `validate` → `_parse_input_values` → `engine.execute` → `_execute_steps` dispatches each step by `type` through `STEP_REGISTRY` → results recorded to `RunState` → exit code from `_run_outcome_exit_code`; paused runs print a `workflow resume <run_id>` hint. — [src/specify_cli/workflows/_commands.py#L1308-1454](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/workflows/_commands.py#L1308-L1454) [src/specify_cli/workflows/engine.py#L986-1073,1208-1271](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/workflows/engine.py#L986-1073,1208-L1271)
- A `command` step resolves `integration` (step → workflow default → project `.specify/integration.json`, `"auto"` → recorded key) and `model`, evaluates `{{ }}` expressions in `input`/`options`, guards every non-string value with a per-step FAILED result (rather than crashing the run), then invokes the agent CLI via `build_exec_args`, streaming output live. — [src/specify_cli/workflows/steps/command/__init__.py#L31-113](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/workflows/steps/command/__init__.py#L31-L113) [src/specify_cli/integrations/base.py#L1089-1108](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/integrations/base.py#L1089-L1108)
- `specify extension add git` trace: `_require_specify_project` → `ExtensionManager(project_root)` → `--dev` local dir / `--from` URL (HTTPS check + trust prompt) / bundled lookup / catalog download → `install_from_directory` or `install_from_zip` validates `extension.yml`, copies artifacts, records files, and `register_hooks` merges `hooks:` into `.specify/extensions.yml` → `_refresh_events_and_warn` refreshes native hook config. — [src/specify_cli/extensions/command_add.py#L19-100](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/extensions/command_add.py#L19-L100) [src/specify_cli/extensions/__init__.py#L2085-2130,2626-2630](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/extensions/__init__.py#L2085-2130,2626-L2630) [src/specify_cli/extensions/_commands.py#L100-120](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/extensions/_commands.py#L100-L120)
- `specify self check` trace: `_get_installed_version` (importlib.metadata, 'unknown' sentinel) → `_fetch_latest_release_tag` does exactly one `open_url` call to `api.github.com/repos/github/spec-kit/releases/latest` with a 5 s timeout and a 1 MiB JSON cap → `_normalize_tag` → `_is_newer` PEP 440 compare; failures categorize as offline/rate-limited/HTTP <code> without a catch-all. — [src/specify_cli/_version.py#L55-145](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/_version.py#L55-L145)
- Agent-side `/speckit.specify` execution trace (what the installed command file instructs the agent to do): read `.specify/extensions.yml` for `hooks.before_specify` (mandatory hooks emitted as EXECUTE_COMMAND and awaited; optional hooks as prompts) → generate a 2-4 word short name → run the `create-new-feature` helper script which returns a `FEATURE_DIR`/`BRANCH_NAME` JSON contract → render `spec.md` from `spec-template.md` under `specs/NNN-<short-name>/`. — [templates/commands/specify.md#L21-80](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/templates/commands/specify.md#L21-L80) [scripts/bash/create-new-feature.sh#L1-80](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/scripts/bash/create-new-feature.sh#L1-L80) [extensions/git/extension.yml#L42-51](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/extensions/git/extension.yml#L42-L51)
- Agent-native event trace: the agent's hook config (emitted by `install_integration_events` during `setup()`) invokes the generated `.specify/events.py` dispatcher → dispatcher resolves the event's command template and confines the script token under the project root → or falls back to `specify event run <cmd> <event> <timeout>` → `resolve_and_run_event_command` executes the script with the stdin payload. — [src/specify_cli/events.py#L33-100](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/events.py#L33-L100) [src/specify_cli/commands/event.py#L13-60](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/commands/event.py#L13-L60) [src/specify_cli/integrations/base.py#L1014-1035](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/integrations/base.py#L1014-L1035)
- Uninstall trace: `IntegrationBase.teardown` → `remove_events` (strips Specify-authored native hook entries) → `manifest.uninstall(project_root, force=...)` removes only files whose on-disk SHA-256 still equals the recorded hash, returning `(removed, skipped)` lists so user-modified files survive. — [src/specify_cli/integrations/base.py#L997-1031](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/integrations/base.py#L997-L1031) [src/specify_cli/integrations/manifest.py#L104-120](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/integrations/manifest.py#L104-L120)
- `specify integration uninstall`/shared-infra refresh respects a three-tier overwrite policy: `force=True` overwrites everything (still skipping symlinks), `refresh_managed=True` overwrites only files whose hash matches the manifest (user edits preserved with a warning + caller-supplied remediation hint), default adds only missing files. — [src/specify_cli/__init__.py#L135-188](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/__init__.py#L135-L188) [src/specify_cli/shared_infra.py](https://github.com/github/spec-kit/blob/175adbcd826befdccce8c60faa07ae3d8bbc8d87/src/specify_cli/shared_infra.py)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
