Skip to content

Conversation

@appboypov
Copy link

@appboypov appboypov commented Dec 21, 2025

Summary

  • Add YAML frontmatter parsing for tracked issues in proposal.md
  • Display issue identifiers in openspec list output (e.g., change-name (SM-123) [tasks])
  • Include trackedIssues in openspec show --json output
  • Report tracked issues when archiving changes
  • Add "External Issue Tracking" section to AGENTS.md template for agent guidance

Frontmatter Format

---
tracked-issues:
  - tracker: linear
    id: SM-123
    url: https://linear.app/team/issue/SM-123
---

Test plan

  • Run openspec list with a proposal containing tracked-issues frontmatter - should show issue ID in parentheses
  • Run openspec show <change> --json - should include trackedIssues array
  • Run openspec archive <change> - should report issue IDs in success message
  • Run openspec update in a project - should include External Issue Tracking section in AGENTS.md

Summary by CodeRabbit

  • New Features

    • External issue tracking: Proposals now support storing and displaying references to external issues; tracked issues appear in change lists and archive confirmations.
    • New plx command available as an alternative CLI entry point.
  • Documentation

    • README redesigned with project branding updates, fork notice, feature comparison table, and quick start guide.
    • Agent guidance updated with external issue tracking workflows and CLI command examples.

✏️ Tip: You can customize this high-level summary in your review settings.

appboypov and others added 2 commits December 21, 2025 16:25
- Add `plx` as an alias command alongside `openspec`
- Create OpenSplx pixel art logo assets (light/dark themes)
- Update README with fork notice and Quick Start section
- Make CLI command name dynamic based on invocation
- Update completion system to support both command names
- Add command-name utility for detecting invoked command
- Add YAML frontmatter parsing for tracked issues in proposal.md
- Display issue identifiers in `openspec list` output
- Include trackedIssues in `openspec show --json` output
- Report tracked issues when archiving changes
- Add External Issue Tracking section to AGENTS.md template
- Add TrackedIssue schema and type exports
Copilot AI review requested due to automatic review settings December 21, 2025 21:32
@appboypov appboypov requested a review from TabishB as a code owner December 21, 2025 21:32
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 21, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Introduces a fork-branded "plx" CLI command alongside the original "openspec," adds external issue tracking to proposals via YAML frontmatter, and updates CLI components to dynamically detect and support multiple command names throughout completion generators and messaging.

Changes

