Skip to content

feat(scripts): add SPECIFY_INIT_DIR to target a member project from the repo root#2892

Open
PascalThuet wants to merge 6 commits into
github:mainfrom
PascalThuet:feat/monorepo-init-dir
Open

feat(scripts): add SPECIFY_INIT_DIR to target a member project from the repo root#2892
PascalThuet wants to merge 6 commits into
github:mainfrom
PascalThuet:feat/monorepo-init-dir

Conversation

@PascalThuet
Copy link
Copy Markdown
Contributor

@PascalThuet PascalThuet commented Jun 7, 2026

Summary

Adds SPECIFY_INIT_DIR as an explicit project-root override for Spec Kit scripts that may be invoked from outside the target project, such as a monorepo root or CI task.

Behavior

  • SPECIFY_INIT_DIR=/path/to/project makes supported scripts operate on that Spec Kit project.
  • The value must resolve to an existing directory containing .specify/.
  • Invalid values fail fast. Scripts do not silently fall back to cwd or the git toplevel.

Changes

  • Adds Bash and PowerShell project-root resolvers for SPECIFY_INIT_DIR.
  • Applies the override to core scripts and bundled git / agent-context extension scripts.
  • Keeps extension scripts able to run without current core scripts installed.
  • Documents the environment variable in the core reference.
  • Adds tests for valid targets, invalid targets, relative paths, monorepo-style invocation, and legacy-core extension fallback.

Validation

  • uv run pytest tests/test_init_dir.py tests/extensions/git/test_git_extension.py tests/test_extensions.py -q
  • uvx ruff check tests/extensions/git/test_git_extension.py
  • bash -n extensions/git/scripts/bash/create-new-feature.sh extensions/git/scripts/bash/git-common.sh scripts/bash/common.sh
  • git diff --check

pwsh is not available in my local environment, so PowerShell tests are included but skipped locally.

PascalThuet and others added 6 commits June 7, 2026 16:30
…utside its directory

Adds a project-root override so a non-interactive / CI caller can run a Spec Kit
command against a member project (e.g. apps/web in a monorepo) from outside that
directory, without cd. SPECIFY_INIT_DIR names the project root — the directory
containing .specify/ — and is honored by get_repo_root in scripts/bash/common.sh,
mirrored in scripts/powershell/common.ps1.

Strict by design, per maintainer guidance on github#2834: when set, the path must exist
and contain .specify/, otherwise the resolver hard-errors and never falls back to
the current directory or the git toplevel (which would silently write to the wrong
project's specs/). Relative paths normalize against the current directory (with
CDPATH="" to avoid CDPATH-based misresolution); trailing slashes are tolerated; an
empty string is treated as unset.

Resolution stays two independent axes: SPECIFY_INIT_DIR selects the project, while
SPECIFY_FEATURE_DIRECTORY / .specify/feature.json / branch detection select the
feature within it (project-then-feature). The bash get_repo_root call sites that
feed real resolution are split into decl/assignment so the hard error propagates
instead of being masked by `local`.

Env var only; the --project CLI flag is deferred. Adds tests/test_init_dir.py
(positive + negative, bash and PowerShell) and documents the variable and the
two-axis precedence in docs/reference/core.md.

Refs: github#2834

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extends SPECIFY_INIT_DIR coverage to the bundled Git extension — the actual
/speckit.specify before_specify entrypoint — so a monorepo/CI user setting it
gets the feature branch created in, and auto-commit run against, the targeted
project rather than the cwd/git toplevel. create-new-feature.sh/.ps1 and
auto-commit.sh/.ps1 now resolve the project root from SPECIFY_INIT_DIR first,
with the same strict contract as core (must exist + contain .specify/, hard
error, no silent fallback). Adds bash tests for the git entrypoint.

Also addresses the max-effort review of the diff:
- common.sh: split the remaining `local x=$(get_repo_root)` /
  `local x=$(get_current_branch)` call sites (has_git, get_feature_paths) so a
  SPECIFY_INIT_DIR validation failure is never masked by `local`.
- docs: note that the agent-context update selects the most recently modified
  plan within the resolved project (feature-axis selectors apply to the core
  feature scripts), and that SPECIFY_INIT_DIR is honored by core + git ext.
- CHANGELOG: drop the hand-added [Unreleased] block; the release workflow
  generates entries from commit subjects, so manual entries would duplicate.

Refs: github#2834

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses the duplication the review flagged: the strict SPECIFY_INIT_DIR
validation was inlined per-script across the git extension. Extract it into a
named resolver — resolve_specify_init_dir (bash) / Resolve-SpecifyInitDir
(PowerShell) — defined once per independently-shippable library:

- core scripts/bash/common.sh + scripts/powershell/common.ps1 (get_repo_root
  now delegates to it)
- extensions/git git-common.sh + git-common.ps1 (create-new-feature and
  auto-commit call it instead of carrying their own inline copy)

The three libraries still each carry one copy because the git and agent-context
extensions must run without the core scripts installed — a single cross-library
source would couple them — but the per-script inline duplication within the git
extension is gone, and each copy is now a named, greppable function that is
trivial to diff and keep in sync. Behavior and error strings are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@PascalThuet PascalThuet marked this pull request as ready for review June 7, 2026 20:55
@PascalThuet PascalThuet requested a review from mnriem as a code owner June 7, 2026 20:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant