Intelligent prs init & Migration Flow¶
Date: 2026-03-20 Status: Implemented Scope: packages/cli, packages/importer
Problem¶
The current prs init creates config + template files but only shows a passive hint when existing AI instruction files are detected. Migration requires separate manual steps (prs import, prs init --migrate) that are disconnected from the init flow. Users must figure out the migration path themselves.
Goals¶
- Detect existing instruction files and offer migration inline during init
- Support static import (fast, deterministic) and AI-assisted migration (skill + kick-start prompt)
- Multi-file import with modular .prs output (recommended project structure)
- Minimize manual work — guide the user step by step
- Safe for CI/CD with explicit opt-in flags
Non-Goals¶
- Reverse sync (importing manual changes from compiled output back to .prs) — future feature
- LLM API calls from CLI — we generate prompts, not call models
- Auto-compile after init — user reviews .prs first
Design¶
1. Command Flow & Decision Tree¶
prs init
│
├─ promptscript.yaml exists? (no --force)
│ YES → "Already initialized"
│ → hint: "Use --force to reinitialize"
│ → exit(2)
│
├─ Detect: project info, AI tools, migration candidates
│
├─ Migration candidates found?
│ │
│ ├─ YES → Gateway prompt:
│ │ "Found existing instruction files:"
│ │ " CLAUDE.md (3.4 KB, Claude Code)"
│ │ " .cursorrules (1.8 KB, Cursor)"
│ │
│ │ ? How would you like to start?
│ │ > 🔄 Migrate existing instructions to PromptScript
│ │ ✨ Fresh start (ignore existing files)
│ │
│ └─ NO → straight to Fresh Start flow
│
├─ FRESH START flow:
│ 1. Standard init prompts (name, registry, targets)
│ 2. Create promptscript.yaml + scaffold .promptscript/project.prs
│ 3. Install PromptScript skill to all targets
│ 4. "Next: use /promptscript in your AI tool to fill in project.prs"
│
└─ MIGRATE flow:
1. Standard init prompts (name, registry, targets)
2. Create promptscript.yaml
3. Migration strategy prompt:
? How do you want to migrate?
> 📋 Static import (fast, deterministic)
🤖 AI-assisted migration (installs skill + generates prompt)
│
├─ STATIC:
│ 1. Git safety check (warn if no git repo)
│ 2. Ask: "Backup to .prs-backup/?" (default: no if git, yes if no git)
│ 3. Select files to import (checkbox, all pre-checked)
│ 4. Run multi-file import → modular .prs structure
│ 5. Show confidence report
│ 6. Install PromptScript skill to targets
│ 7. "Next: review .prs files, then prs compile"
│
└─ AI-ASSISTED:
1. Git safety check (warn if no git repo)
2. Ask: "Backup to .prs-backup/?" (default: no if git, yes if no git)
3. Create scaffold .promptscript/project.prs
4. Install PromptScript skill to targets (before compile)
5. Generate kick-start prompt (file list + migration instructions)
6. Copy to clipboard / display in terminal
7. Save to .promptscript/migration-prompt.md
8. "Next: paste this prompt in your AI tool"
2. Multi-file Static Import & Modular Output¶
Import pipeline¶
Detected files: CLAUDE.md, .cursorrules, copilot-instructions.md
│ │ │
▼ ▼ ▼
importFile() importFile() importFile()
│ │ │
▼ ▼ ▼
ScoredSection[] per file (with source attribution)
│
▼
mergeSections() — group by target block type
│
▼
Deduplicate — exact match after whitespace normalization
│
▼
Emit modular .prs structure
Output structure¶
.promptscript/
project.prs # Entry: @meta, @inherit, @use directives, @identity
context.prs # @context (merged from all sources)
standards.prs # @standards (merged, categorized)
restrictions.prs # @restrictions (union of all sources)
commands.prs # @shortcuts + @knowledge (if found, grouped as supplementary content)
Files are only emitted if they contain content. If no @shortcuts or @knowledge sections are found, commands.prs is not created. Users can reorganize the modular structure after import.
project.prs contains @use directives pointing to the modular files:
@meta {
id: "my-project"
syntax: "1.4.7"
}
@use ./context
@use ./standards
@use ./restrictions
@use ./commands
@identity {
"""
[merged identity from primary source]
"""
}
Merge rules per block type¶
| Block | Strategy | Conflict resolution |
|---|---|---|
@identity | Pick longest (highest character count after trim) | Others added as # REVIEW: alt from <source> |
@context | Union structured fields | Deduplicate identical entries |
@standards | Merge by category key | Concatenate arrays, source comment on conflicts |
@restrictions | Full union | Restrictions are additive — no conflicts |
@shortcuts | Merge all | Same command name → keep longer, comment shorter |
@knowledge | Concatenate | Source attribution headers between sections |
Confidence reporting¶
Sections below 50% confidence get # REVIEW: low confidence — verify this mapping in output.
Import Summary:
CLAUDE.md → 5 sections (87% confidence)
.cursorrules → 3 sections (82% confidence)
copilot-instr.md → 4 sections (85% confidence)
Merged: 8 unique sections (3 deduplicated)
Overall confidence: 84%
3. AI-Assisted Migration (Skill + Kick-start Prompt)¶
The PromptScript CLI ships a built-in skill (packages/cli/skills/promptscript/SKILL.md) that is normally auto-injected during prs compile. For migration, we install it before compile to avoid overwriting existing instruction files.
Kick-start prompt template¶
The generated prompt does NOT include full file contents (they're on disk — AI can read them). It includes:
Migrate my existing AI instructions to PromptScript.
I've just initialized PromptScript in this project. The following
instruction files need to be migrated to .prs format:
- CLAUDE.md (3.4 KB, Claude Code)
- .cursorrules (1.8 KB, Cursor)
- .github/copilot-instructions.md (2.1 KB, GitHub Copilot)
Use the /promptscript skill for the PromptScript language reference.
Steps:
1. Read each file listed above
2. Analyze the content and map to PromptScript blocks
3. Generate a modular .prs structure in .promptscript/:
- project.prs (entry: @meta, @identity, @use directives)
- context.prs (@context)
- standards.prs (@standards)
- restrictions.prs (@restrictions)
- commands.prs (@shortcuts, @knowledge)
4. Deduplicate overlapping content across files
5. Run: prs validate --strict
6. Run: prs compile --dry-run
Clipboard delivery¶
- macOS:
pbcopy - Linux:
xclip -selection clipboardorxsel --clipboard - Windows:
clip - Fallback: print to terminal + "Could not copy to clipboard"
- Always save to
.promptscript/migration-prompt.md
Tool-specific next steps¶
After prompt generation, show invocation hints per detected target:
Invoke the PromptScript skill in your AI tool:
Claude Code: /promptscript
Cursor: /promptscript
GitHub Copilot: /promptscript
4. CLI Flags & Non-interactive Mode¶
prs init flags¶
prs init # Interactive — gateway choice if files detected
prs init -y # Non-interactive, safe defaults, skip migration
prs init -y --auto-import # Non-interactive + static import of detected files
prs init -i # Force interactive even with all args provided
prs init -f # Force reinitialize
prs init --backup # Create .prs-backup/
prs init -m, --migrate # DEPRECATED → deprecation notice, installs skill
The --migrate flag stays for backward compatibility with a deprecation warning:
⚠ --migrate is deprecated. Use interactive mode: prs init
The migration flow is now built into the standard init process.
prs migrate command¶
Alias/shortcut to the init migration path:
prs migrate # Alias → prs init (enters migrate flow)
prs migrate --static # Non-interactive: imports ALL detected files without prompting
prs migrate --llm # Non-interactive: generates kick-start prompt to stdout
prs migrate --files <f1> <f2> # Selective: import only specified files
--static imports all detected candidates without confirmation (equivalent to prs init -y --auto-import). Use --files for selective non-interactive import. --llm pre-selects the AI-assisted path and copies the prompt to clipboard (falls back to stdout if clipboard unavailable).
Behavior depends on whether promptscript.yaml exists:
- No
promptscript.yaml: RunsinitCommand()with the migrate flow pre-selected (skips gateway prompt). promptscript.yamlexists: Runs migration flow only (skips init prompts — config already exists). Detects migration candidates and offers static/AI-assisted import into the existing.promptscript/directory. This allows users to add migration to an already-initialized project without--force.
Reverse sync (re-importing manual edits from compiled output) is out of scope — future feature.
Non-interactive behavior matrix¶
| Flags | Files detected? | Behavior |
|---|---|---|
-y | No | Standard init, scaffold project.prs, install skill |
-y | Yes | Standard init, scaffold project.prs, install skill, hint about migration |
-y --auto-import | No | Standard init (nothing to import) |
-y --auto-import | Yes | Standard init + static multi-file import → modular .prs |
-y --auto-import --backup | Yes | Same + backup to .prs-backup/ |
| (no flags) | No | Interactive fresh start |
| (no flags) | Yes | Interactive gateway: migrate vs fresh start |
Exit codes¶
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General failure |
| 2 | Already initialized (without --force) |
Git safety check¶
Before migration (static or AI-assisted):
- If not a git repo → warn, default backup to "yes"
- If git repo → default backup to "no"
Backup directory: Uses timestamped subdirectory: .prs-backup/<ISO-timestamp>/. Multiple backups can coexist without collision. The @use directive convention is without file extension (e.g., @use ./context resolves to ./context.prs).
Stdout vs stderr¶
- Human-readable output → stderr (spinners, summary, hints)
- Kick-start prompt → stdout only in non-interactive mode (pipe-friendly:
prs migrate --llm 2>/dev/null | pbcopy). In interactive mode, the prompt is copied to clipboard and/or saved to file — not emitted to stdout (which would conflict with Inquirer prompts). - Structured output → stdout with
--format json - All Inquirer prompts use stderr as their output stream (Inquirer supports this via the
outputoption).
5. Fresh Start: Skill Installation¶
For the "Fresh start" path (no migration), after creating config and scaffold files, prs init installs the built-in PromptScript skill directly to all target directories. This allows the AI tool to immediately help the user edit .prs files using /promptscript — without needing prs compile first (which would generate output from a placeholder template).
Once the user finishes editing .prs files, they run prs compile which generates output AND auto-injects the skill (normal compile behavior).
6. Enhanced Migration Candidate Detection¶
The AIToolsDetection.migrationCandidates type changes from string[] to enriched objects:
interface MigrationCandidate {
path: string;
format: DetectedFormat; // 'claude' | 'github' | 'cursor' | 'generic'
sizeBytes: number;
sizeHuman: string; // "3.4 KB"
toolName: string; // "Claude Code", "Cursor", etc.
}
Format detection mapping: The importer's DetectedFormat is currently 'claude' | 'github' | 'cursor' | 'generic'. Files without a dedicated parser (AGENTS.md, OPENCODE.md, GEMINI.md, .windsurfrules, .clinerules, AI_INSTRUCTIONS.md, AI.md) fall through to 'generic'. The generic parser handles markdown-based instruction files adequately for static import. Expanding DetectedFormat with additional parsers is future work and not required for this design.
Ambiguous file ownership: Some files (e.g., AGENTS.md) appear in detection patterns for multiple tools (Factory, Codex, Amp). The toolName field uses the first matching tool pattern from AI_TOOL_PATTERNS (ordered by specificity). The format field is independent — determined by the importer's detectFormat(), not by the AI tool detection.
This is an internal CLI interface change — no public API impact.
Implementation Phases¶
Phase 1: Foundation utilities (no breaking changes)¶
New files:
packages/cli/src/utils/clipboard.ts— cross-platform clipboardpackages/cli/src/utils/backup.ts—.prs-backup/creation + git repo detectionpackages/cli/src/utils/migration-prompt.ts— kick-start prompt generator
Tests:
packages/cli/src/__tests__/clipboard.spec.tspackages/cli/src/__tests__/backup.spec.tspackages/cli/src/__tests__/migration-prompt.spec.ts
Phase 2: Multi-file import in @promptscript/importer¶
New files:
packages/importer/src/merger.ts— section dedup + merge by block typepackages/importer/src/multi-importer.ts— batch import → modular .prs output
Modified files:
packages/importer/src/emitter.ts— source attribution comments, modular emitpackages/importer/src/index.ts— export new functions
Tests:
packages/importer/src/__tests__/merger.spec.tspackages/importer/src/__tests__/multi-importer.spec.ts
Phase 3: Enhanced init command¶
Modified files:
packages/cli/src/commands/init.ts— gateway choice, migrate flow, skill install for fresh start, kick-start prompt generationpackages/cli/src/types.ts— addimportflag toInitOptionspackages/cli/src/utils/ai-tools-detector.ts— enrichMigrationCandidatewith size, format, toolName
Tests:
packages/cli/src/__tests__/init-migrate.spec.ts(new)packages/cli/src/__tests__/init-command.spec.ts(update)
Phase 4: prs migrate command¶
New files:
packages/cli/src/commands/migrate.ts— thin wrapper delegating to init
Modified files:
packages/cli/src/cli.ts— register migrate command +--importflag on init, deprecation for--migrate
Tests:
packages/cli/src/__tests__/migrate-command.spec.ts
Phase 5: Documentation¶
Modified files:
packages/cli/skills/promptscript/SKILL.md— update CLI commands section- New migration guide (location TBD based on docs structure)
Dependency graph¶
Phase 1 (utils) ─────────────┐
├─→ Phase 3 (init) ─→ Phase 4 (migrate) ─→ Phase 5 (docs)
Phase 2 (multi-import) ──────┘
Phases 1 and 2 are independent and can be parallelized.
Scope summary¶
| Phase | New source files | Modified source files | New test files |
|---|---|---|---|
| 1 | 3 | 0 | 3 |
| 2 | 2 | 2 | 2 |
| 3 | 1 (init-migrate test) | 3 | update 1 existing test |
| 4 | 2 (command + test) | 1 | — |
| 5 | 0 | 2 | 0 |
| Total | 8 | 8 | 5 new + 1 update |
Error Handling¶
| Scenario | Handling |
|---|---|
| File detected but unreadable | Skip with warning, continue with remaining files |
| Import produces 0 sections | Skip with warning: "Could not parse X" |
| All sections LOW confidence (<50%) | Warn: "Low confidence — consider AI-assisted migration" |
promptscript.yaml exists without --force | Exit with code 2 |
| User cancels (Ctrl+C) | Catch ExitPromptError, clean exit |
| Clipboard unavailable | Fallback to terminal display |
| Not a git repo + no backup | Warn and default backup prompt to "yes" |
Backward Compatibility¶
prs init -ybehavior unchanged (scaffold, no auto-import)prs init --migratecontinues to work (installs skill) with deprecation noticeprs import <file>single-file import unchanged- New behavior only activates in interactive mode when candidates detected, or with explicit
--importflag - Exit code change: "Already initialized" previously exited with code 0 (warn + return). Now exits with code 2. This is a breaking change for scripts that check exit codes — document in release notes.