Repository navigation
A spec.md symlink to a file elsewhere in the same project is refused since 1.8.0 #2100
Description
What happened
Since 1.8.0, every command that reads main specs refuses an openspec/specs/<capability>/spec.md that is a symlink to a file elsewhere in the same repository:
✖ Error: Path is outside the allowed directory: <repo>/openspec/specs/login/spec.md
list --specs reports "No specs found", show and validate fail, and archive refuses to merge deltas into the spec. 1.7.0 handles the same layout correctly. Still present in 1.14.2.
We keep our main specs next to the product documentation they belong to (docs/<area>/specs/<capability>.md), not under openspec/specs/. Each openspec/specs/<capability>/spec.md is a relative symlink to that file, so OpenSpec and the docs read and write the same bytes. 1.7.0 supported this explicitly: #1437 made "symlinked specs/<capability>/spec.md files … discovered instead of silently dropped".
What you expected instead
A spec.md link whose target stays inside the same project to be accepted, as in 1.7.0.
The containment check from #1499 uses the specs root as the boundary for a spec.md link. But since #2052 (1.14.2), openspec/specs itself may be a project-owned symlink to a directory in another repository, and a symlinked capability directory may resolve outside the project (with an OpenSpecExternalSpecWrite warning). A spec.md link that stays inside the project is the more contained case. For example, the project root could be the boundary for a capability's spec.md link, while targets outside the project are still refused.
Moving to directory symlinks doesn't work for this layout: a symlinked capability directory is accepted by show and archive but invisible to list --specs and validate --specs, and a symlinked openspec/specs only works if the docs adopt the <capability>/spec.md naming.
Minimal steps to reproduce
mkdir -p repo/docs/auth/specs repo/openspec/specs/login repo/openspec/changes && cd repo && git init -q
printf '# login\n\n## Purpose\nUsers sign in with their credentials to reach their account.\n\n## Requirements\n\n### Requirement: Sign in\nThe system SHALL let a user sign in with valid credentials.\n\n#### Scenario: Valid credentials\n- **WHEN** the user submits valid credentials\n- **THEN** the user is signed in\n' > docs/auth/specs/login.md
ln -s ../../../docs/auth/specs/login.md openspec/specs/login/spec.md
npx @fission-ai/openspec@1.7.0 list --specs # login requirements 1
npx @fission-ai/openspec@1.7.0 validate login --type spec # Specification 'login' is valid
npx @fission-ai/openspec@1.14.2 list --specs # Error: Path is outside the allowed directory
npx @fission-ai/openspec@1.14.2 validate login --type spec # Error: Path is outside the allowed directoryRelated: #2050 / #2052, the same regression since 1.8.0 for symlinked openspec/changes and openspec/specs directories.
OpenSpec version
1.14.2 (works in 1.7.0, broken since 1.8.0)
Coding agent and model
Claude Code (not agent-specific: plain CLI commands reproduce it)
OS and Node version
Ubuntu 24.04, Node 26.5.1
Activity
fix(specs): anchor the project boundary on a real planning root
test(specs): guard the reported layout through the real CLI
fix(specs): accept a spec.md symlink to a file elsewhere in the proje…