Cohort / File(s) Summary
Rebranding & Documentation
README.md, openspec/AGENTS.md, src/core/templates/agents-template.ts
Updated repository branding from OpenSpec to OpenSplx; added fork notice, feature comparison table, and Quick Start section in README; added External Issue Tracking guidance section to agent documentation and template.
New CLI Entry & Bin Setup
bin/plx.js, package.json
Added new executable bin script plx.js and registered "plx" entry in package.json alongside existing "openspec" mapping.
Command Name Detection
src/utils/command-name.ts, src/cli/index.ts, src/commands/completion.ts
Introduced utility to detect CLI invocation name from process.argv; updated CLI index and completion command to use dynamic command name for user messaging and script generation.
External Issue Tracking Schema
src/core/schemas/change.schema.ts, src/core/schemas/index.ts
Added TrackedIssueSchema with tracker, id, and url fields; extended ChangeSchema with optional trackedIssues array; exported new TrackedIssue type.
Frontmatter Parsing
src/core/parsers/markdown-parser.ts, src/core/parsers/change-parser.ts
Added frontmatter detection and YAML extraction to MarkdownParser; updated ChangeParser to extract and attach trackedIssues from frontmatter to parsed changes.
CLI Display Updates
src/commands/change.ts, src/core/list.ts, src/core/archive.ts
Imported TrackedIssue type; enhanced list flow to extract and display tracked issue IDs; updated archive flow to report tracked issues in success message.
Completion Generator Refactoring
src/core/completions/types.ts, src/core/completions/generators/zsh-generator.ts, scripts/postinstall.js
Updated CompletionGenerator interface to accept optional commandName parameter; refactored zsh-generator to use dynamic command name throughout function definitions and compdef registrations; updated postinstall messaging to suggest both openspec and plx completion install commands.
External Issue Tracking Specifications
openspec/changes/add-external-issue-tracking/ (proposal.md, tasks.md, specs/*)
Added proposal document and task specifications defining external issue tracking feature requirements; included CLI archive/list/show spec updates and agent instruction documentation.
Tests
test/core/completions/generators/zsh-generator.test.ts
Updated expected header comment to reflect dynamic command name in generated zsh completion script.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • src/core/parsers/markdown-parser.ts — Frontmatter extraction and YAML parsing logic should be validated for edge cases (empty frontmatter, malformed YAML, missing delimiters).
  • src/core/completions/generators/zsh-generator.ts — Extensive refactoring with dynamic commandName propagated across multiple method signatures and string literals; verify all function names, compdef registrations, and references are correctly parameterized.
  • Schema propagation — TrackedIssue type flows through multiple commands (list, archive, change); confirm all consumers properly handle optional trackedIssues field.
  • Command name detection logic — Process.argv[1] parsing in src/utils/command-name.ts should work correctly for both bin/openspec.js and bin/plx.js invocations.

Possibly related PRs

  • feature/oh-my-zsh-completions #289 — Introduces the shell-completions feature that this PR extends; shares modifications to completion generators, command types, and CLI wiring with dynamic commandName support.

Suggested reviewers

  • TabishB

Poem

🐰 A fork so fine, two names we share,
Plx and openspec, both debonair,
Frontmatter tracked from issue to spec,
With zsh completions, what's next?
Hopping forward, branch so bright!

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 68e0a7e and 0e9cde1.

⛔ Files ignored due to path filters (2)
  • assets/opensplx_pixel_dark.svg is excluded by !**/*.svg
  • assets/opensplx_pixel_light.svg is excluded by !**/*.svg
📒 Files selected for processing (25)
  • README.md (2 hunks)
  • bin/plx.js (1 hunks)
  • openspec/AGENTS.md (1 hunks)
  • openspec/changes/add-external-issue-tracking/proposal.md (1 hunks)
  • openspec/changes/add-external-issue-tracking/specs/cli-archive/spec.md (1 hunks)
  • openspec/changes/add-external-issue-tracking/specs/cli-list/spec.md (1 hunks)
  • openspec/changes/add-external-issue-tracking/specs/cli-show/spec.md (1 hunks)
  • openspec/changes/add-external-issue-tracking/specs/docs-agent-instructions/spec.md (1 hunks)
  • openspec/changes/add-external-issue-tracking/tasks.md (1 hunks)
  • package.json (1 hunks)
  • scripts/postinstall.js (4 hunks)
  • src/cli/index.ts (1 hunks)
  • src/commands/change.ts (5 hunks)
  • src/commands/completion.ts (5 hunks)
  • src/core/archive.ts (2 hunks)
  • src/core/completions/generators/zsh-generator.ts (12 hunks)
  • src/core/completions/types.ts (1 hunks)
  • src/core/list.ts (3 hunks)
  • src/core/parsers/change-parser.ts (1 hunks)
  • src/core/parsers/markdown-parser.ts (2 hunks)
  • src/core/schemas/change.schema.ts (4 hunks)
  • src/core/schemas/index.ts (1 hunks)
  • src/core/templates/agents-template.ts (1 hunks)
  • src/utils/command-name.ts (1 hunks)
  • test/core/completions/generators/zsh-generator.test.ts (1 hunks)

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds external issue tracking support to enable integration with tools like Linear, GitHub Issues, and Jira. Additionally, it introduces a plx command alias and rebrands the project as OpenSplx (a fork of OpenSpec).

Key changes:

  • YAML frontmatter parsing in proposal.md files to store tracked issue references (tracker, id, url)
  • Display of tracked issue identifiers in CLI commands (list, show, archive)
  • Agent guidance documentation for detecting, storing, and updating external issues

Reviewed changes

Copilot reviewed 24 out of 27 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/core/parsers/markdown-parser.ts Adds YAML frontmatter extraction and tracked-issues parsing
src/core/parsers/change-parser.ts Integrates frontmatter parsing into change parsing flow
src/core/schemas/change.schema.ts Adds TrackedIssue schema and optional trackedIssues field to Change schema
src/core/schemas/index.ts Exports TrackedIssue schema and type
src/core/list.ts Displays first tracked issue ID in parentheses after change name
src/commands/change.ts Includes trackedIssues in JSON output and displays issue ID in long format list
src/core/archive.ts Reports tracked issue IDs when archiving changes
src/core/templates/agents-template.ts Adds "External Issue Tracking" section with agent workflow guidance
openspec/AGENTS.md Adds same "External Issue Tracking" section to project template
src/utils/command-name.ts New utility to detect CLI command name from invocation (plx vs openspec)
src/cli/index.ts Uses detected command name for CLI program name
src/core/completions/types.ts Adds optional commandName parameter to CompletionGenerator.generate()
src/core/completions/generators/zsh-generator.ts Parameterizes command name throughout completion script generation
src/commands/completion.ts Passes detected command name to completion generator
scripts/postinstall.js Updates completion install messages to mention both openspec and plx
package.json Adds plx binary entry
bin/plx.js New entry point that imports CLI with plx invocation name
README.md Rebrands to OpenSplx with fork notice and OpenSpec comparison
assets/opensplx_pixel_*.svg New logo assets for OpenSplx branding
test/core/completions/generators/zsh-generator.test.ts Updates test expectation to use lowercase "openspec" in comment
openspec/changes/add-external-issue-tracking/* Complete change proposal with specs and tasks

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

/**
* Generates Zsh completion scripts for the OpenSpec CLI.
* Follows Zsh completion system conventions using the _openspec function.
* Generates Zsh completion scripts for the OpenSpec/OpenSplx CLI.
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment references "OpenSpec/OpenSplx CLI" which is inconsistent with the branding used elsewhere in the codebase. Since this is a fork that adds the 'plx' alias but maintains compatibility, the comment should either reference the generic nature of the tool or just say it generates completion scripts without specific branding references.

Suggested change
* Generates Zsh completion scripts for the OpenSpec/OpenSplx CLI.
* Generates Zsh completion scripts for a CLI application.

Copilot uses AI. Check for mistakes.
Comment on lines +93 to +100
const key = inlineMatch[1] as keyof TrackedIssue;
currentIssue[key] = inlineMatch[2].trim().replace(/^["']|["']$/g, '');
}
} else if (currentIssue) {
const propMatch = line.match(/^\s+(\w+)\s*:\s*(.+)$/);
if (propMatch) {
const key = propMatch[1] as keyof TrackedIssue;
currentIssue[key] = propMatch[2].trim().replace(/^["']|["']$/g, '');
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The YAML parser does not validate that URLs are well-formed before storing them in the parsed result. While the TrackedIssueSchema includes URL validation via zod's .url() method, the parser stores potentially invalid URLs that will only fail validation later when the Change schema is applied. Consider validating URLs during parsing or adding a try-catch to handle malformed URLs gracefully, providing better error messages to users about which line in the frontmatter is problematic.

Copilot uses AI. Check for mistakes.
Comment on lines +37 to +115
static extractFrontmatter(content: string): FrontmatterResult {
const lines = content.split('\n');

if (lines.length === 0 || lines[0].trim() !== '---') {
return { frontmatter: null, content };
}

let endIndex = -1;
for (let i = 1; i < lines.length; i++) {
if (lines[i].trim() === '---') {
endIndex = i;
break;
}
}

if (endIndex === -1) {
return { frontmatter: null, content };
}

const yamlLines = lines.slice(1, endIndex);
const remainingContent = lines.slice(endIndex + 1).join('\n');

const frontmatter = MarkdownParser.parseSimpleYaml(yamlLines);

return { frontmatter, content: remainingContent };
}

private static parseSimpleYaml(lines: string[]): Frontmatter {
const result: Frontmatter = { raw: {} };
const trackedIssues: TrackedIssue[] = [];

let inTrackedIssues = false;
let currentIssue: Partial<TrackedIssue> | null = null;

for (const line of lines) {
if (line.trim() === '' || line.trim().startsWith('#')) continue;

const topLevelMatch = line.match(/^(\w[\w-]*)\s*:/);
if (topLevelMatch && !line.startsWith(' ') && !line.startsWith('\t')) {
if (topLevelMatch[1] === 'tracked-issues') {
inTrackedIssues = true;
continue;
} else {
inTrackedIssues = false;
currentIssue = null;
}
}

if (inTrackedIssues) {
if (line.match(/^\s+-\s+\w/)) {
if (currentIssue && currentIssue.tracker && currentIssue.id && currentIssue.url) {
trackedIssues.push(currentIssue as TrackedIssue);
}
currentIssue = {};
const inlineMatch = line.match(/^\s+-\s+(\w+)\s*:\s*(.+)$/);
if (inlineMatch) {
const key = inlineMatch[1] as keyof TrackedIssue;
currentIssue[key] = inlineMatch[2].trim().replace(/^["']|["']$/g, '');
}
} else if (currentIssue) {
const propMatch = line.match(/^\s+(\w+)\s*:\s*(.+)$/);
if (propMatch) {
const key = propMatch[1] as keyof TrackedIssue;
currentIssue[key] = propMatch[2].trim().replace(/^["']|["']$/g, '');
}
}
}
}

if (currentIssue && currentIssue.tracker && currentIssue.id && currentIssue.url) {
trackedIssues.push(currentIssue as TrackedIssue);
}

if (trackedIssues.length > 0) {
result.trackedIssues = trackedIssues;
}

return result;
}
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The frontmatter extraction and tracked issues parsing logic lacks test coverage. While there are existing tests for MarkdownParser in test/core/parsers/markdown-parser.test.ts, no tests verify the new frontmatter functionality. Consider adding tests for: parsing valid tracked-issues frontmatter, handling missing or malformed frontmatter, handling multiple tracked issues, and validating that invalid URLs are caught appropriately.

Copilot uses AI. Check for mistakes.
Comment on lines +45 to 64
// Try to get tracked issue from proposal.md frontmatter
let trackedIssue: string | undefined;
try {
const proposalPath = path.join(changesDir, changeDir, 'proposal.md');
const proposalContent = await fs.readFile(proposalPath, 'utf-8');
const parser = new MarkdownParser(proposalContent);
const frontmatter = parser.getFrontmatter();
if (frontmatter?.trackedIssues && frontmatter.trackedIssues.length > 0) {
trackedIssue = frontmatter.trackedIssues[0].id;
}
} catch {
// proposal.md might not exist or be unreadable
}

changes.push({
name: changeDir,
completedTasks: progress.completed,
totalTasks: progress.total
totalTasks: progress.total,
trackedIssue,
});
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tracked issues feature in the list command lacks test coverage. The existing tests in test/core/list.test.ts don't verify that tracked issues are displayed correctly when present in proposal.md frontmatter. Consider adding a test case that creates a proposal.md with tracked-issues frontmatter and verifies the issue ID appears in the list output.

Copilot uses AI. Check for mistakes.
Comment on lines +256 to +277
// Get tracked issues before moving the change
let trackedIssues: TrackedIssue[] = [];
try {
const proposalPath = path.join(changeDir, 'proposal.md');
const proposalContent = await fs.readFile(proposalPath, 'utf-8');
const parser = new MarkdownParser(proposalContent);
const frontmatter = parser.getFrontmatter();
if (frontmatter?.trackedIssues) {
trackedIssues = frontmatter.trackedIssues;
}
} catch {
// proposal.md might not exist or be unreadable
}

// Move change to archive
await fs.rename(changeDir, archivePath);

console.log(`Change '${changeName}' archived as '${archiveName}'.`);

// Display archive success with tracked issues if present
const issueDisplay = trackedIssues.length > 0
? ` (${trackedIssues.map(i => i.id).join(', ')})`
: '';
console.log(`Change '${changeName}'${issueDisplay} archived as '${archiveName}'.`);
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tracked issues display in archive command lacks test coverage. Consider adding a test case that creates a change with tracked issues and verifies the issue IDs are displayed in the archive success message.

Copilot uses AI. Check for mistakes.
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