This document describes how the tikalk fork (tikalk/agentic-sdlc-spec-kit) maintains customizations while staying synced with upstream github/spec-kit.
The fork isolates customizations into a small set of focused modules under src/specify_cli/ to minimize merge conflicts. When syncing with upstream:
- The import block in
__init__.pymay conflict - All customization logic lives in the
_*_fork.pymodules - Upstream changes to other parts of
__init__.pymerge cleanly
| Module | Purpose | Imports from |
|---|---|---|
_assets_fork.py |
Leaf — bundled-asset helpers (get_bundled_*_version/_path, fork _locate_bundled_preset) |
_assets (clean upstream) |
_core_fork.py |
Leaf — fork-level extension constants (EXTENSION_NAMESPACES, EXTENSION_ALIAS_PATTERN_ENABLED, FORK_INSTALL_COMMAND), alias resolution, MCP config, skill naming, preinstalled extension queries |
(none) |
_init_fork.py |
Theming, package identity, init hooks (pre_init/post_init), scaffolding, skill installation |
_core_fork, _assets_fork |
base_fork.py |
Fork-level helpers on IntegrationBase (e.g. detect_native_worktree()) |
(none) |
extensions_fork.py |
Constants and schemas for fork-specific extension features (e.g. worktree config) | (none) |
Consolidation note (
0.11.9+adlc9): The former leaf module_extension_fork.py(pure constants) was merged into_core_fork.pyto simplify the dependency graph from three tiers to two._init_fork.pynow imports extension constants from_core_fork.pyinstead of_extension_fork.py. The_extension_fork.pyfile was deleted; any stale references to it in older commits are historical.
Dependency direction (locked):
_assets_fork.py (leaf)
_core_fork.py (leaf - constants + alias/MCP/skill)
^
|
_init_fork.py
Anything added to a higher-tier module must not be imported by a lower-tier module. This rule prevents circular imports.
The fork uses a suffix-based versioning system to track both upstream and fork-specific changes:
<upstream-version>+adlc<N>
Examples:
0.8.2+adlc1- Fork based on upstream 0.8.2, first fork release0.8.2+adlc2- Same upstream base, second fork release with new features0.9.0+adlc1- After upstream merge to 0.9.0, reset fork counter
| Scenario | Version Change | Example |
|---|---|---|
| Fork adds new feature | Increment adlc suffix | 0.8.2+adlc1 → 0.8.2+adlc2 |
| Merge upstream release | Update base, reset suffix | 0.8.2+adlc5 → 0.9.0+adlc1 |
| Hotfix/patch | Increment adlc suffix | 0.8.2+adlc1 → 0.8.2+adlc2 |
Use agentic-sdlc-v<version> with plus:
-
Version:
0.11.9+adlc4 -
Tag:
agentic-sdlc-v0.11.9+adlc4When a fork release changes only bundled extension behavior, keep the CLI version on the upstream base (for example0.10.0+adlc3) and bump the affected extension manifest version independently (for exampleextensions/git/extension.ymlto1.5.0).
| Version | Date | Base Upstream | Changes |
|---|---|---|---|
| 0.12.4+adlc9 | 2026-07-03 | 0.12.4.dev0 (bbe86310) |
Major refactor: replaced loop extension (v1.2.0) with workflow extension (v2.0.0). Three commands: mission (assess prompt → generate workflow YAML → run; LLM-as-judge routes to spec./change./quick.* pipelines; no-args collects Mission Brief), resume (scan runs for PAUSED/FAILED matching current feature → specify workflow resume <run_id>), persist (copy run's workflow.yml to permanent location + register). Per-step model selection via config (models.strong/models.fast). EDD next-spec.md spec-correction routing handled at agent level (not nested in YAML) with .mission-state.json state file preventing infinite loops (max_spec_corrections: 2). No drafts directory — run directory stores workflow.yml. Deleted extensions/loop/, workflows/sdd-loop/. Kept workflows/impl-converge-loop/ for direct impl↺converge. Removed sdd-loop from workflows/catalog.json. CLI 0.12.4+adlc8→0.12.4+adlc9. |
| 0.12.4+adlc8 | 2026-07-03 | 0.12.4.dev0 (bbe86310) |
Loop extension v1.2.0: Fixed impl-converge-loop workflow — command names adlc.spec.implement/adlc.spec.converge → spec.implement/spec.converge (CLI was resolving adlc.spec.implement to spec.spec.implement, causing "Command not found"). Replaced literal command names in adlc.loop.goal.md with __SPECKIT_COMMAND_*__ placeholders (resolved to /spec.specify etc. at init by resolve_command_refs). Added CLI fallback to adlc.loop.run.md — if specify workflow run impl-converge-loop fails, manually iterate __SPECKIT_COMMAND_IMPLEMENT__ → __SPECKIT_COMMAND_CONVERGE__ (max 5). Extension 1.1.0→1.2.0. |
| 0.12.4+adlc7 | 2026-07-03 | 0.12.4.dev0 (bbe86310) |
Clean up dangling verify references after merge into converge: change.implement handoff adlc.change.verify → adlc.change.converge, agentic-change README /change.verify → /change.converge, EXTENSION-API-REFERENCE before_verify/after_verify → before_converge/after_converge. CLI 0.12.4+adlc6→0.12.4+adlc7. |
| 0.12.4+adlc6 | 2026-07-03 | 0.12.4.dev0 (bbe86310) |
change.converge full verification parity with spec.converge — append-only convergence assessment for change proposals, test gate, 4-pillar quality assessment, outcome token (converged/tasks_appended). Agentic-change preset 1.3.0→1.4.0. CLI 0.12.4+adlc5→0.12.4+adlc6. |
| 0.12.4+adlc5 | 2026-07-02 | 0.12.4.dev0 (bbe86310) |
Loop extension v1.1.0: adlc.loop.goal rewritten to arg-based flow — with args: spec.specify→spec.plan→spec.tasks→loop.run (regenerates artifacts, passes spec_description to spec.specify); without args: hard error if spec/plan/tasks missing, else resumes loop.run. Command invocations changed from specify <cmd> CLI syntax to bare command names (agent-resolved, like hooks). loop.run alias used instead of full adlc.loop.run. Added outer loop cap (max 2 spec-level corrections) to prevent unbounded recursion in loop routing. Added exit conditions, design philosophy, and examples sections. New sdd-loop workflow (constitution → loop.goal, passes {{ inputs.spec }} as args). Registered sdd-loop in workflows/catalog.json. Extension 1.0.0→1.1.0. |
| 0.12.4+adlc4 | 2026-07-02 | 0.12.4.dev0 (bbe86310) |
EDD v1.1.0: appends actionable verification gaps to tasks.md, writes next-spec.md for spec-level corrections, fills EDD placeholder sections in converge's verify.md. Fixes loop disconnect (next-prompt targeted spec.specify while loop ran implement). Converge verify.md now includes Intent, Verification Summary, What Was Checked/Not Checked, Residual Risks, Provenance — the unified evidence bundle. Loop routing added to adlc.loop.goal (steps 6-7) and adlc.loop.run (detailed section with __SPECKIT_COMMAND_*__ placeholders). EDD extension 1.0.0→1.1.0. CLI 0.12.4+adlc3→0.12.4+adlc4. |
| 0.12.4+adlc3 | 2026-07-02 | 0.12.4.dev0 (bbe86310) |
New loop extension (v1.0.0): adlc.loop.run + adlc.loop.goal commands, impl-converge-loop engine workflow (do-while, max 5 iterations, condition: contains('tasks_appended')). Merged spec.verify into spec.converge (test gate + diff analysis + 4-pillar assessment now part of converge; converge outputs outcome token as first stdout line). Merged change.verify into change.converge (parallel merge in agentic-change preset). EDD hook moved after_implement → after_converge. Deleted broken sdd-loop.yml (non-functional Jinja2 expressions, unregistered, untested). Updated README.md (6 locations), QUICKSTART.md, EDD README/CHANGELOG. CLI 0.12.4+adlc2→0.12.4+adlc3. |
| 0.12.4+adlc2 | 2026-07-02 | 0.12.4.dev0 (bbe86310) |
Preset hook fix: removed manual extension.yml manifest resolution from all 15 preset command files — replaced with upstream-aligned EXECUTE_COMMAND blocks (pre-hook → **Automatic Pre-Hook**, post-hook → **Automatic Hook**). Fork regression fixes: PS Get-CurrentBranch git lookup removed for bash parity (branch fallback to feature dir basename); _INSTALLER_PATH_PREFIXES extended with agentic-sdlc-specify-cli fork tool-dir names for specify self upgrade detection. CLI 0.12.4+adlc1→0.12.4+adlc2. Preset bumps: agentic-sdlc 1.5.0→1.6.0, agentic-quick 1.1.0→1.2.0, agentic-change 1.2.0→1.3.0. |
| 0.12.4+adlc1 | 2026-07-02 | 0.12.4.dev0 (bbe86310) |
Merge upstream 15 commits: py script type + Python interpreter resolution, private-repo release asset URL fix, Analytics extension catalog, multi-expression template fix, SPECIFY_INIT_DIR, core-command dir helpers, CURRENT_BRANCH fallback, bug-fix/bug-test workflows, Copilot pre-rollout warning, newsletter, zed integration, cline hook fix. 4 conflicts resolved (pyproject.toml, common.sh, base.py, test_base.py). Also: fixed banner theming regression — converted all 8 remaining sub-apps (bundle/extension/preset/workflow-step) from plain typer.Typer() to make_typer(). |
| 0.12.2+adlc2 | 2026-07-01 | 0.12.2 (810d6fcf) |
Merge upstream PR-8/8: workflow command handlers moved from __init__.py to new workflows/_commands.py. Re-applied fork import block (_init_fork/_core_fork/_assets_fork, _upstream_-aliased version fns, show_banner override) on top of upstream's compact register() region; scoped from typing import Any into fallback. Patched _commands.py so workflow_app/workflow_catalog_app use make_typer() theming (step apps stay plain). Fixed bash 3.2 portability (${var,,} → tr) in fork extension scripts setup-architect/levelup/product.sh. 1 real conflict (__init__.py); test_workflows.py auto-merged. |
| 0.12.2+adlc1 | 2026-06-30 | 0.12.2 | Merge upstream 0.12.2 (19 commits): retired iflow/roo/windsurf integrations, moved version_satisfies to _utils.py (allows prereleases), workflow fan-out max_concurrency, bool max_iterations rejection, bash 3.2 portability fixes, --no-persist in common.sh, extension catalog updates (Intake v0.1.3, Architecture Workflow v1.2.2, Repository Governance, Workflow Preset v1.3.11). 2 conflicts resolved (pyproject.toml, AGENTS.md). |
| 0.11.9+adlc9 | 2026-06-30 | 0.11.9 | Fixed F811 ruff lint (duplicate _locate_bundled_preset import). Consolidated _extension_fork.py into _core_fork.py (three-tier → two-tier dependency graph). Agent-context opt-in alignment in adlc.spec.plan (conditional context-file update). |
| 0.11.9+adlc4 | 2026-06-29 | 0.11.9 | Fixed 4 remaining CI test failures: Generic integration converge prefix mismatch (3 tests), eval.yml action SHA pinning (1 test). Pinned all 6 GitHub Actions to commit SHAs. All CI tests now pass. |
| 0.11.9+adlc3 | 2026-06-29 | 0.11.9 | Merge upstream 2 new commits: community bundle submission issue template + docs (#3162), docs for /speckit.converge (#3181). All doc files already identical; only README.md required merge. Added new Community Bundles section to README with contribution link. Fixed 6 CI test failures: converge command keeps speckit. prefix (like taskstoissues); Firebender _expected_files accepts project kwarg + dedup; setup-plan test uses SPECIFY_FEATURE_DIRECTORY; PS create-new-feature.ps1 null $featureDir fix; PS test uses correct extension script path. |
| 0.11.9+adlc2 | 2026-06-29 | 0.11.9 | Re-added specify preset update CLI command (registration lost during upstream merge). Fixed test_e2e_branch_pattern_with_issue_config to source git-common.sh (core common.sh no longer has check_feature_branch). |
| 0.11.9+adlc1 | 2026-06-28 | 0.11.9 | Merge upstream 0.11.9 (15 commits): mandatory hook invocation enforcement (#2901), PowerShell branch-name acronym case-sensitivity fix (#3129), GHES private release asset resolution (#3157), community bundle submission path (#3162), docs for --force and --refresh-shared-infra (#3179). Fork fixes: relative imports in extensions/ and presets/ init.py, registered.append guard in agents.py, bundled extension update uses install_from_directory not catalog download. |
| 0.11.8+adlc1 | 2026-06-28 | 0.11.8 | Merge upstream 0.11.8 (19 commits): standardized EXECUTE_COMMAND hook format across all core command templates; git extension aligned to upstream opt-in (removed --no-git flag); forked core and preset commands split their hook strategies (upstream's EXECUTE_COMMAND for core, fork's manifest-lookup dispatcher for presets); script delegation paths fixed (core -> git extension); workflow tests adapted to fork's run_and_tee streaming; bundled-extension update checks bundled version first. |
| 0.10.0+adlc33 | 2026-06-22 | 0.10.0 | Orange accent theming sweep: replaced all 54 [green] Rich markup references with accent() across 8 files — every success message, checkmark symbol, and status indicator now uses #f47721 orange instead of green. Affects __init__.py, _init_fork.py, _version.py, _utils.py, _console.py, commands/init.py, integrations/_install_commands.py, integrations/_migrate_commands.py, integrations/_query_commands.py. |
| 0.10.0+adlc32 | 2026-06-22 | 0.10.0 | Fixed broken /memory/constitution.md paths in agentic-sdlc preset (analyze, plan, implement, verify) — now uses {REPO_ROOT}/.specify/memory/constitution.md. Added constitution alignment to agentic-quick (implement) and agentic-change (specify, implement, verify) via IF EXISTS pattern. Bumped agentic-sdlc v1.4.0→v1.5.0, agentic-quick v1.0.0→v1.1.0, agentic-change v1.0.0→v1.1.0, team-ai-directives v3.1.0→v3.2.0, CLI 0.10.0+adlc31→0.10.0+adlc32. |
| 0.10.0+adlc31 | 2026-06-20 | 0.10.0 | Added make_typer() helper to _init_fork.py — creates typer.Typer with cls=BannerGroup by default. Converted 9 sub-app definitions to use make_typer() or cls=BannerGroup (extension_app, catalog_app, preset_app, preset_catalog_app, workflow_app, workflow_catalog_app, integration_app, integration_catalog_app, self_app). Replaced 4 hardcoded [cyan] markup with accent() in init/install flows. Bumped CLI 0.10.0+adlc30→0.10.0+adlc31. |
| 0.10.0+adlc30 | 2026-06-20 | 0.10.0 | Extracted project-root .skills.json and .specify/skills/ install from _install_skills_from_path() into new standalone install_project_skills() function. Project skills now install during every init as a dedicated fork step (not only with --team-ai-directives). Added ("project-skills", "Install Projects skills") tracker step. |
| 0.10.0+adlc29 | 2026-06-20 | 0.10.0 | Removed extensions/quick. Added agentic-change and agentic-quick bundled presets (force-included in wheel, catalog entries with preinstall:true). agentic-change provides 4 commands (change.specify/implement/verify/levelup) for lightweight OpenSpec-inspired change proposals; agentic-quick provides 2 commands (quick.implement/levelup) replacing the deleted quick extension with identical content. pyproject.toml, README.md, QUICKSTART.md, CHANGELOG.md, FORK.md, catalog.json updated. |
| 0.10.0+adlc28 | 2026-06-20 | 0.10.0 | Added brainstorm lifecycle stage (adlc.spec.brainstorm) — structured exploration before specification, outputs .specify/drafts/brainstorm-context.md, consumed by adlc.spec.specify (Mission Brief seeding + promotion). Added verify lifecycle stage (adlc.spec.verify) — hard test gate + 4-pillar compliance assessment (Spec Compliance, Code Quality, Test Adequacy, Risk & Evidence), outputs SPECIFY_FEATURE_DIRECTORY/verify.md. 8 new hook events: before_brainstorm/after_brainstorm, before_verify/after_verify, before_levelup/after_levelup, before_trace/after_trace. Agentic SDLC preset v1.3.0→v1.4.0. README updated (4 locations). |
| 0.10.0+adlc27 | 2026-06-20 | 0.10.0 | Fixed TEAM_DIRECTIVES sentinel bug in quick.levelup (boolean flag guard). Replaced raw git with git extension commands (git.commit --message, git.publish --draft). Aligned CDR ID format to CDR-{NNN} (year-scoped, no year prefix). Added OKF v0.1 frontmatter (type, title, description, tags, timestamp). Structured evidence as YAML list. Added constitution amendment safety instruction. Quick extension v1.4.0→v1.5.0. |
| 0.10.0+adlc26 | 2026-06-20 | 0.10.0 | Model-invocation opt-in for skills agents (model-invocation: true on quick.implement, quick.levelup, team.discover, team.skills). Removed Claude's unconditional disable-model-invocation: false. Added project-root .skills.json support in init and team.skills. |
| 0.10.0+adlc25 | 2026-06-20 | 0.10.0 | Fixed per-task metadata lifecycle in adlc.spec.implement.md (start-task/complete-task/fail-task instead of stale add-task with SYNC_OR_ASYNC placeholder). Downstream workflow steps (plan/tasks/implement) no longer receive full raw prompt as args. |
| 0.10.0+adlc22 | 2026-06-19 | 0.10.0 | Decoupled worktree cd from specify (git extension handles entry). Removed stale git.task-merge/delegate_merge_conflicts refs from adlc.spec.implement.md. Fixed 24 CI test failures — updated idempotency tests, removed task-branch test classes, deleted test_merge_task_branch.py. |
| 0.10.0+adlc20 | 2026-06-19 | 0.10.0 | Git extension v1.6.0: simplified worktree model to feature-only isolation (removed per-task branches), added git.worktree-list and git.worktree-cleanup commands, idempotent worktree creation with origin/main default base, hardened cd instruction for agents. Removed task-mode auto-commit prefixes. |
| 0.10.0+adlc17 | 2026-06-18 | 0.10.0 | Agentic SDLC preset v1.2.1: fixed constitution handoff agent naming (speckit.specify → adlc.spec.specify), registered missing delegation-template in preset manifest, refactored tasks-meta-utils.sh to use resolve_template for preset override support, aligned preset delegation-template placeholders with core version. |
| 0.10.0+adlc15 | 2026-06-14 | 0.10.0 | OKF v0.1 conformance: Added type, title, description, tags, timestamp fields to all context module frontmatter (constitution, personas, rules, examples, skills). Updated LevelUp templates (rule, persona, example, skill) and command docs (implement, validate, init) to generate OKF-compliant frontmatter. Updated team-ai-directives extension commands (repair, verify) for OKF field validation and orphan repair. Bumped LevelUp extension to v1.9.0 and team-ai-directives extension to v1.9.0. |
| 0.10.0+adlc14 | 2026-06-14 | 0.10.0 | Agentic SDLC preset v1.2.0: token compression across all 9 preset commands (~236 lines, ~9.4% reduction). Quick extension v1.3.0: hook execution aligned to preset protocol (manifest resolution + condition filtering) + non-hook compression (~95 lines). |
| 0.10.0+adlc13 | 2026-06-14 | 0.10.0 | EDD Extension v1.0.0 (extensions/edd/): unified edd.verify command with deterministic auto-detect + AI evaluation, guardrails (no-progress/budget/regression/escalation), .eval/loop-state.yml spine, sdd-loop.yml workflow with hook-driven verify (after_implement, optional: false). Review bugs fixed: {SCRIPT} overload, script paths, workflow grade step, double-run, coverage, smoke parsing. Agentic SDLC preset v1.1.0: removed adlc.spec.verify, implement step 3, handoffs updated. |
| 0.10.0+adlc12 | 2026-06-14 | 0.10.0 | Fork _assets_fork.py module: consolidates bundled-asset helpers into leaf module, restores _assets.py to clean-upstream. specify preset update command: atomic updates with backup/rollback for bundled presets. Fuzzy-match suggestions on preset typos. |
| 0.10.0+adlc11 | 2026-06-13 | 0.10.0 | Agentic SDLC preset v1.0.11: added mission-brief checklist domain to spec.checklist for Oracle Adequacy validation — 6-item checklist auto-evaluates whether the Mission Brief (Goal, Success Criteria, Constraints) is sufficient to serve as its own verification oracle. Added spec.specify handoff to spec.checklist mission-brief and spec.implement pre-flight adequacy warning when score < 80%. |
| 0.10.0+adlc10 | 2026-06-13 | 0.10.0 | Quick extension v1.2.0: added quick.levelup command for low-friction directive contribution to team-ai-directories — 6 verifiable phases with automated gates (Signal Gate, Cross-System Conflict Detection, Output Artifact Verification), CDR schema completeness check, Descriptor generation matching levelup.implement format, companion skill auto-detection, and handoff to /levelup.validate. |
| 0.10.0+adlc9 | 2026-06-13 | 0.10.0 | CDR.md becomes the context module search surface for /team.discover. New Descriptor column in CDR.md index table enables LLM-driven relevance matching without full-file scans. LevelUp extension v1.8.0: implement.md emits Descriptor column. Team AI Directives extension v1.8.0: discover.md uses CDR index as primary search surface (skills-style), repair.md re-indexer updated for Descriptor column, agents-template.md documents CDR.md as context index. Falls back to legacy context_modules/ scan when CDR.md unavailable. |
| 0.10.0+adlc8 | 2026-06-12 | 0.10.0 | Fixed _locate_bundled_preset() to resolve agentic-sdlc from bundled_presets/ in wheel/uv-tool installs, matching the pyproject.toml wheel path. |
| 0.10.0+adlc7 | 2026-06-12 | 0.10.0 | Agentic SDLC preset v1.0.10: trimmed duplicate [SYNC]/[ASYNC] taxonomies in adlc.spec.plan.md and adlc.spec.tasks.md; references canonical templates/plan-template.md and templates/tasks-template.md instead of inline duplication. ~340 tokens saved, behavior-identical. |
| 0.10.0+adlc6 | 2026-06-08 | 0.10.0 | Repaired the bundled evals extension (PowerShell lifecycle parity, validation path fixes, non-interactive robustness) and promoted feature-local trace/verification into the preset surface: spec.trace owns specs/{branch}/trace.md, spec.verify defines specs/{branch}/evidence.md, and the Agentic SDLC preset now suggests trace/verify after implement. Evals extension bumped to v1.1.1, LevelUp stays at v1.7.1, preset bumped to v1.0.9. |
| 0.10.0+adlc5 | 2026-06-08 | 0.10.0 | Added configurable git extension branch_pattern support with Jira issue keys, expanded git extension docs, added installed-extension end-to-end coverage for configured Jira branch names, bumped the bundled git extension to v1.5.0, and bumped the fork CLI release to capture the shipped behavior. |
| 0.10.0+adlc4 | 2026-06-08 | 0.10.0 | Follow-up fork release after 0.10.0+adlc3: fixed the PowerShell merge-task-branch regression test to execute from the primary checkout script path while preserving worktree cwd, so the release tag includes the CI fix as well. Git extension remains at v1.4.0. |
| 0.10.0+adlc3 | 2026-06-08 | 0.10.0 | Kept the CLI on the upstream 0.10.0 base while shipping the real async/[P] execution backend: script-backed tasks-meta-utils CLI (bash + PowerShell), feature-scoped async state, explicit [SYNC]/[ASYNC] parsing in tasks-dag.{sh,ps1}, real implement.{sh,ps1} executors, and merge-task-branch support in worktree-utils.{sh,ps1}. Bumped the bundled git extension to v1.4.0 for these capabilities. |
| 0.10.0+adlc2 | 2026-06-08 | 0.10.0 | Hook command id normalization: .specify/extensions.yml now stores alias-normalized hook command ids; added normalization helpers in _core_fork.py, normalized bundled-install hook configs in init/install flows, and fixed skill-name resolution for alias-form command ids. |
| 0.10.0+adlc1 | 2026-06-07 | 0.10.0 | Upstream merge: adopted upstream 0.10.0 removal of legacy --ai, --ai-commands-dir, and --ai-skills init flags; merged bundled bug triage extension, private-repo preset/workflow release-asset URL hardening, and workflow gate prompt rendering updates. Preserved fork identity, theming, spec-* alias guidance, team-directives hooks, and fork package metadata/versioning. |
| 0.9.5+adlc1 | 2026-06-04 | 0.9.5 | Merge upstream 0.9.5 (3 commits): rovodev Atlassian Rovo Dev integration (acli rovodev); --json output for workflow run/resume/status; upversion to 0.9.5.dev0. Preserved fork identity and theming. Fixed upstream rovodev integration for fork: added _reconcile_rovodev_prompts in post_init so prompt wrappers + prompts.yml follow alias-aware skill names (spec-*); updated tests to reflect alias-aware contract |
| 0.9.2+adlc5 | 2026-06-04 | 0.9.2 | Hotfix: made specify self check and specify self upgrade fork-aware by detecting agentic-sdlc-specify-cli, accepting fork tags like agentic-sdlc-v0.9.2+adlc4, and emitting fork-correct reinstall/rollback commands |
| 0.9.2+adlc4 | 2026-06-03 | 0.9.2 | Follow-up fork release after upstream main merge: self-upgrade/rollback guidance now points to tikalk/agentic-sdlc-spec-kit, themed specify --help, fixed generic integration quickstart test, and cleaned targeted Ruff/test issues while excluding eval Python template assets from Ruff |
| 0.9.2+adlc3 | 2026-06-03 | 0.9.2 | Upstream main merge after 0.9.2: adopted bb2b49d workflow run-state hardening so RunState.load() validates run_id before path construction, plus new traversal/validation regression tests; kept fork release/version identity |
| 0.9.2+adlc2 | 2026-06-03 | 0.9.2 | Hotfix: project-scoped alias resolution for HookExecutor skill names and CommandRegistrar output names (uses project_root instead of cwd), fixing fork CI failures where core commands should render spec-* but git / agent-context / tasktoissues remain speckit-* |
| 0.9.2+adlc1 | 2026-06-03 | 0.9.2 | Upstream merge: 14 commits (v0.9.0-v0.9.2). Major: ee17b04 co-locates integration CLI handlers into integrations/_*.py (fork theming re-applied); d79a514 drops unsupported Copilot mode: frontmatter (fork adopted); UTF-8 I/O pinning, workflows continue_on_error, private-repo asset URL fix. Removed deleted command stubs |
| 0.8.12+adlc39 | 2026-05-30 | 0.8.12 | Architect v2.1.3: Viewpoint-organized aggregation enforcement, Mermaid-only diagram constraint |
| 0.8.12+adlc38 | 2026-05-30 | 0.8.12 | Architect v2.1.2: Subsystem view links in AD.md - inline links after each view when 2+ subsystems detected |
| 0.8.12+adlc37 | 2026-05-30 | 0.8.12 | LevelUp v1.7.0: Constitution CDR lifecycle - constitution changes now require review before publication |
| 0.8.12+adlc36 | 2026-05-29 | 0.8.12 | LevelUp v1.6.4: Constitution Generation phase in /levelup.init - derives principles from cross-cutting patterns and inconsistencies |
| 0.8.12+adlc35 | 2026-05-29 | 0.8.12 | LevelUp v1.6.3: Moved /levelup.repair to team-ai-directives as /team.repair, deleted orphan scripts; Team AI Directives v1.7.8: team.repair command, team.skills script fix, setup-team.sh/ps1 |
| 0.8.12+adlc34 | 2026-05-29 | 0.8.12 | ADLC preset v1.0.7: Hardened tasks_meta.json creation (MANDATORY init step, per-task metadata updates, completion verification); LevelUp extension: fixed common.sh path resolution in generate-trace.sh and validate-trace.sh |
| 0.8.12+adlc31 | 2026-05-29 | 0.8.12 | Team AI Directives extension v1.7.6: Renamed {KNOWLEDGE_BASE} to {TEAM_AI_DIRECTIVES} placeholder |
| 0.8.12+adlc26 | 2026-05-28 | 0.8.12 | Architect extension v2.1.1: Hardened DAG orchestration (threshold enforcement, DAG-guarded views, per-view state updates, Accepted-only ADR promotion), AD-template.md link fix |
| 0.8.12+adlc25 | 2026-05-28 | 0.8.12 | Hook execution hardening in all preset command files: pre-execution hooks moved to absolute top, compact imperative format, post-execution hooks extracted and standardized |
| 0.8.12+adlc24 | 2026-05-28 | 0.8.12 | Reference extension auto-update: specify extension update detects and applies updates for source: reference extensions with rollback support |
| 0.8.12+adlc23 | 2026-05-28 | 0.8.12 | Windows test failures: Replaced f-string JSON construction with json.dumps() to properly escape Windows paths |
| 0.8.12+adlc22 | 2026-05-28 | 0.8.12 | PresetResolver reference extension path resolution: resolve_extension_dir() for reference extensions living outside .specify/extensions/ |
| 0.8.12+adlc21 | 2026-05-28 | 0.8.12 | Reference extension support: full support for extensions registered with source: reference and a top-level path across CLI commands and config loading |
| 0.8.12+adlc20 | 2026-05-26 | 0.8.12 | Fix extension download URL {{VERSION}} placeholder substitution in download_extension method |
| 0.8.12+adlc19 | 2026-05-23 | 0.8.12 | LevelUp extension v1.6.1: Fix redundant ID generation, CDR ref preservation, AGENTS.md grep pattern, validate-directives.sh jq error |
| 0.8.12+adlc18 | 2026-05-23 | 0.8.12 | Fix team-ai-directives reference mode registration in extension registry |
| 0.8.12+adlc17 | 2026-05-22 | 0.8.12 | LevelUp extension v1.6.0: Repair command for CDR.md, .skills.json, and AGENTS.md reindexing |
| 0.8.12+adlc16 | 2026-05-20 | 0.8.12 | Architect extension v2.1.0: Technology neutrality in Functional View, Functional-Development view parity, analyze Pass E.6/E.7 |
| 0.8.12+adlc14 | 2026-05-19 | 0.8.12 | Product extension v1.5.6: In-section diagrams, remove Visual Summary, sections renumbered 1-12, delete visual templates, no .specify/product/visuals/ |
| 0.8.12+adlc13 | 2026-05-19 | 0.8.12 | Product extension v1.5.5: PDR lifecycle enforcement - mandatory memory promotion, state schema lifecycle fields, 9-check final gate |
| 0.8.12+adlc12 | 2026-05-19 | 0.8.12 | Product extension v1.5.4: Fix self-contained PRD enforcement - Step 3.3 structure, embedding rules, prd-template .specify/ references |
| 0.8.12+adlc11 | 2026-05-19 | 0.8.12 | Product extension v1.5.3: Business stakeholder sections (Executive Summary, Market Opportunity, Investment, GTM), self-contained PRD generation, enhanced validation |
| 0.8.12+adlc10 | 2026-05-19 | 0.8.12 | Product extension v1.5.2: Hardened implement command with compliance checklist, validation scripts, strict template enforcement, ASCII→Mermaid conversion |
| 0.8.12+adlc9 | 2026-05-19 | 0.8.12 | Product extension v1.5.1: Mermaid v10 syntax fixes, new diagram types (architecture, journey, gantt), mandatory visual generation |
| 0.8.12+adlc4 | 2026-05-17 | 0.8.12 | CLI bundled extension update support: specify extension update now checks CLI wheel for bundled extension updates |
| 0.8.12+adlc3 | 2026-05-17 | 0.8.12 | Architect extension v2.0.8 hardening: clarify→implement workflow enforcement, placeholder validation, --force flag |
| 0.8.12+adlc2 | 2026-05-16 | 0.8.12 | Architect extension comprehensive hardening: Phase execution enforcement, view file generation, sub-system detection with mandatory interactive proposal |
| 0.8.12+adlc1 | 2026-05-15 | 0.8.12 | Git extension enhancements (workspace command with force flag, setup-ignore command) |
The fork's customizations are split across the modules listed in Fork module layout. Historically these were all in a single cli_customization.py file; that file has been split into focused modules (as of release 0.9.5+adlc2).
The split assigns each concern to the lowest tier that owns it:
_core_fork.py— fork-level extension constants (EXTENSION_NAMESPACES,EXTENSION_ALIAS_PATTERN_ENABLED,FORK_INSTALL_COMMAND),COMMAND_PREFIX,build_alias_map,resolve_command_alias,compute_skill_output_name, MCP config helpers,get_preinstalled_extensions_init_fork.py—ACCENT_COLOR,BANNER_COLORS,TAGLINE,PKG_NAMES,TEAM_DIRECTIVES_DIRNAME,accent,accent_style,apply_theming_patches,pre_init,post_init,get_team_directives_path,sync_team_ai_directives,get_speckit_version,GITHUB_API_LATESTbase_fork.py—detect_native_worktree()extensions_fork.py— worktree constants and config schema
Feature / override table:
| Feature | Upstream Default | Fork Override | Module |
|---|---|---|---|
| ACCENT_COLOR | "cyan" | "#f47721" (tikalk orange) | _init_fork |
| BANNER_COLORS | cyan gradient | orange gradient | _init_fork |
| accent() | N/A | Helper function for theming | _init_fork |
| accent_style() | N/A | Helper for Rich style= params | _init_fork |
| PKG_NAMES | ("specify-cli",) | ("agentic-sdlc-specify-cli", "specify-cli") | _init_fork |
| TEAM_DIRECTIVES_DIRNAME | N/A | "team-ai-directives" | _init_fork |
| EXTENSION_NAMESPACES | ["speckit"] | ["speckit", "adlc"] | _core_fork |
| EXTENSION_ALIAS_PATTERN_ENABLED | False | True | _core_fork |
| COMMAND_PREFIX | "speckit" | "spec" | _core_fork |
The __init__.py file starts with this import block that you should preserve during merges:
# Tikalk fork customizations - import with fallback to upstream defaults
try:
from ._init_fork import (
ACCENT_COLOR,
BANNER_COLORS,
TAGLINE,
accent,
accent_style,
TEAM_DIRECTIVES_DIRNAME,
PKG_NAMES,
pre_init,
post_init,
)
from ._core_fork import compute_skill_output_name
except ImportError:
ACCENT_COLOR = "cyan"
BANNER_COLORS = ["#00ffff", "#00cccc", "cyan", "#009999", "white", "bright_white"]
TEAM_DIRECTIVES_DIRNAME = "team-ai-directives"
PKG_NAMES = ["specify-cli"]
def accent(
text: str, bold: bool = False, italic: bool = False, dim: bool = False
) -> str:
style = ACCENT_COLOR
if bold:
style = f"bold {style}"
if italic:
style = f"italic {style}"
if dim:
style = f"dim {style}"
return f"[{style}]{text}[/]"
def accent_style() -> str:
return ACCENT_COLOR
def pre_init(project_path, selected_ai, team_ai_directives, tracker=None):
pass
def post_init(project_path, selected_ai, tracker=None, no_git=False):
pass
def compute_skill_output_name():
return NoneCritical: This block must include ALL fork customizations with fallbacks, not just partial imports. The import block is the SINGLE SOURCE OF TRUTH for fork customizations - all theming, hooks (pre_init, post_init), and helper functions must be defined here.
In extensions.py, the fork configures command name patterns:
# Get namespaces from customization module (supports speckit and adlc)
try:
from ._core_fork import EXTENSION_NAMESPACES, EXTENSION_ALIAS_PATTERN_ENABLED
except ImportError:
EXTENSION_NAMESPACES = ["speckit"]
EXTENSION_ALIAS_PATTERN_ENABLED = False
EXTENSION_COMMAND_NAME_PATTERN = re.compile(
rf"^(?:{'|' . join(EXTENSION_NAMESPACES)})\.([a-z0-9-]+)\.([a-z0-9-]+)$"
)
if EXTENSION_ALIAS_PATTERN_ENABLED:
EXTENSION_ALIAS_NAME_PATTERN = re.compile(r"^([a-z0-9-]+)\.([a-z0-9-]+)$")
else:
EXTENSION_ALIAS_NAME_PATTERN = NoneThis section documents the complete workflow for merging upstream changes from github/spec-kit.
# Fetch latest upstream changes
git fetch upstream
# Check what commits are new in upstream (not in origin)
git log origin/main --not upstream/main
git log upstream/main --not origin/maingit checkout main
git branch backup-before-upstream-merge-$(date +%Y%m%d)git fetch upstream
git merge upstream/mainCRITICAL: Never use git checkout --theirs for init.py or pyproject.toml
Correct Strategy: Use upstream as clean base, then ADD fork customizations on top.
Upstream has extracted code from __init__.py into separate modules:
| Module | Contents | Fork Action |
|---|---|---|
_console.py |
BANNER, TAGLINE, StepTracker, console | Keep upstream, fork theming overrides in show_banner() |
_version.py |
Version checking, self-update | Override GITHUB_API_LATEST via _init_fork |
_assets.py |
Bundled asset location | Accept as-is |
_utils.py |
Utility functions | Accept as-is |
catalogs.py |
Catalog config loading | Accept as-is |
integration_state.py |
Integration state management | Accept as-is |
- Keep upstream imports from extracted modules (
_console,_assets,_utils,_version) - Keep fork's
_init_forkand_core_forkimport blocks AFTER upstream imports - Keep fork's custom functions that depend on the fork modules:
show_banner()(overrides upstream to apply theming)TEAM_DIRECTIVES_DIRNAME(from_init_fork)sync_team_ai_directives()(imported from_init_fork)get_team_directives_path()(imported from_init_fork)
NEVER use --theirs. Manually edit to preserve fork values:
name = "agentic-sdlc-specify-cli"version = "0.8.X+adlcN"(fork version)description(fork description)- Wheel paths: keep bundled extensions/presets paths
- Keep
httpx>=0.27.0dependency
See Test Merge Strategy section. Do NOT use git checkout --theirs tests/.
Why this works:
- Upstream refactoring isolates code into stable modules
- Fork customizations stay in
_init_fork.py/_core_fork.pyand the__init__.pyimport block - Clear separation of concerns reduces future conflicts
- pyproject.toml needs manual edit to preserve fork version (never use --theirs)
python3 -m pytest tests/ -vUpdate pyproject.toml:
version = "0.3.X" # Increment from current versionAdd new entry at top of changelog (after ## [Unreleased] or before latest release):
## [0.3.X] - YYYY-MM-DD
### Changed
- **Upstream merge**: Synced with github/spec-kit
- [List upstream commits merged]git add -A
git commit -m "chore: merge upstream and bump to v0.3.X"
git push origin maingit tag -a agentic-sdlc-v0.3.X -m "Release agentic-sdlc-v0.3.X"
git push origin agentic-sdlc-v0.3.XExample for this release:
git tag -a agentic-sdlc-v0.10.0+adlc6 -m "Release agentic-sdlc-v0.10.0+adlc6"
git push origin agentic-sdlc-v0.10.0+adlc6The fork dogfoods its own SDD tooling to verify upstream merges. After the git merge and conflict resolution (Steps 1-3) and before tagging (Step 8), treat the upgrade as a change proposal and run it through the full verification pipeline.
Create a change proposal that captures what the upstream merge changed:
/change.specify "Upgrade from upstream <old> to <new>"
The spec should capture:
- Breaking changes — from upstream CHANGELOG / release notes
- New features adopted — new commands, hooks, extension capabilities
- Affected extensions/presets — diff
extension.yml/preset.ymlversions before and after merge - Constitution drift — compare
.specify/memory/constitution.mdagainst the upstream template for new/changed governance principles
To gather this context, run:
# What extension/preset versions changed
git diff HEAD~1 -- extensions/*/extension.yml presets/*/preset.yml
# What constitution principles changed upstream
git diff upstream/main -- .specify/memory/constitution.md 2>/dev/null || \
git diff HEAD~1 -- templates/constitution-template.md
# Upstream changelog entries for this merge range
git log --oneline origin/main..upstream/mainFeed the output as context to /change.specify.
After tests pass (Step 4), run:
/change.converge
This runs the full verification machinery on the upgrade:
- Test Gate — tests must pass before assessment (same as Step 4, but formalized)
- 4-Pillar Assessment — Spec Compliance (did the merge cover all upstream changes?), Code Quality (conflict resolution quality), Test Adequacy (are new features tested?), Risk & Evidence (what could break in existing projects?)
- Evidence bundle — writes
changes/NNN-upgrade/verify.mdwith What Was Checked / What Was NOT Checked / Residual Risks - EDD hook (if installed) — deterministic checks (lint, tests, smoke) + AI evaluation (oracle adequacy, quality gates)
If converge finds gaps → tasks appended to tasks.md → fix → re-converge.
Read changes/NNN-upgrade/verify.md:
- What Was Checked — confirms tests, lint, 4-pillar all ran
- What Was NOT Checked — flags blind spots (e.g., "EDD not installed", "no trace for this change")
- Residual Risks — upgrade-specific risks (e.g., "constitution not updated for new governance model", "extension compatibility not verified")
If all pillars >= 70 and no CRITICAL residual risks → upgrade is verified. Proceed to Step 8 (commit/tag/push).
If any pillar < 70 or CRITICAL risks exist → fix the issues, re-run /change.converge until verified.
This is the fork's answer to the "self-evolving harness" open problem from the SDD
academic literature: the framework applies its own spec-driven verification discipline
to its own upgrades, rather than relying on manual CHANGELOG reading and ad-hoc testing.
The agentic-change preset provides the lifecycle; converge provides the verification;
the evidence bundle provides the audit trail.
When conflicts occur during merge:
- Keep origin changes as base - Our customizations in
_init_fork.py,_core_fork.py,base_fork.py,extensions_fork.pyand the__init__.pyimport block must be preserved - Adapt upstream changes - Integrate upstream improvements to work with our customizations
- Test after resolving - Always run tests before committing
| File | Why It Conflicts | Resolution |
|---|---|---|
__init__.py |
Import block at top | Use our try/except import pattern with fallback |
pyproject.toml |
Version number | Increment version after merge |
CHANGELOG.md |
New entries | Add fork-specific entries, preserve upstream section |
These fork customizations should NEVER be modified unless intentionally updating them:
_init_fork.py,_core_fork.py- Fork customization modulesbase_fork.py,extensions_fork.py- Fork-level helpers and feature constantsextensions.py- Extension namespace configuration- Bundled extensions in
pyproject.toml- levelup, evals, architect, product, tdd, edd - Bundled presets in
pyproject.toml- agentic-sdlc, agentic-change, agentic-quick
The following customization categories live in the fork modules listed in Fork module layout. The mapping is:
- Theming (
_init_fork.py):ACCENT_COLOR,BANNER_COLORS,accent(),accent_style() - Package Identity (
_init_fork.py):PKG_NAMES,TAGLINE,get_speckit_version(),GITHUB_API_LATEST - Team Directives (
_init_fork.py):TEAM_DIRECTIVES_DIRNAME,sync_team_ai_directives(),get_team_directives_path() - Init hooks (
_init_fork.py):pre_init(),post_init(),install_project_skills() - Scaffolding (
_init_fork.py):_scaffold_extensions_to_project(),_scaffold_presets_to_project(), bundled extension/preset installation - Extension Namespaces (
_core_fork.py):EXTENSION_NAMESPACES,EXTENSION_ALIAS_PATTERN_ENABLED,FORK_INSTALL_COMMAND - Command aliasing (
_core_fork.py):COMMAND_PREFIX,build_alias_map(),resolve_command_alias(),compute_skill_output_name(),FORK_COMMAND_NAMESPACES - MCP config (
_core_fork.py):validate_mcp_config(),merge_mcp_configs_report_conflicts(),install_mcp_config() - Native tool detection (
base_fork.py):detect_native_worktree()onIntegrationBase - Worktree constants (
extensions_fork.py):WORKTREE_DEFAULT_ISOLATION_MODE,WORKTREE_VALID_ISOLATION_MODES,WORKTREE_MANIFEST_FILENAME,WORKTREE_BASE_DIR,WORKTREE_TASK_BRANCH_PATTERN,WORKTREE_CONFIG_KEY,WORKTREE_CONFIG_SCHEMA - Bundled-asset helpers (
_assets_fork.py):get_bundled_extension_version(),get_bundled_extension_path(),get_bundled_preset_version(),get_bundled_preset_path(), fork_locate_bundled_preset()
The following tikalk-specific features are still defined directly in __init__.py because they require access to internal functions and the central app context:
install_bundled_extensions()- Installs bundled extensions during initinstall_bundled_presets()- Installs bundled presets during initsync_team_ai_directives()- Syncs team-ai-directives repository
These functions are called during init but don't conflict with upstream because they use conditional checks (e.g., if skip_bundled:).
The re-export shim get_preinstalled_extensions() is also kept here because downstream consumers expect it on the top-level package; the canonical implementation now lives in _core_fork.py.
The following files and directories exist only in the fork and were never present in upstream. During merges, git will show these as "deleted by them" — always reject the deletion.
File: src/specify_cli/_init_fork.py
The largest of the fork modules; holds theming, package identity, init hooks, team directives, and bundled extension/preset scaffolding. See Fork module layout for the dependency chain.
Key exports:
- Theming:
ACCENT_COLOR,BANNER_COLORS,accent(),accent_style(),apply_theming_patches() - Package Identity:
PKG_NAMES,TAGLINE,get_speckit_version(),GITHUB_API_LATEST - Team Directives:
TEAM_DIRECTIVES_DIRNAME,sync_team_ai_directives(),get_team_directives_path() - Init hooks:
pre_init(),post_init(),install_project_skills() - Scaffolding:
_scaffold_extensions_to_project(),_scaffold_presets_to_project(),_install_bundled_extensions(),_install_bundled_presets() - Extension Namespaces:
EXTENSION_NAMESPACES,EXTENSION_ALIAS_PATTERN_ENABLED(defined in_core_fork.py)
Total: ~1700 lines of fork-only code, split across five modules:
| Module | Approx. size | Role |
|---|---|---|
_init_fork.py |
~1000 | Theming, init hooks, scaffolding |
_core_fork.py |
~430 | Fork-level extension constants, alias/MCP/skill helpers |
_assets_fork.py |
~150 | Bundled-asset version/path helpers |
base_fork.py |
~15 | detect_native_worktree() |
extensions_fork.py |
~25 | Worktree constants |
File: src/specify_cli/_assets_fork.py
Leaf fork module that wraps _assets.py (clean upstream) with fork-specific bundled-asset discovery. Moved here in 0.10.0+adlc12 to restore _assets.py to clean-upstream.
Key exports:
_locate_bundled_preset(): upstream locator +bundled_presets/fallback for wheel/uv-tool installsget_bundled_extension_version(),get_bundled_extension_path()(relocated from adlc4)get_bundled_preset_version(),get_bundled_preset_path()
The following test files are fork-only:
tests/test_fork_inventory.py— Fork inventory teststests/integrations/test_fork_inventory.py— Integration inventory teststests/test_bundled_extension_hooks.py— Bundled extension hook teststests/test_check_prerequisites_risks.py— Prerequisite risk teststests/test_create_new_feature.py— Feature creation teststests/auth_helpers.py— Authentication test helperstests/test_team_directives.py— Team AI directives teststests/test_project_skills.py— Project skills install tests
The fork adds feature-level git worktree isolation and DAG-aware task execution to the bundled git extension. The work follows obra/superpowers using-git-worktrees principles (provenance-based cleanup, native tool preference) while staying inside the existing git extension rather than shipping a separate one.
The git extension already owns git.feature, git.validate, git.commit, and the related hook pipeline (auto-commit before/after every core command). Feature-level isolation is a natural fit for git.feature, and the task-execution commands (git.task, git.task-merge, git.task-list) only make sense as siblings of git.feature. Adding a separate worktrees extension would have duplicated the git.feature hook wiring and forced an inter-extension dependency for the most common path.
git.feature now accepts worktree-isolation flags on both bash and PowerShell. Source priority is CLI flag > SPECIFY_ISOLATION_MODE env > git-config.yml isolation_mode key > default branch.
| Bash flag | PowerShell param | Meaning |
|---|---|---|
--worktree |
-Worktree |
Force worktree mode (shorthand for --isolation-mode worktree) |
--branch-mode |
-BranchMode |
Force branch mode (shorthand for --isolation-mode branch) |
--isolation-mode <branch|worktree> |
-IsolationMode <branch|worktree> |
Explicit mode selection |
--base <branch> |
-Base <branch> |
Pin the base ref (used by git worktree add); defaults to the current branch |
When worktree mode is selected, the script:
- Calls
worktree-utils.sh create-feature-worktree --feature <branch> [--base <base>](or the PowerShell counterpart) instead ofgit checkout -b - Writes a
git.worktree-manifest.jsonto the worktree root for provenance tracking - Returns
ISOLATION_MODE,WORKTREE_PATH, andMANIFEST_PATHin the JSON output (in addition toBRANCH_NAME/FEATURE_NUM) - Does not
cdinto the worktree — the calling agent mustcd "$WORKTREE_PATH"separately
Unrecognized isolation mode values are rejected with Error: --isolation-mode must be 'branch' or 'worktree'.
Three new git extension commands were added in this release. They are worktree-mode only and refuse to run in a primary checkout.
| Command | Purpose | Script |
|---|---|---|
speckit.git.task (git.task) |
Create/resume a task branch in the current feature worktree and dispatch the task to a subagent | worktree-utils.sh create-task-branch |
speckit.git.task-merge (git.task-merge) |
Merge a completed task branch back into the feature branch (git merge --no-ff); delegates conflict resolution to a subagent; then unregisters the task branch via worktree-utils.sh merge-task-branch |
worktree-utils.sh merge-task-branch |
speckit.git.task-list (git.task-list) |
List active task branches in the current worktree (with ahead/behind counts); supports --json and --ids-only output |
worktree-utils.sh read-manifest |
These commands are declared in extensions/git/extension.yml and reference .md files under extensions/git/commands/. The is-in-worktree script (exit 0 = primary, exit 2 = inside a worktree) is the gate that all three check before proceeding.
Two new dispatcher scripts (one Bash, one PowerShell) were added. They follow the project's single-file dispatcher pattern (matching auto-commit.sh): the script name is a subcommand, and <subcommand> [args...] is dispatched via a case (bash) or switch (PS1) block.
| Script | Subcommands | Purpose |
|---|---|---|
worktree-utils.{sh,ps1} |
create-feature-worktree, remove-feature-worktree, create-task-branch, remove-task-branch, merge-task-branch, is-in-worktree, list-worktrees, read-manifest, finish-feature |
All worktree lifecycle operations, with JSON output to stdout and human-readable status to stderr |
tasks-dag.{sh,ps1} |
generate, validate, show, classify, coalesce |
DAG generation from tasks.md (wave computation, parallel-marker validation, coalescing suggestions) |
Both scripts are ASCII-only. The PowerShell version uses single-dash params (-TasksMd, -Dag, -Feature, -TaskId); the bash version uses double-dash (--tasks-md, --dag, --feature, --task-id). The header comment in each PowerShell script documents this divergence.
Each feature worktree has a git.worktree-manifest.json at its root. The manifest is gitignored (tasks_dag.json, git.worktree-manifest.json, and .worktrees/ are added to .gitignore by git.setup-ignore). Schema:
{
"schema_version": "1.0",
"feature": "003-user-auth",
"feature_branch": "003-user-auth",
"worktree_path": ".worktrees/003-user-auth",
"created_at": "2026-06-07T15:30:00Z",
"task_branches": [
{"id": "T007", "branch": "003-user-auth--task-7-add-oauth-provider", "created_at": "2026-06-07T15:35:12Z"}
],
"provenance": {
"created_by": "worktree-utils.sh create-feature-worktree",
"version": "1.0"
}
}finish-feature (and remove-feature-worktree) use this manifest to clean up: delete all listed task branches, remove the worktree, then delete the feature branch. --keep-branch opts out of the final feature-branch deletion; --force opts out of the safety checks (manifest missing, task branches remaining, dirty worktree).
tasks-dag.sh generate writes tasks_dag.json alongside tasks.md (the same path with a .dag.json suffix). Schema:
{
"schema_version": "1.0",
"feature": "003-user-auth",
"tasks": [
{"id": "T001", "title": "...", "files": ["src/auth.py"], "story": "Setup", "parallel": false, "execution_wave": 0, "depends_on": []}
],
"execution_waves": [[0, 1, 2], [3, 4, 5], ...],
"stats": {"total_tasks": 12, "parallel_tasks": 8, "total_waves": 5, "stories": 2}
}execution_wave is 0-based per task. execution_waves is the canonical 1-based wave grouping. The DAG is consumed by the ADLC preset's adlc.spec.implement (Phase 0: read tasks_dag.json).
auto-commit.sh and auto-commit.ps1 now accept --mode <sync|parallel|async> and --task-id <TNNN>. When the mode is parallel or async and a task-id is supplied, the commit subject is prefixed with [TNNN] (e.g., [T007] [Spec Kit] Auto-commit after implement). The prefix is idempotent (re-prefixing an already-prefixed subject is a no-op). Env-var fallback: SPECKIT_TASK_MODE / SPECKIT_TASK_ID (precedence: flag > env > default sync).
This is what makes subagent-dispatched task work show up cleanly in git log per-task, without forcing the implementer to construct a custom message.
git.setup-ignore (and its .ps1 sibling) was extended with four new ignore rules:
| Rule | What it covers |
|---|---|
.worktrees/ |
All feature worktrees (ephemeral; not for version control) |
tasks_dag.json |
DAG sidecar written by tasks-dag.sh generate (ephemeral; rebuilt on every tasks run) |
git.worktree-manifest.json |
Worktree manifest (ephemeral; rebuilt by worktree-utils.sh create-feature-worktree) |
.speckit-merge-conflict-*.md |
Merge-conflict resolution prompts (ephemeral; deleted after conflict resolution) |
The existing setup-gitignore.{sh,ps1} script was extended (not duplicated) — the markdown command file speckit.git.setup-ignore.md was updated in lockstep to keep the user-facing documentation and the script's actual ignore list in sync.
extensions/git/config-template.yml was extended with three new top-level sections:
isolation_mode: branch # branch | worktree
worktrees:
base_dir: .worktrees
manifest_filename: git.worktree-manifest.json
task_branch_pattern: "{feature}--task-{id}-{task-slug}"
task_execution:
default_mode: sync # sync | parallel | async
parallel_threshold_wave_size: 2
delegate_merge_conflicts: true
task_generation:
parallel_marker_default: true
coalesce_simple_tasks: true
max_tasks_per_story: 8isolation_mode is the only key the git.feature script actually reads today (via grep -E '^[[:space:]]*isolation_mode'); the other sections are read by the ADLC preset's adlc.spec.implement and tasks template.
Three new test files cover the worktree scripts, DAG scripts, and the new git.feature / auto-commit / setup-gitignore flags:
tests/extensions/git/test_git_worktree.py(55 tests total — bash + PowerShell)tests/extensions/git/test_tasks_dag.py(33 tests total — bash + PowerShell)- Additions to
tests/extensions/git/test_git_extension.py:TestAutoCommitTaskModeBash/PowerShell(18 tests),TestCreateFeatureIsolationModeBash/PowerShell(17 tests),TestSetupGitignoreWorktreeBash/PowerShell(6 tests)
These tests use the existing _setup_project harness from test_git_worktree.py and require no PKG_NAMES skip-guards — the worktree/DAG scripts are designed to run identically upstream and in the fork (no fork-only constants referenced; defaults are hard-coded in the scripts).
Run tests to verify customization module works correctly:
python3 -c "
from src.specify_cli import ACCENT_COLOR, BANNER_COLORS, accent, accent_style
from src.specify_cli.extensions import EXTENSION_COMMAND_NAME_PATTERN
print('ACCENT_COLOR:', ACCENT_COLOR)
print('accent test:', accent('Test', bold=True))
print('Extension pattern:', EXTENSION_COMMAND_NAME_PATTERN.pattern)
"Expected output:
ACCENT_COLOR: #f47721
accent test: [bold #f47721]Test[/]
Extension pattern: ^(?:speckit|adlc)\.([a-z0-9-]+)\.([a-z0-9-]+)$
IMPORTANT: The fork uses the tag pattern agentic-sdlc-v* to distinguish from upstream v* tags.
Upstream uses tags like v0.5.0, v0.5.1, etc. These tags from origin trigger GitHub Actions workflows designed for upstream, which causes confusion and wasted CI runs.
- Fork tags:
agentic-sdlc-v0.3.11(our releases) - Upstream tags:
v0.5.0(from upstream/main, don't push these to origin)
Always check before pushing to avoid triggering upstream workflows:
# Check what tags you're about to push
git push origin --dry-run --tags
# List only fork-pattern tags
git tag -l "agentic-sdlc-*"When a tag is force-replaced (deleted and re-created), the associated GitHub Release becomes a draft and must be manually published:
- After pushing the re-created tag, visit:
https://github.com/tikalk/agentic-sdlc-spec-kit/releases - Find the draft release for the tag
- Click Edit → verify content → Publish release
This is required because GitHub does not auto-publish releases on tag re-creation — the release stays in draft state until manually confirmed.
If upstream tags get pushed to origin by mistake, remove them:
# Local cleanup
git tag -l "v*" | xargs -I {} git tag -d {}
# Remote cleanup (example for v0.5.0)
git push origin --delete v0.5.0Or delete multiple at once:
git push origin --delete v0.0.1 v0.1.0 v0.2.0 v0.5.0Tests should be manually merged (NOT git checkout --theirs tests/):
- Accept upstream test refactoring for new extracted modules (
test_console_imports.py,test_version_imports.py,test_utils_assets_imports.py) - Keep fork-only test files that upstream shows as "deleted" (they were never upstream):
tests/test_fork_inventory.pytests/integrations/test_fork_inventory.pytests/test_bundled_extension_hooks.pytests/test_check_prerequisites_risks.pytests/test_create_new_feature.pytests/auth_helpers.pytests/test_team_directives.py
- Merge and re-apply
PKG_NAMESskip guards to upstream tests that expect upstream-only behavior - New fork tests are additive — they should not conflict with upstream tests
def test_complete_file_inventory_sh(self, tmp_path):
"""Every file produced by specify init --integration <key> --script sh."""
from specify_cli import PKG_NAMES
if any("agentic-sdlc" in pkg for pkg in PKG_NAMES):
import pytest
pytest.skip("Fork has bundled extensions/presets with different file counts")
# ... rest of testUpstream _version.py hardcodes GitHub API URLs pointing to github/spec-kit:
GITHUB_API_LATEST = "https://api.github.com/repos/github/spec-kit/releases/latest"The fork should override these via _init_fork.py:
GITHUB_API_LATEST→ point totikalk/agentic-sdlc-spec-kitreleases- Install instructions → reference fork's repo URL
This section documents common CI failures and how to debug them.
Symptom: ruff fails with invalid-syntax: Expected ,, found <<
Example error:
invalid-syntax: Expected `,`, found `<<`
--> src/specify_cli/__init__.py:1064:1
|
1064 | <<<<<<< HEAD
| ^^
Cause: Merge conflict not fully resolved - <<<<<<< HEAD markers remain in code
Fix:
# Find remaining conflict markers
grep -rn "<<<<<< HEAD" src/
# Fix in editor (remove the marker line)
# Verify fix
uvx ruff check src/
# Commit and push
git add -A
git commit -m "fix: remove unresolved merge conflict marker"
git push origin mainPrevention: Always run uvx ruff check src/ locally before pushing
Symptom: pytest fails after upstream merge
Fix:
# Run tests locally
uv run pytest
# If tests fail, investigate and fix
# Then commit and pushSymptom: Tests fail on specific Python versions in CI matrix
Fix: Ensure code is compatible with Python 3.11, 3.12, and 3.13
- Check the workflow run: Look at the GitHub Actions logs for the specific error
- Reproduce locally: Run the same commands locally:
uvx ruff check src/ uv run pytest
- Check for conflicts:
grep -rn "<<<<<<" src/ - Review recent changes:
git log --oneline -10
This section documents hard-won lessons from merging upstream changes.
-
NEVER use
git checkout --theirsfor pyproject.toml or init.py- Using
--theirson pyproject.toml discards the fork version entirely - The stash with fork changes gets lost
- Always manually edit to preserve fork values after merge
- Using
-
Use upstream as clean base, then ADD fork customizations
- Merge upstream/main cleanly first
- Then manually add fork-specific functions/values AFTER merge
- This prevents accidental overwriting
-
The import block is the SINGLE SOURCE OF TRUTH
- All fork customizations must be in the try/except import block
- Both the imports AND the fallback functions must be complete
- Missing fallbacks = runtime errors when the fork modules are not available
The fork uses specify_cli/core_pack/... paths (NOT root-level directories):
[tool.hatch.build.targets.wheel.force-include]
# Tikalk bundled extensions
"extensions/levelup" = "specify_cli/core_pack/extensions/levelup"
"extensions/evals" = "specify_cli/core_pack/extensions/evals"
"extensions/architect" = "specify_cli/core_pack/extensions/architect"
"extensions/product" = "specify_cli/core_pack/extensions/product"
"extensions/tdd" = "specify_cli/core_pack/extensions/tdd" # Don't forget!
# Tikalk bundled presets
"presets/agentic-sdlc" = "specify_cli/bundled_presets/agentic-sdlc"
# Core pack assets
"templates/agent-file-template.md" = "specify_cli/core_pack/templates/agent-file-template.md"
# ... etcCommon mistake: Using root-level paths like "extensions/levelup" = "extensions/levelup" will cause build errors because those paths don't exist inside the wheel.
After merging upstream, ensure these are present in init.py:
- Full import block (see above) - with ALL imports and fallbacks
- TEAM_DIRECTIVES_DIRNAME - for team-ai-directives feature
- _run_git_command() - helper for git operations
- sync_team_ai_directives() - clones/updates team repo
- compute_skill_output_name() - delegates to
_core_fork - TAGLINE - fork's tagline (different from upstream)
Apply theming to all UI elements using accent_style() and accent():
show_banner(): UseBANNER_COLORSandaccent_style()for tagline- StepTracker title:
f"[{accent_style()}]{self.title}" - "Selected AI assistant:" and "Selected script type:": Use
accent() - "Project ready.": Use
accent(bold=True) - All Panel borders: Use
border_style=accent_style() - Next Steps and Enhancement Commands panels
The init flow must include these steps in order:
for key, label in [
("chmod", "Ensure scripts executable"),
("project-skills", "Install Projects skills"),
("constitution", "Constitution setup"),
("git", "Install git extension"),
("workflow", "Install bundled workflow"),
("team-directives", "Team AI Directives setup"),
("extensions", "Install bundled extensions"),
("presets", "Install bundled presets"),
]:
tracker.add(key, label)
# Final MUST be added LAST
tracker.add("final", "Finalize")The fork uses /spec.* prefix instead of upstream's /speckit.*:
def _display_cmd(name: str) -> str:
# ... agent-specific cases ...
# Fork default: use "spec." prefix instead of "speckit."
return f"/spec.{name}"Always create a backup branch BEFORE merging:
git branch backup-before-upstream-merge-$(date +%Y%m%d-%H%M%S)This allows you to:
- Compare against backup to see exactly what changed
- Restore any accidentally lost customizations
- Debug issues by comparing working vs broken state
The fork bundles extensions, presets, and skills that aren't present in upstream. This causes the test_complete_file_inventory_* tests to fail because they expect upstream's file count.
Solution: Skip these tests on the fork by checking PKG_NAMES:
def test_complete_file_inventory_sh(self, tmp_path):
"""Every file produced by specify init --integration <key> --script sh."""
from specify_cli import PKG_NAMES
if any("agentic-sdlc" in pkg for pkg in PKG_NAMES):
import pytest
pytest.skip("Fork has bundled extensions/presets with different file counts")
# ... rest of testThis check exists in:
tests/integrations/test_integration_base_markdown.pytests/integrations/test_integration_base_skills.py
The tests pass upstream (no skip) and skip on the fork (with skip), ensuring CI passes in both environments.