Add custom schema support to openspec init#1115
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
✅ Files skipped from review due to trivial changes (2)
📝 WalkthroughWalkthroughAdds non-interactive schema selection to ChangesNon-interactive schema selection
🎯 3 (Moderate) | ⏱️ ~25 minutes Sequence Diagram(s)sequenceDiagram
participant CLI as openspec CLI
participant Init as InitCommand
participant Schema as SchemaResolver
participant FS as Filesystem
participant Config as ConfigWriter
CLI->>Init: invoke init with { --schema, --schema-source, --force, --profile, --tools }
Init->>Schema: parseSchema / resolveSchema (load schema.yaml from source when provided)
Schema-->>Init: schemaName (from bundle or built-in)
Init->>FS: copy schema bundle -> openspec/schemas/<schemaName> (rm+cp) [when importing]
Init->>Config: createConfig(schemaName, ...)
Config-->>Init: config written
Init-->>CLI: displaySuccessMessage(configStatus, schemaName)
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
1aee590 to
4a892cb
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/core/init.ts`:
- Around line 332-345: The validation currently allows artifact.template values
that resolve outside the schema bundle root; update
validateSchemaSourceTemplates to resolve each candidate path (for the
'templates' subfolder and root) using path.resolve and ensure the resolved path
is inside sourceDir (e.g., via path.relative or startsWith check) before
accepting it; if neither resolved candidate exists or both resolve outside
sourceDir, throw the same error referencing artifact.template and artifact.id.
Use the existing validateSchemaSourceTemplates function, the artifact.template
value, and sourceDir as the identifiers to locate and fix the logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 86fa0d66-0385-4a12-bdb8-8b88d3c05e23
📒 Files selected for processing (7)
docs/cli.mddocs/customization.mdsrc/cli/index.tssrc/core/completions/command-registry.tssrc/core/init.tstest/cli-e2e/basic.test.tstest/core/init.test.ts
✅ Files skipped from review due to trivial changes (2)
- docs/customization.md
- docs/cli.md
4a892cb to
96c1dfb
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/core/init.ts`:
- Around line 332-348: In validateSchemaSourceTemplates, the current check uses
lexical containment and fs.existsSync which allows symlink escape; change it to
canonicalize the sourceDir once (use FileSystemUtils.canonicalizeExistingPath or
realpathSync) and for each candidate path (templatePathInTemplates and
templatePathInRoot) canonicalize those existing targets as well and then use
isSameOrDescendant against the canonical sourceDir to reject any template whose
realpath lies outside the sourceDir; alternatively, explicitly detect symlinks
with fs.lstatSync(...).isSymbolicLink() and reject them before accepting the
template so imports (cp with preserved symlinks) cannot escape the bundle.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: d4b7920e-de44-42fa-9427-e695223b62a1
📒 Files selected for processing (7)
docs/cli.mddocs/customization.mdsrc/cli/index.tssrc/core/completions/command-registry.tssrc/core/init.tstest/cli-e2e/basic.test.tstest/core/init.test.ts
✅ Files skipped from review due to trivial changes (1)
- docs/cli.md
Allow `openspec init` to initialize projects with a requested workflow schema and import a schema bundle directory into `openspec/schemas/<name>/`. The imported schema is validated before setup continues, existing configs are preserved, and the new options are documented with focused CLI and init tests.
96c1dfb to
db32a2f
Compare
alfred-openspec
left a comment
There was a problem hiding this comment.
This is directionally good. Init-time schema import is a real workflow need, and the referenced-template path escape issue looks fixed.
One remaining safety issue before approval: --schema-source still copies the whole source directory recursively, so unreferenced symlinks inside the bundle can be preserved into openspec/schemas/<name>/ even when schema.yaml does not reference them. Please reject symlinks anywhere in the source bundle, or use an explicit safe-copy path that refuses them, and add a regression test for an unreferenced symlink.
Also note GitHub currently reports this PR as conflicting with main. I checked the diff against the init/schema path and ran pnpm exec vitest run test/core/init.test.ts test/cli-e2e/basic.test.ts locally on the PR head, which passed.
Summary
Adds custom schema support to
openspec init.Users can now initialize a project with an existing workflow schema via
--schema <name>, or import an external schema bundle directory via--schema-source <dir>.Usage
Use an already resolvable schema:
Import an external schema bundle directory:
The imported schema bundle must be a directory containing schema.yaml and its
templates. OpenSpec reads the schema name from schema.yaml, copies the bundle
into:
and writes:
to openspec/config.yaml.
If both --schema and --schema-source are provided, their schema names must
match.
Use Case
Teams may manage shared OpenSpec schemas outside individual repositories, such
as in an internal platform or tooling project that standardizes proposal,
design, spec, and task templates across many codebases.
Previously, those teams had to initialize with the default schema, manually copy
schema files into the target project, and edit openspec/config.yaml. This
change makes that workflow a single init command while keeping the target
project self-contained and reproducible.
Changes
Adds openspec init --schema
Adds openspec init --schema-source
Imports schema bundle directories into openspec/schemas//
Validates imported schema structure and referenced templates before setup
Preserves existing openspec/config.yaml / config.yml
Updates shell completion metadata
Adds focused unit and CLI e2e coverage
Updates CLI and customization docs
Summary by CodeRabbit
New Features
Documentation
Tests