Skip to content

feat: add rich issue body composition and GitHub auto-labels for external task tracking#96

Merged
sanmak merged 2 commits intomainfrom
feat/add-rich-issue-body-composition-and-github-auto-labels
Mar 21, 2026
Merged

feat: add rich issue body composition and GitHub auto-labels for external task tracking#96
sanmak merged 2 commits intomainfrom
feat/add-rich-issue-body-composition-and-github-auto-labels

Conversation

@sanmak
Copy link
Owner

@sanmak sanmak commented Mar 21, 2026

Summary

  • Issue Body Composition template: Defines a mandatory structured template for composing GitHub/Jira/Linear issue bodies from spec artifacts — pulling context from requirements.md overview, linking to spec artifacts, and including full task details (description, implementation steps, acceptance criteria, files, tests)
  • GitHub Label Protocol: Auto-applies three label categories per issue (P-high/P-medium, spec:<id>, feat/fix/refactor) using idempotent gh label create --force
  • Protocol breach enforcement: Freeform issue bodies are now explicitly marked as a protocol breach, with cross-references in task-tracking.md and workflow.md
  • CI enforcement: ISSUE_BODY_MARKERS added to validate.py and test_platform_consistency.py for all 4 platforms

Changes

File Change
core/config-handling.md Added Issue Body Composition subsection, GitHub Label Protocol subsection, updated platform steps (<TaskDescription><IssueBody>, --label flags)
core/task-tracking.md Added protocol breach cross-reference in External Tracker Sync
core/workflow.md Updated Phase 2 step 6 to reference Issue Body Composition and labels
generator/validate.py Added ISSUE_BODY_MARKERS constant, per-platform check, cross-platform consistency
tests/test_platform_consistency.py Added issue_body to REQUIRED_MARKERS
platforms/*/, skills/specops/ Regenerated outputs with new content
.specops/rich-issue-bodies/ Full spec artifacts (requirements, design, tasks, implementation, spec.json)

Test Plan

  • python3 generator/generate.py --all — 4 platforms generated
  • python3 generator/validate.py — all checks pass including new issue-body markers
  • bash scripts/run-tests.sh — 8/8 tests pass
  • shasum -a 256 -c CHECKSUMS.sha256 — all 17 checksums verified
  • Generated outputs contain "Issue Body Composition" and "GitHub Label Protocol" markers
  • ShellCheck passes on all scripts

Summary by CodeRabbit

  • New Features

    • Mandatory structured issue bodies for external tracker issues (template with required sections) and automatic per-issue labels (priority, spec, type) with idempotent label provisioning.
  • Documentation

    • Updated external issue-creation and workflow guides across platforms to reflect the new Issue Body Composition and labeling protocol.
  • Tests

    • CI/validation extended to enforce presence of issue-body markers across all generated platform outputs.

Greptile Summary

This PR enriches external issue creation in SpecOps by adding a mandatory structured Issue Body Composition template (Context, Spec Artifacts, Description, Implementation Steps, Acceptance Criteria, Files to Modify, Tests Required) and a GitHub Label Protocol that auto-applies three label categories (P-high/P-medium, spec:<id>, feat/fix/refactor) using idempotent gh label create --force. The changes are wired to core/config-handling.md, propagated to all four generated platform outputs, cross-referenced in task-tracking.md and workflow.md, and enforced in CI via ISSUE_BODY_MARKERS in both validate.py and test_platform_consistency.py.

Key findings:

  • Jira/Linear graceful degradation gap: The --label flags are embedded inline in the single jira issue create / linear issue create command. If the CLI version doesn't support --label, the entire command fails, blocking issue creation — contrary to the stated "Do not block issue creation on label failure" requirement. The protocol needs an explicit retry-without-labels fallback for these trackers.
  • Label safety regex permits colons in spec-id: The regex ^[a-z0-9][a-z0-9:_-]*$ allows colons inside the spec-id value, which is unintentional (spec IDs are hyphenated slugs) and could allow ambiguous label names like spec:foo:bar.
  • Validator and test coverage: ISSUE_BODY_MARKERS is correctly added to both the per-platform validation and the cross-platform consistency loop, and the test file is updated in parallel — consistent with the pattern used by all prior marker sets.
  • --force semantics: The documentation now accurately describes --force as an overwrite/upsert operation (creating if absent, updating if present), which is correct — an improvement over the wording flagged in the previous review round.

Confidence Score: 3/5

  • Safe to merge for GitHub-only users; Jira and Linear users may experience unintended issue-creation failures due to the inline label flag issue.
  • The core GitHub workflow is well-implemented with proper shell safety, correct --force semantics, and full CI enforcement via markers. The validator and test changes are solid. The score is reduced because the Jira/Linear command templates embed --label flags in the issue-creation command with no described retry-without-labels path, which contradicts the explicit graceful degradation requirement — a genuine logic gap for non-GitHub tracker users.
  • core/config-handling.md (and all four generated platform files) — specifically the Jira and Linear command templates in the Issue Creation Protocol section.

Important Files Changed

Filename Overview
core/config-handling.md Core protocol change adding Issue Body Composition template and GitHub Label Protocol; the Jira/Linear command templates embed --label flags in the same command as issue creation, which prevents graceful label-only failure and can block issue creation entirely if the flag is unsupported. Label safety regex also unnecessarily allows colons in spec-id values.
generator/validate.py Adds ISSUE_BODY_MARKERS constant with 6 marker strings and wires it into both the per-platform validation call and the cross-platform consistency loop; follows the same pattern as all prior marker sets and is correct.
tests/test_platform_consistency.py Adds the "issue_body" entry to REQUIRED_MARKERS with the same 6 strings as ISSUE_BODY_MARKERS in validate.py; consistent and complete.
core/task-tracking.md Adds a single cross-reference sentence reinforcing the Issue Body Composition template requirement; straightforward documentation change.
core/workflow.md Phase 2 step 6 updated to explicitly reference Issue Body Composition and GitHub labels; no logic changes, clean documentation update.
platforms/claude/SKILL.md Regenerated output reflecting config-handling.md changes; inherits the Jira/Linear graceful-degradation inconsistency from the source template.
platforms/codex/SKILL.md Regenerated output; same Jira/Linear label-flag issue inherited from source template.
platforms/copilot/specops.instructions.md Regenerated output; same Jira/Linear label-flag issue inherited from source template.
platforms/cursor/specops.mdc Regenerated output; same Jira/Linear label-flag issue inherited from source template.
.specops/rich-issue-bodies/spec.json New spec metadata file for this feature; missing trailing newline (already flagged in a previous review thread) and otherwise complete.
CHECKSUMS.sha256 Updated SHA-256 checksums for all 5 regenerated platform output files; consistent with the PR's generation run.

Sequence Diagram

sequenceDiagram
    participant Agent
    participant TasksMd as tasks.md
    participant SpecArtifacts as Spec Artifacts
    participant GitHub

    Agent->>TasksMd: Read - identify High/Medium priority tasks
    loop For each eligible task
        Agent->>SpecArtifacts: Read requirements.md or bugfix.md or refactor.md
        Agent->>SpecArtifacts: Read spec.json for id and type fields
        Agent->>Agent: Compose IssueBody from template
        note over Agent,GitHub: Label creation runs once per spec
        Agent->>GitHub: gh label create P-high or P-medium --force
        Agent->>GitHub: gh label create spec id --force
        Agent->>GitHub: gh label create type label --force
        Agent->>Agent: Write IssueBody to temp file
        Agent->>GitHub: gh issue create with title, body-file, and labels
        GitHub-->>Agent: Return issue URL or number
        Agent->>TasksMd: Write IssueID back to task entry
    end
Loading

Last reviewed commit: "fix: address PR revi..."

Greptile also left 1 inline comment on this PR.

…rnal task tracking

Define mandatory Issue Body Composition template and GitHub Label Protocol in the Issue Creation Protocol, replacing bare one-liner issue descriptions with structured bodies that pull context from spec artifacts.
Copilot AI review requested due to automatic review settings March 21, 2026 04:56
@coderabbitai
Copy link

coderabbitai bot commented Mar 21, 2026

📝 Walkthrough

Walkthrough

This PR adds a new "rich-issue-bodies" feature: mandatory Issue Body Composition templates and an automated GitHub Label Protocol, updates platform/tracking docs to use composed issue bodies and labels, and enforces presence of ISSUE_BODY_MARKERS via generator validation and platform-consistency tests.

Changes

Cohort / File(s) Summary
Feature spec & docs
.specops/index.json, .specops/rich-issue-bodies/spec.json, .specops/rich-issue-bodies/design.md, .specops/rich-issue-bodies/requirements.md, .specops/rich-issue-bodies/implementation.md, .specops/rich-issue-bodies/tasks.md, .specops/memory/context.md
Added new feature entry and full specops documentation (design, requirements, tasks, implementation journal, memory/context) describing Issue Body Composition and GitHub Label Protocol.
Core protocol
core/config-handling.md, core/task-tracking.md, core/workflow.md
Replaced freeform task description flow with mandatory composed <IssueBody>; added label creation/application rules and conformance language; updated Phase 2 workflow to use composed bodies and labels.
Platform outputs / skills
platforms/claude/SKILL.md, platforms/codex/SKILL.md, platforms/copilot/specops.instructions.md, platforms/cursor/specops.mdc, skills/specops/SKILL.md
Regenerated/updated platform instructions to compose IssueBody from spec artifacts, idempotently create GitHub labels, and include --label flags when creating issues; replaced prior <TaskDescription> usage.
Validation & tests
generator/validate.py, tests/test_platform_consistency.py
Added ISSUE_BODY_MARKERS constant; wired marker checks into validate_platform() and cross-platform consistency; added issue_body required markers to tests.
Checksums / metadata
CHECKSUMS.sha256
Updated SHA-256 entries for regenerated platform/skill output files.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Generator
participant PlatformOutput
participant GitHubCLI
participant Validator
Generator->>PlatformOutput: Read spec artifacts + tasks → compose
PlatformOutput->>GitHubCLI: Ensure labels exist (gh label create --force)
GitHubCLI-->>PlatformOutput: Labels created/ok (non-blocking if unsupported)
PlatformOutput->>GitHubCLI: Create issue with --title and --body (composed ) and --label args
GitHubCLI-->>PlatformOutput: Return IssueID
PlatformOutput->>Generator: Write IssueID back to tasks.md
Generator->>Validator: Run checks (check_markers_present for ISSUE_BODY_MARKERS)
Validator-->>Generator: Report pass/fail for marker presence

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 I stitched issue bodies with careful art,
Labels hopped on, each playing its part,
Templates tidy, markers all known,
Validators nod — the garden has grown,
A carrot for progress, a happy heart! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately summarizes the main change: introducing rich issue body composition and GitHub auto-labeling for external task tracking.
Description check ✅ Passed The pull request description is comprehensive and well-structured, covering all key aspects of the changes: summary of features, detailed change list with file mappings, and completed test plan with verification results.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/add-rich-issue-body-composition-and-github-auto-labels

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 12

🧹 Nitpick comments (1)
core/workflow.md (1)

133-133: Generalize provider wording in core workflow text.

Line [133] hard-codes GitHub in a core module. Consider phrasing this as provider-specific metadata to keep core guidance platform-agnostic.

💡 Proposed wording tweak
-6. **External issue creation (mandatory when taskTracking configured)**: If `config.team.taskTracking` is not `"none"`, create external issues following the Task Tracking Integration protocol in the Configuration Handling module. READ_FILE `tasks.md`, identify all tasks with `**Priority:** High` or `**Priority:** Medium`. For each eligible task, compose the issue body using the Issue Body Composition template (reading spec artifacts for context), create issues via the Issue Creation Protocol (with labels for GitHub), and write IssueIDs back to `tasks.md`. If issue creation is skipped or all IssueIDs remain `None`, the Phase 3 task tracking gate will catch the omission — the spec artifact linter validates IssueIDs on completed specs and fails CI when they are missing.
+6. **External issue creation (mandatory when taskTracking configured)**: If `config.team.taskTracking` is not `"none"`, create external issues following the Task Tracking Integration protocol in the Configuration Handling module. READ_FILE `tasks.md`, identify all tasks with `**Priority:** High` or `**Priority:** Medium`. For each eligible task, compose the issue body using the Issue Body Composition template (reading spec artifacts for context), create issues via the Issue Creation Protocol (including provider-specific metadata, e.g., labels when using GitHub), and write IssueIDs back to `tasks.md`. If issue creation is skipped or all IssueIDs remain `None`, the Phase 3 task tracking gate will catch the omission — the spec artifact linter validates IssueIDs on completed specs and fails CI when they are missing.
As per coding guidelines: `core/` must remain platform-agnostic — use abstract operations and never platform-specific tool names.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/workflow.md` at line 133, Update the hard-coded provider wording in the
External issue creation step: replace the phrase "create issues via the Issue
Creation Protocol (with labels for GitHub)" with a platform-agnostic description
that uses provider-specific metadata (e.g., "create issues via the Issue
Creation Protocol, attaching provider-specific metadata such as
labels/tags/fields as required by the configured taskTracking provider"). Ensure
references to config.team.taskTracking, Issue Creation Protocol, Issue Body
Composition, and writing IssueIDs back to tasks.md remain unchanged so behavior
is unchanged but wording is provider-neutral.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.specops/rich-issue-bodies/implementation.md:
- Line 7: The docs line containing the config summary currently uses a lowercase
platform name; update the phrase "taskTracking: github" in the string "Config:
loaded from `.specops.json` — vertical: builder, specsDir: .specops,
taskTracking: github" to use the proper capitalized form "GitHub" so it reads
"taskTracking: GitHub".
- Around line 18-28: The markdown tables under the headings "## Decision Log",
"## Deviations from Design", and "## Blockers Encountered" need blank lines
before and after each table to satisfy markdownlint MD058; edit the
implementation.md content to insert an empty line above and below each table
block (i.e., surround the three pipe-delimited tables following those headings)
so each table is separated from surrounding text by a blank line.

In @.specops/rich-issue-bodies/requirements.md:
- Line 21: Update the canonical section name in the requirements extraction
rule: replace the phrase "bugfix.md Bug Description" with "bugfix.md Problem
Statement" so the rule reads that the Context section should extract 1–3
sentences from Overview (or bugfix.md Problem Statement / refactor.md
Motivation); update the string literal in the requirements.md rule to use
"Problem Statement" to remove ambiguity.

In `@core/config-handling.md`:
- Line 106: The fenced code block opening currently uses a bare ``` fence which
triggers MD040; update the opening fence to include the language identifier by
changing the leading ``` to ```markdown so the block becomes a markdown fenced
block containing the "## Context" section and the priority/effort/dependencies
line, ensuring markdownlint no longer flags it.
- Line 171: The examples and guidance use unescaped <TaskTitle> in shell
single-quoted arguments; update the three tracker command templates (the GitHub,
Jira, and Linear examples) to use the explicit <EscapedTaskTitle> placeholder
instead of <TaskTitle> (i.e., change --title '<taskPrefix><TaskTitle>' and
--summary='<taskPrefix><TaskTitle>' to use <EscapedTaskTitle>) and update the
Shell safety guidance text to mention <EscapedTaskTitle> explicitly (e.g., "use
an explicitly escaped value (<EscapedTaskTitle>) where internal single quotes
are escaped or prefer file-based args"). Ensure all three command examples and
the guidance consistently reference <EscapedTaskTitle> so implementers know to
escape internal single quotes before interpolation.

In `@platforms/codex/SKILL.md`:
- Around line 477-479: Replace the unsafe single-quoted title interpolation in
the gh issue create command (the fragment using '--title
'<taskPrefix><TaskTitle>'') so that titles containing apostrophes do not break:
construct the title via a safe shell variable or printf expansion (for example
use --title "$(printf '%s' "$taskPrefix$TaskTitle")" or --title
"$taskPrefix$TaskTitle") in core/config-handling.md where the gh issue create
command is composed, then regenerate all platform files with python3
generator/generate.py --all.

In `@platforms/copilot/specops.instructions.md`:
- Around line 457-460: The label creation path interpolates raw spec IDs into
shell commands (e.g., the gh label create "<label>" --force --description
"<description>" invocation) without sanitization—add a validation step that
enforces a strict allowlist regex (e.g., /^[a-z0-9:-]+$/) for spec-id and any
derived label names, and reject or normalize inputs that don't match;
additionally, stop constructing commands via raw string interpolation by using a
safe command runner that accepts arguments as an array (or the GitHub CLI SDK)
so labels are passed as argv rather than embedded into a shell string; update
the label-generation helper to apply the regex, return sanitized labels, and
fail early with a clear error if validation fails before calling the gh label
create invocation.

In `@platforms/cursor/specops.mdc`:
- Around line 473-474: Update the "Jira and Linear" guidance so the concrete
command examples actually attempt to apply labels when the `--label` flag is
available, and fall back to silently skipping labels on failure; specifically,
modify the command/example blocks under the "Jira and Linear" section to include
the `--label` flag usage and error-tolerant behavior described in the prose,
ensuring the examples show how to pass labels and note the silent skip behavior
when the flag is unsupported or fails (keep label application non-blocking for
issue creation).
- Around line 419-421: Replace the hardcoded artifact link that points to
"<specsDir>/<spec-name>/requirements.md" with the resolved spec artifact file
path so non-feature specs (bugfix/refactor) link correctly; locate the three
markdown link entries in platforms/cursor/specops.mdc (the lines containing
"[Requirements](<specsDir>/<spec-name>/requirements.md)" and the similar
Design/Tasks links) and substitute the Requirements link to use the same
resolved artifact variable or helper used for the other artifacts (e.g.,
specArtifactPath or resolvedSpecArtifact) so it points to the actual artifact
filename instead of always "requirements.md".
- Line 480: The gh issue creation commands use --title '<taskPrefix><TaskTitle>'
(and similar occurrences) without escaping single quotes, violating the
shell-safety guidance; fix by either writing the interpolated title to a
temporary file and passing it via a file-based argument (use the CLI/file flag
variant for title instead of --title inline) or by escaping single quotes in the
title before interpolation using the safe shell escape pattern (replace each '
with '\'' ), and update every occurrence of the command pattern (--title
'<taskPrefix><TaskTitle>') to use one of these safe approaches.

In `@skills/specops/SKILL.md`:
- Line 410: The fenced code block in SKILL.md currently starts with triple
backticks (```) with no language tag which triggers markdownlint MD040; update
that opening fence to include the correct language identifier (for example
```bash, ```json, or ```js depending on the block contents) so the code block is
language-marked and MD040 is satisfied.
- Around line 419-421: The three hard-coded links in SKILL.md always point to
requirements.md and break for bugfix/refactor specs; update the template to
choose the correct artifact filename based on the spec type (requirements.md for
"feature"/"spec", bugfix.md for "bugfix", refactor.md for "refactor") instead of
always linking to requirements.md. Locate the block that renders
"[Requirements](<specsDir>/<spec-name>/requirements.md)" and replace it with a
conditional/lookup that selects the filename using the spec type variable (e.g.,
spec.type or similar) so the link becomes
"<specsDir>/<spec-name>/<chosen-filename>.md", ensuring the three items
(Requirements/Design/Tasks) resolve to the correct artifact names for bugfix and
refactor specs.

---

Nitpick comments:
In `@core/workflow.md`:
- Line 133: Update the hard-coded provider wording in the External issue
creation step: replace the phrase "create issues via the Issue Creation Protocol
(with labels for GitHub)" with a platform-agnostic description that uses
provider-specific metadata (e.g., "create issues via the Issue Creation
Protocol, attaching provider-specific metadata such as labels/tags/fields as
required by the configured taskTracking provider"). Ensure references to
config.team.taskTracking, Issue Creation Protocol, Issue Body Composition, and
writing IssueIDs back to tasks.md remain unchanged so behavior is unchanged but
wording is provider-neutral.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1ee21248-9796-469e-9146-7a766b132661

📥 Commits

Reviewing files that changed from the base of the PR and between 6932931 and 11c01de.

📒 Files selected for processing (18)
  • .specops/index.json
  • .specops/memory/context.md
  • .specops/rich-issue-bodies/design.md
  • .specops/rich-issue-bodies/implementation.md
  • .specops/rich-issue-bodies/requirements.md
  • .specops/rich-issue-bodies/spec.json
  • .specops/rich-issue-bodies/tasks.md
  • CHECKSUMS.sha256
  • core/config-handling.md
  • core/task-tracking.md
  • core/workflow.md
  • generator/validate.py
  • platforms/claude/SKILL.md
  • platforms/codex/SKILL.md
  • platforms/copilot/specops.instructions.md
  • platforms/cursor/specops.mdc
  • skills/specops/SKILL.md
  • tests/test_platform_consistency.py

6 tasks completed, 0 deviations from design, 0 blockers. Added Issue Body Composition template and GitHub Label Protocol to core/config-handling.md — defining a mandatory issue body structure that pulls context from spec artifacts (requirements overview, spec links, task details) and auto-applies GitHub labels (priority, spec name, type). Cross-references added to task-tracking.md and workflow.md. ISSUE_BODY_MARKERS added to both validate.py and test_platform_consistency.py (Gap 31 enforced). All 4 platform outputs regenerated, validator passes all checks including new markers, all 8 tests pass.

## Phase 1 Context Summary
- Config: loaded from `.specops.json` — vertical: builder, specsDir: .specops, taskTracking: github
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Capitalize the platform name consistently.

Line [7] should use GitHub (not github) for consistency and correctness in docs.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~7-~7: The official name of this software platform is spelled with a capital “H”.
Context: ...lder, specsDir: .specops, taskTracking: github - Context recovery: none (new spec) - S...

(GITHUB)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.specops/rich-issue-bodies/implementation.md at line 7, The docs line
containing the config summary currently uses a lowercase platform name; update
the phrase "taskTracking: github" in the string "Config: loaded from
`.specops.json` — vertical: builder, specsDir: .specops, taskTracking: github"
to use the proper capitalized form "GitHub" so it reads "taskTracking: GitHub".

Comment on lines +18 to +28
## Decision Log
| # | Decision | Rationale | Task | Timestamp |
|---|----------|-----------|------|-----------|

## Deviations from Design
| Planned | Actual | Reason | Task |
|---------|--------|--------|------|

## Blockers Encountered
| Blocker | Resolution | Impact | Task |
|---------|------------|--------|------|
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add blank lines around tables to satisfy markdownlint (MD058).

Line [19], Line [23], and Line [27] tables should be surrounded by blank lines.

🧹 Proposed markdownlint-compliant spacing
 ## Decision Log
+
 | # | Decision | Rationale | Task | Timestamp |
 |---|----------|-----------|------|-----------|
 
 ## Deviations from Design
+
 | Planned | Actual | Reason | Task |
 |---------|--------|--------|------|
 
 ## Blockers Encountered
+
 | Blocker | Resolution | Impact | Task |
 |---------|------------|--------|------|
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Decision Log
| # | Decision | Rationale | Task | Timestamp |
|---|----------|-----------|------|-----------|
## Deviations from Design
| Planned | Actual | Reason | Task |
|---------|--------|--------|------|
## Blockers Encountered
| Blocker | Resolution | Impact | Task |
|---------|------------|--------|------|
## Decision Log
| # | Decision | Rationale | Task | Timestamp |
|---|----------|-----------|------|-----------|
## Deviations from Design
| Planned | Actual | Reason | Task |
|---------|--------|--------|------|
## Blockers Encountered
| Blocker | Resolution | Impact | Task |
|---------|------------|--------|------|
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 19-19: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


[warning] 23-23: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


[warning] 27-27: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.specops/rich-issue-bodies/implementation.md around lines 18 - 28, The
markdown tables under the headings "## Decision Log", "## Deviations from
Design", and "## Blockers Encountered" need blank lines before and after each
table to satisfy markdownlint MD058; edit the implementation.md content to
insert an empty line above and below each table block (i.e., surround the three
pipe-delimited tables following those headings) so each table is separated from
surrounding text by a blank line.

Unwanted: IF [unwanted condition] THEN THE SYSTEM SHALL [response]
-->
- WHEN creating an external issue for a High or Medium priority task THE SYSTEM SHALL compose the issue body using the Issue Body Composition template with sections: Context, Spec Artifacts, Description, Implementation Steps, Acceptance Criteria, Files to Modify, Tests Required (optional), and metadata footer
- WHEN composing the Context section THE SYSTEM SHALL extract 1-3 sentences from the requirements.md Overview (or bugfix.md Bug Description / refactor.md Motivation) explaining why the work exists
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use canonical bugfix section name to avoid extraction ambiguity

Line 21 says bugfix.md Bug Description, but the standard bugfix template section is Problem Statement. Please align wording so context extraction rules are unambiguous.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.specops/rich-issue-bodies/requirements.md at line 21, Update the canonical
section name in the requirements extraction rule: replace the phrase "bugfix.md
Bug Description" with "bugfix.md Problem Statement" so the rule reads that the
Context section should extract 1–3 sentences from Overview (or bugfix.md Problem
Statement / refactor.md Motivation); update the string literal in the
requirements.md rule to use "Problem Statement" to remove ambiguity.


Compose `<IssueBody>` using this template:

```
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add a language identifier to the fenced template block.

This block is flagged by markdownlint (MD040). Add markdown after the opening fence.

Proposed doc fix
-```
+```markdown
 ## Context
 ...
 **Priority:** <task priority> | **Effort:** <task effort> | **Dependencies:** <task dependencies>
</details>

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.21.0)</summary>

[warning] 106-106: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @core/config-handling.md at line 106, The fenced code block opening currently
uses a bare fence which triggers MD040; update the opening fence to include the language identifier by changing the leading to ```markdown so the block
becomes a markdown fenced block containing the "## Context" section and the
priority/effort/dependencies line, ensuring markdownlint no longer flags it.


</details>

<!-- fingerprinting:phantom:triton:hawk -->

<!-- This is an auto-generated comment by CodeRabbit -->


Compose `<IssueBody>` using this template:

```
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add a language identifier to the fenced code block

Line 410 starts a fenced block without a language, which fails markdownlint MD040.

🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 410-410: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@skills/specops/SKILL.md` at line 410, The fenced code block in SKILL.md
currently starts with triple backticks (```) with no language tag which triggers
markdownlint MD040; update that opening fence to include the correct language
identifier (for example ```bash, ```json, or ```js depending on the block
contents) so the code block is language-marked and MD040 is satisfied.

"reviewRounds": 0,
"approvals": 0,
"requiredApprovals": 0
} No newline at end of file
Copy link

Choose a reason for hiding this comment

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

P2 Missing newline at end of file

The file is missing a trailing newline (the diff shows \ No newline at end of file). This is inconsistent with POSIX conventions and may trigger linter warnings. All other spec JSON files in the repo should have a trailing newline for consistency.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Owner Author

Choose a reason for hiding this comment

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

Fixed in 7922aa4.

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 PR formalizes how SpecOps composes external tracker issue bodies (pulling structured content from spec artifacts) and standardizes GitHub auto-labeling, then enforces presence of these instructions across generated platform outputs via validation and tests.

Changes:

  • Added a mandatory “Issue Body Composition” template and a “GitHub Label Protocol” to the task-tracking integration docs, including protocol-breach language for freeform bodies.
  • Extended CI/validator enforcement with new ISSUE_BODY_MARKERS and corresponding cross-platform consistency checks.
  • Regenerated platform outputs and introduced a full spec (.specops/rich-issue-bodies/) capturing requirements/design/tasks for this change.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
core/config-handling.md Defines the issue body composition template + GitHub label protocol; updates issue creation steps to use <IssueBody> and --label.
core/task-tracking.md Adds a protocol-breach cross-reference reinforcing mandatory issue-body composition.
core/workflow.md Updates Phase 2 step 6 to reference the new issue body composition + labels behavior.
generator/validate.py Adds ISSUE_BODY_MARKERS, validates them per-platform, and includes them in cross-platform consistency checks.
tests/test_platform_consistency.py Adds issue_body markers to ensure platform outputs contain the required new content.
platforms/claude/SKILL.md Regenerated platform output containing the new issue body + label protocol instructions.
platforms/cursor/specops.mdc Regenerated platform output containing the new issue body + label protocol instructions.
platforms/codex/SKILL.md Regenerated platform output containing the new issue body + label protocol instructions.
platforms/copilot/specops.instructions.md Regenerated platform output containing the new issue body + label protocol instructions.
skills/specops/SKILL.md Synced “legacy skills” output (generated from Claude output) to include the new instructions.
CHECKSUMS.sha256 Updates checksums to match regenerated outputs / updated docs.
.specops/rich-issue-bodies/requirements.md Captures product requirements for rich issue bodies + GitHub auto-labeling + CI enforcement.
.specops/rich-issue-bodies/design.md Documents design decisions and enforcement approach for the new protocol.
.specops/rich-issue-bodies/tasks.md Task breakdown and acceptance criteria for implementing the feature end-to-end.
.specops/rich-issue-bodies/spec.json Spec metadata for the new “rich-issue-bodies” feature.
.specops/rich-issue-bodies/implementation.md Implementation journal summarizing work completed and validations run.
.specops/memory/context.md Appends the completed spec summary to project memory.
.specops/index.json Adds the completed spec entry to the spec index.

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

**Label set per issue:**
- **Priority label**: `P-high` or `P-medium` (matching the task's `**Priority:**` field; Low tasks are not created as issues)
- **Spec label**: `spec:<spec-id>` where `<spec-id>` is the `id` from `spec.json` (e.g., `spec:proxy-metrics`)
- **Type label**: `<type>` where `<type>` is the `type` from `spec.json` — one of `feat`, `fix`, or `refactor` (map `feature` to `feat`, `bugfix` to `fix`, `refactor` stays `refactor`)
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

The Type label bullet is internally inconsistent with the spec.json schema: spec.json.type is feature|bugfix|refactor (see spec-schema.json), but this text says it is already feat|fix|refactor while also describing a mapping. Please reword to make it explicit that the label value is derived from spec.json.type via the mapping (and consider naming it <typeLabel> to avoid confusion with the raw type).

Suggested change
- **Type label**: `<type>` where `<type>` is the `type` from `spec.json` — one of `feat`, `fix`, or `refactor` (map `feature` to `feat`, `bugfix` to `fix`, `refactor` stays `refactor`)
- **Type label**: `<typeLabel>` where `<typeLabel>` is derived from the `type` field in `spec.json` using this mapping: `feature` `feat`, `bugfix` `fix`, `refactor` `refactor`

Copilot uses AI. Check for mistakes.
Copy link
Owner Author

Choose a reason for hiding this comment

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

Fixed in 7922aa4.


RUN_COMMAND(`gh label create "<label>" --force --description "<description>"`)

The `--force` flag is idempotent — it creates the label if missing, does nothing if it already exists. Run this once per unique label, not once per issue.
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

This description of gh label create --force is inaccurate: --force will update/overwrite an existing label’s metadata (name/description/color) rather than “do nothing”. Please adjust the wording to reflect the actual behavior (e.g., idempotent only when the same arguments are used) so readers don’t assume it’s a no-op on existing labels.

Suggested change
The `--force` flag is idempotent — it creates the label if missing, does nothing if it already exists. Run this once per unique label, not once per issue.
The `--force` flag creates the label if it is missing and updates/overwrites its metadata (name/description/color) if it already exists. It is effectively idempotent only when you re-run it with the same arguments for a given label. Run this once per unique label definition, not once per issue.

Copilot uses AI. Check for mistakes.
Comment on lines +151 to +153
- **Priority label**: `P-high` or `P-medium` (matching the task's `**Priority:**` field; Low tasks are not created as issues)
- **Spec label**: `spec:<spec-id>` where `<spec-id>` is the `id` from `spec.json` (e.g., `spec:proxy-metrics`)
- **Type label**: `<type>` where `<type>` is the `type` from `spec.json` — one of `feat`, `fix`, or `refactor` (map `feature` to `feat`, `bugfix` to `fix`, `refactor` stays `refactor`)
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

Placeholder conventions are inconsistent in this protocol: the spec label is written as spec:<spec-id> here, but the later gh issue create example uses spec:<specId>. Please standardize on a single placeholder style/value source and use it consistently across the label bullets and the command examples to avoid agents substituting the wrong value.

Copilot uses AI. Check for mistakes.
Copy link
Owner Author

Choose a reason for hiding this comment

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

Fixed in 7922aa4.

**Label set per issue:**
- **Priority label**: `P-high` or `P-medium` (matching the task's `**Priority:**` field; Low tasks are not created as issues)
- **Spec label**: `spec:<spec-id>` where `<spec-id>` is the `id` from `spec.json` (e.g., `spec:proxy-metrics`)
- **Type label**: `<type>` where `<type>` is the `type` from `spec.json` — one of `feat`, `fix`, or `refactor` (map `feature` to `feat`, `bugfix` to `fix`, `refactor` stays `refactor`)
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

The Type label bullet is internally inconsistent with the spec.json schema: spec.json.type is feature|bugfix|refactor, but this text says it is already feat|fix|refactor while also describing a mapping. Please reword to make it explicit that the label value is derived from spec.json.type via the mapping (and consider naming it <typeLabel> vs the raw type).

Suggested change
- **Type label**: `<type>` where `<type>` is the `type` from `spec.json` one of `feat`, `fix`, or `refactor` (map `feature` to `feat`, `bugfix` to `fix`, `refactor` stays `refactor`)
- **Type label**: `<typeLabel>` where `<typeLabel>` is derived from the `type` field in `spec.json` (one of `feature`, `bugfix`, `refactor`) by mapping `feature` `feat`, `bugfix` `fix`, and `refactor` `refactor`

Copilot uses AI. Check for mistakes.

Use the Bash tool to run(`gh label create "<label>" --force --description "<description>"`)

The `--force` flag is idempotent — it creates the label if missing, does nothing if it already exists. Run this once per unique label, not once per issue.
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

This description of gh label create --force is inaccurate: --force will update/overwrite an existing label’s metadata rather than “do nothing”. Please adjust the wording to reflect the actual behavior so readers don’t assume it’s a no-op on existing labels.

Suggested change
The `--force` flag is idempotent — it creates the label if missing, does nothing if it already exists. Run this once per unique label, not once per issue.
The `--force` flag is safe to re-run — it creates the label if missing, and updates/overwrites the existing label’s metadata (such as description or color) if it already exists. Run this once per unique label name, not once per issue.

Copilot uses AI. Check for mistakes.
Comment on lines +454 to +457
**Label set per issue:**
- **Priority label**: `P-high` or `P-medium` (matching the task's `**Priority:**` field; Low tasks are not created as issues)
- **Spec label**: `spec:<spec-id>` where `<spec-id>` is the `id` from `spec.json` (e.g., `spec:proxy-metrics`)
- **Type label**: `<type>` where `<type>` is the `type` from `spec.json` — one of `feat`, `fix`, or `refactor` (map `feature` to `feat`, `bugfix` to `fix`, `refactor` stays `refactor`)
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

Placeholder conventions are inconsistent: the spec label is described as spec:<spec-id> here, but the later gh issue create example uses spec:<specId>. Please standardize on a single placeholder style/value source and use it consistently across the section to avoid agents substituting the wrong value.

Copilot uses AI. Check for mistakes.
**Label set per issue:**
- **Priority label**: `P-high` or `P-medium` (matching the task's `**Priority:**` field; Low tasks are not created as issues)
- **Spec label**: `spec:<spec-id>` where `<spec-id>` is the `id` from `spec.json` (e.g., `spec:proxy-metrics`)
- **Type label**: `<type>` where `<type>` is the `type` from `spec.json` — one of `feat`, `fix`, or `refactor` (map `feature` to `feat`, `bugfix` to `fix`, `refactor` stays `refactor`)
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

The Type label bullet is internally inconsistent with the spec.json schema: spec.json.type is feature|bugfix|refactor, but this text says it is already feat|fix|refactor while also describing a mapping. Please reword to make it explicit that the label value is derived from spec.json.type via the mapping.

Suggested change
- **Type label**: `<type>` where `<type>` is the `type` from `spec.json` — one of `feat`, `fix`, or `refactor` (map `feature` to `feat`, `bugfix` to `fix`, `refactor` stays `refactor`)
- **Type label**: `<type-label>` where `<type-label>` is derived from the `type` field in `spec.json` by mapping `feature` `feat`, `bugfix` `fix`, and `refactor` `refactor`

Copilot uses AI. Check for mistakes.

Run the terminal command(`gh label create "<label>" --force --description "<description>"`)

The `--force` flag is idempotent — it creates the label if missing, does nothing if it already exists. Run this once per unique label, not once per issue.
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

This description of gh label create --force is inaccurate: --force will update/overwrite an existing label’s metadata rather than “do nothing”. Please adjust the wording to reflect the actual behavior so users don’t assume it’s a no-op on existing labels.

Suggested change
The `--force` flag is idempotent — it creates the label if missing, does nothing if it already exists. Run this once per unique label, not once per issue.
The `--force` flag is safe to run repeatedly — it creates the label if missing and updates an existing label’s metadata (such as its description) to match the arguments you pass. Run this once per unique label definition, not once per issue.

Copilot uses AI. Check for mistakes.
Comment on lines +453 to +456
- **Priority label**: `P-high` or `P-medium` (matching the task's `**Priority:**` field; Low tasks are not created as issues)
- **Spec label**: `spec:<spec-id>` where `<spec-id>` is the `id` from `spec.json` (e.g., `spec:proxy-metrics`)
- **Type label**: `<type>` where `<type>` is the `type` from `spec.json` — one of `feat`, `fix`, or `refactor` (map `feature` to `feat`, `bugfix` to `fix`, `refactor` stays `refactor`)

Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

Placeholder conventions are inconsistent: the spec label is described as spec:<spec-id> here, but the later gh issue create example uses spec:<specId>. Please standardize on a single placeholder style/value source and regenerate outputs so agents apply the intended label reliably.

Copilot uses AI. Check for mistakes.
…ng hierarchy, and cross-platform consistency

- Use <EscapedTaskTitle> placeholder in all issue creation command templates (CodeRabbit critical)
- Fix inaccurate --force flag description: creates/updates, not "does nothing" (Greptile + Copilot)
- Reword type label bullet to show explicit spec.json mapping (Copilot)
- Standardize placeholder to <spec-id> across label definitions and commands (Copilot)
- Demote Issue Body Composition / GitHub Label Protocol to h4 sub-sections (Greptile)
- Add spec-id sanitization rule before shell interpolation (CodeRabbit critical)
- Fix hardcoded requirements.md link — use <specArtifact> for bugfix/refactor specs (CodeRabbit)
- Add --label flags to Jira/Linear command examples (CodeRabbit)
- Add trailing newline to spec.json (Greptile)
- Regenerate all platform outputs and checksums
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (2)
core/config-handling.md (1)

106-106: ⚠️ Potential issue | 🟡 Minor

Add a language tag to the fenced template block.

The opening fence should include a language (e.g., ```markdown) to satisfy markdownlint MD040.

Proposed fix
-```
+```markdown
 ## Context
 ...
 **Priority:** <task priority> | **Effort:** <task effort> | **Dependencies:** <task dependencies>
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @core/config-handling.md at line 106, Add a language tag to the fenced
template block that begins with the opening triple backticks and contains the
"## Context" heading: change the opening fence from tomarkdown so the
block is explicitly marked as Markdown (resolving markdownlint MD040); update
the fenced block that includes the lines starting with "## Context" and the task
metadata line to use the ```markdown tag.


</details>

</blockquote></details>
<details>
<summary>platforms/cursor/specops.mdc (1)</summary><blockquote>

`475-476`: _⚠️ Potential issue_ | _🟠 Major_

**Jira/Linear examples still contradict the non-blocking label policy.**

Line 475 says label failures must be skipped silently, but Lines 489 and 496 use required `--label` flags with no fallback path, so issue creation can fail instead of degrading gracefully.  
 

<details>
<summary>Suggested patch</summary>

```diff
-3. Run the terminal command(`jira issue create --type=Task --summary='<taskPrefix><EscapedTaskTitle>' --description-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'`)
+3. Run the terminal command(`jira issue create --type=Task --summary '<taskPrefix><EscapedTaskTitle>' --description-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>' || jira issue create --type=Task --summary '<taskPrefix><EscapedTaskTitle>' --description-file <tempFile>`)

-3. Run the terminal command(`linear issue create --title '<taskPrefix><EscapedTaskTitle>' --description-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'`)
+3. Run the terminal command(`linear issue create --title '<taskPrefix><EscapedTaskTitle>' --description-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>' || linear issue create --title '<taskPrefix><EscapedTaskTitle>' --description-file <tempFile>`)
```
</details>


Also applies to: 489-490, 496-497

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against the current code and only fix it if needed.

In `@platforms/cursor/specops.mdc` around lines 475 - 476, The Jira/Linear
examples currently treat `--label` as required (contradicting the non-blocking
label policy); update the examples and implementation so label usage is
optional: change example CLI usage to show `--label` as optional, and in the
code paths that apply labels (e.g., functions named createJiraIssue,
createLinearIssue, or applyLabels) wrap label application in a try/catch (or
check feature-flag/flag-presence) so any failure to add labels only logs a
non-fatal warning and does not abort or return an error for issue creation;
ensure any place that previously assumed `--label` was mandatory is updated to
degrade gracefully and reflect the spec language that labels are enhancements,
not requirements.
```

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against the current code and only fix it if needed.

Inline comments:
In @core/config-handling.md:

  • Around line 171-193: The command templates for Jira and Linear still always
    pass --label and can fail on older CLIs; update the flow around RUN_COMMAND for
    "jira issue create" and "linear issue create" so label failures do not abort
    creation: after WRITE_FILE of , attempt RUN_COMMAND with labels
    first, detect a non-fatal label-related error from stdout/stderr, and on such
    failure retry RUN_COMMAND without any --label flags (or with only guaranteed
    flags); ensure the parsed issue key/identifier handling (the parse step that
    feeds EDIT_FILE tasks.md and the EDIT_FILE step that sets IssueID:) runs on
    success of either attempt; keep EscapedTaskTitle and --description-file/--title
    usage unchanged.

In @platforms/claude/SKILL.md:

  • Line 410: The fenced code block containing the "## Context" snippet in
    SKILL.md is missing a language identifier (triggering markdownlint MD040);
    update the opening fence to include the markdown language (e.g., replace the
    opening withmarkdown) so the block is explicitly marked as markdown,
    ensuring the "## Context" section and its contents are linted correctly.

In @platforms/codex/SKILL.md:

  • Around line 397-498: The fenced code block for the "Issue Body Composition"
    template is missing a language tag; edit the template in core/config-handling.md
    (the "Issue Body Composition" section that contains the triple-backtick block
    showing the IssueBody template) and change the opening fence from ``` to
by running python3 generator/generate.py --all so platforms/codex/SKILL.md is
updated with the language-annotated code fence.

In `@platforms/cursor/specops.mdc`:
- Line 477: The composed command uses config.team.taskPrefix + EscapedTaskTitle
which escapes only the title and leaves the prefix unescaped, enabling shell
injection; fix by creating a single escaped final title (e.g., compute
EscapedIssueTitle = shellEscape(config.team.taskPrefix + TaskTitle) where
shellEscape replaces '\'' with '\''\\\'\'' or, preferably, write the full
composed title and IssueBody to temporary files and pass via file-based args
(e.g., --title-file/--body-file) to the tracker CLI; replace all uses of the
current EscapedTaskTitle concatenation in the command templates with
EscapedIssueTitle (or the file-argument) and ensure IssueBody is similarly
passed via file or fully escaped.

---

Duplicate comments:
In `@core/config-handling.md`:
- Line 106: Add a language tag to the fenced template block that begins with the
opening triple backticks and contains the "## Context" heading: change the
opening fence from ``` to ```markdown so the block is explicitly marked as
Markdown (resolving markdownlint MD040); update the fenced block that includes
the lines starting with "## Context" and the task metadata line to use the
```markdown tag.

In `@platforms/cursor/specops.mdc`:
- Around line 475-476: The Jira/Linear examples currently treat `--label` as
required (contradicting the non-blocking label policy); update the examples and
implementation so label usage is optional: change example CLI usage to show
`--label` as optional, and in the code paths that apply labels (e.g., functions
named createJiraIssue, createLinearIssue, or applyLabels) wrap label application
in a try/catch (or check feature-flag/flag-presence) so any failure to add
labels only logs a non-fatal warning and does not abort or return an error for
issue creation; ensure any place that previously assumed `--label` was mandatory
is updated to degrade gracefully and reflect the spec language that labels are
enhancements, not requirements.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1a39210c-a2ea-4ce5-a193-f03f4632bf4e

📥 Commits

Reviewing files that changed from the base of the PR and between 11c01de and 7922aa4.

📒 Files selected for processing (8)
  • .specops/rich-issue-bodies/spec.json
  • CHECKSUMS.sha256
  • core/config-handling.md
  • platforms/claude/SKILL.md
  • platforms/codex/SKILL.md
  • platforms/copilot/specops.instructions.md
  • platforms/cursor/specops.mdc
  • skills/specops/SKILL.md
✅ Files skipped from review due to trivial changes (2)
  • CHECKSUMS.sha256
  • .specops/rich-issue-bodies/spec.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • skills/specops/SKILL.md

Comment on lines +171 to +193
**Jira and Linear**: Label/tag support varies. For Jira, use `--label` flag if available in the CLI version. For Linear, use `--label` flag. If the flag is unavailable or fails, skip labels silently — labels are enhancement, not requirement. Do not block issue creation on label failure.

**Shell safety**: `<TaskTitle>` and `<IssueBody>` contain user-controlled text. Before interpolating into shell commands, write the title and body to temporary files and pass via file-based arguments (e.g., `--body-file`). If file-based arguments are unavailable for the tracker CLI, single-quote the values with internal single-quotes escaped (`'` → `'\''`). Never pass unescaped user text directly in shell command strings. In command templates below, `<EscapedTaskTitle>` denotes the title after applying this escaping.

**GitHub** (`taskTracking: "github"`):
1. WRITE_FILE a temp file with `<TaskDescription>` as content
2. RUN_COMMAND(`gh issue create --title '<taskPrefix><TaskTitle>' --body-file <tempFile>`)
3. Parse the issue URL/number from stdout
4. EDIT_FILE `tasks.md` — set the task's `**IssueID:**` to the returned issue identifier (e.g., `#42`)
1. Compose `<IssueBody>` following the Issue Body Composition template above
2. WRITE_FILE a temp file with `<IssueBody>` as content
3. RUN_COMMAND(`gh issue create --title '<taskPrefix><EscapedTaskTitle>' --body-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'`)
4. Parse the issue URL/number from stdout
5. EDIT_FILE `tasks.md` — set the task's `**IssueID:**` to the returned issue identifier (e.g., `#42`)

**Jira** (`taskTracking: "jira"`):
1. WRITE_FILE a temp file with `<TaskDescription>` as content
2. RUN_COMMAND(`jira issue create --type=Task --summary='<taskPrefix><TaskTitle>' --description-file <tempFile>`)
3. Parse the issue key from stdout (e.g., `PROJ-123`)
4. EDIT_FILE `tasks.md` — set the task's `**IssueID:**` to the returned key
1. Compose `<IssueBody>` following the Issue Body Composition template above
2. WRITE_FILE a temp file with `<IssueBody>` as content
3. RUN_COMMAND(`jira issue create --type=Task --summary='<taskPrefix><EscapedTaskTitle>' --description-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'`)
4. Parse the issue key from stdout (e.g., `PROJ-123`)
5. EDIT_FILE `tasks.md` — set the task's `**IssueID:**` to the returned key

**Linear** (`taskTracking: "linear"`):
1. WRITE_FILE a temp file with `<TaskDescription>` as content
2. RUN_COMMAND(`linear issue create --title '<taskPrefix><TaskTitle>' --description-file <tempFile>`)
3. Parse the issue identifier from stdout
4. EDIT_FILE `tasks.md` — set the task's `**IssueID:**` to the returned identifier
1. Compose `<IssueBody>` following the Issue Body Composition template above
2. WRITE_FILE a temp file with `<IssueBody>` as content
3. RUN_COMMAND(`linear issue create --title '<taskPrefix><EscapedTaskTitle>' --description-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'`)
4. Parse the issue identifier from stdout
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Make Jira/Linear label fallback explicit in the command flow.

This section says label failures must not block issue creation, but the command templates always pass --label and don’t define a retry path without labels. That can still fail hard on unsupported/older CLIs.

Proposed protocol patch
 **Jira** (`taskTracking: "jira"`):
 1. Compose `<IssueBody>` following the Issue Body Composition template above
 2. WRITE_FILE a temp file with `<IssueBody>` as content
-3. RUN_COMMAND(`jira issue create --type=Task --summary='<taskPrefix><EscapedTaskTitle>' --description-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'`)
+3. Try with labels:
+   RUN_COMMAND(`jira issue create --type=Task --summary='<taskPrefix><EscapedTaskTitle>' --description-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'`)
+   If label flags are unsupported/fail, retry once without labels:
+   RUN_COMMAND(`jira issue create --type=Task --summary='<taskPrefix><EscapedTaskTitle>' --description-file <tempFile>`)
 4. Parse the issue key from stdout (e.g., `PROJ-123`)
 5. EDIT_FILE `tasks.md` — set the task's `**IssueID:**` to the returned key
 
 **Linear** (`taskTracking: "linear"`):
 1. Compose `<IssueBody>` following the Issue Body Composition template above
 2. WRITE_FILE a temp file with `<IssueBody>` as content
-3. RUN_COMMAND(`linear issue create --title '<taskPrefix><EscapedTaskTitle>' --description-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'`)
+3. Try with labels:
+   RUN_COMMAND(`linear issue create --title '<taskPrefix><EscapedTaskTitle>' --description-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'`)
+   If label flags are unsupported/fail, retry once without labels:
+   RUN_COMMAND(`linear issue create --title '<taskPrefix><EscapedTaskTitle>' --description-file <tempFile>`)
 4. Parse the issue identifier from stdout
 5. EDIT_FILE `tasks.md` — set the task's `**IssueID:**` to the returned identifier
🧰 Tools
🪛 LanguageTool

[uncategorized] ~175-~175: The official name of this software platform is spelled with a capital “H”.
Context: ...er applying this escaping. GitHub (taskTracking: "github"): 1. Compose <IssueBody> following ...

(GITHUB)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/config-handling.md` around lines 171 - 193, The command templates for
Jira and Linear still always pass --label and can fail on older CLIs; update the
flow around RUN_COMMAND for "jira issue create" and "linear issue create" so
label failures do not abort creation: after WRITE_FILE of <IssueBody>, attempt
RUN_COMMAND with labels first, detect a non-fatal label-related error from
stdout/stderr, and on such failure retry RUN_COMMAND without any --label flags
(or with only guaranteed flags); ensure the parsed issue key/identifier handling
(the parse step that feeds EDIT_FILE tasks.md and the EDIT_FILE step that sets
**IssueID:**) runs on success of either attempt; keep EscapedTaskTitle and
--description-file/--title usage unchanged.


Compose `<IssueBody>` using this template:

```
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add a language identifier to the fenced code block.

This fence triggers markdownlint MD040 and will keep lint noisy/failing.

Suggested fix
-```
+```markdown
 ## Context
 
 <1-3 sentence summary from requirements.md/bugfix.md/refactor.md Overview explaining why this work exists>
@@
 **Priority:** <task priority> | **Effort:** <task effort> | **Dependencies:** <task dependencies>
</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion

🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 410-410: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@platforms/claude/SKILL.md` at line 410, The fenced code block containing the
"## Context" snippet in SKILL.md is missing a language identifier (triggering
markdownlint MD040); update the opening fence to include the markdown language
(e.g., replace the opening ``` with ```markdown) so the block is explicitly
marked as markdown, ensuring the "## Context" section and its contents are
linted correctly.

Comment on lines +397 to 498
#### Issue Body Composition

Before creating each issue, compose `<IssueBody>` by extracting content from spec artifacts. This composition is mandatory — writing a freeform description instead of following this template is a protocol breach.

For each eligible task, Read the file at `<specsDir>/<spec-name>/requirements.md` (or `bugfix.md`/`refactor.md`), Read the file at `<specsDir>/<spec-name>/spec.json`, and extract:

1. **Context**: The spec's Overview/Product Requirements first paragraph (1-3 sentences explaining "why")
2. **Spec type**: From `spec.json` `type` field
3. **Spec name**: From `spec.json` `id` field

Compose `<IssueBody>` using this template:

```
## Context

<1-3 sentence summary from requirements.md/bugfix.md/refactor.md Overview explaining why this work exists>

**Spec:** `<spec-id>` | **Type:** <spec-type>

## Spec Artifacts

- [Requirements](<specsDir>/<spec-name>/<specArtifact>) where <specArtifact> is `requirements.md` for features, `bugfix.md` for bugfixes, or `refactor.md` for refactors
- [Design](<specsDir>/<spec-name>/design.md)
- [Tasks](<specsDir>/<spec-name>/tasks.md)

## Description

<Full text from the task's **Description:** section in tasks.md>

## Implementation Steps

<Numbered list from the task's **Implementation Steps:** section in tasks.md>

## Acceptance Criteria

<Checkbox items from the task's **Acceptance Criteria:** section in tasks.md>

## Files to Modify

<Bulleted list from the task's **Files to Modify:** section in tasks.md>

## Tests Required

<Checkbox items from the task's **Tests Required:** section in tasks.md. If the task has no Tests Required section, omit this entire section.>

---

**Priority:** <task priority> | **Effort:** <task effort> | **Dependencies:** <task dependencies>
```

Every section above (except Tests Required) is mandatory. If a section's source data is empty in `tasks.md`, write "None specified" rather than omitting the section.

#### GitHub Label Protocol

When `taskTracking` is `"github"`, apply labels to each created issue. Labels make issues searchable and categorizable.

**Label set per issue:**
- **Priority label**: `P-high` or `P-medium` (matching the task's `**Priority:**` field; Low tasks are not created as issues)
- **Spec label**: `spec:<spec-id>` where `<spec-id>` is the `id` from `spec.json` (e.g., `spec:proxy-metrics`)
- **Type label**: `<typeLabel>` where `<typeLabel>` is derived from the `type` field in `spec.json` using this mapping: `feature` → `feat`, `bugfix` → `fix`, `refactor` → `refactor`

**Label safety**: Before interpolating `<spec-id>` or `<typeLabel>` into label commands, validate that each value matches `^[a-z0-9][a-z0-9:_-]*$` (lowercase alphanumeric, hyphens, underscores, colons). Reject or normalize any value that doesn't match — this prevents shell injection via malformed spec IDs.

**Label creation**: Before creating the first issue for a spec, ensure all required labels exist. For each label in the set, run:

Execute the command(`gh label create "<label>" --force --description "<description>"`)

The `--force` flag creates the label if it is missing and updates/overwrites its metadata (name/description/color) if it already exists. It is effectively idempotent only when you re-run it with the same arguments. Run this once per unique label definition, not once per issue.

Label descriptions:
- `P-high`: "High priority task"
- `P-medium`: "Medium priority task"
- `spec:<spec-id>`: "SpecOps spec: <spec-id>"
- `feat`: "Feature implementation"
- `fix`: "Bug fix"
- `refactor`: "Code refactoring"

**Jira and Linear**: Label/tag support varies. For Jira, use `--label` flag if available in the CLI version. For Linear, use `--label` flag. If the flag is unavailable or fails, skip labels silently — labels are enhancement, not requirement. Do not block issue creation on label failure.

**Shell safety**: `<TaskTitle>` and `<IssueBody>` contain user-controlled text. Before interpolating into shell commands, write the title and body to temporary files and pass via file-based arguments (e.g., `--body-file`). If file-based arguments are unavailable for the tracker CLI, single-quote the values with internal single-quotes escaped (`'` → `'\''`). Never pass unescaped user text directly in shell command strings. In command templates below, `<EscapedTaskTitle>` denotes the title after applying this escaping.

**GitHub** (`taskTracking: "github"`):
1. Write the file at a temp file with `<TaskDescription>` as content
2. Execute the command(`gh issue create --title '<taskPrefix><TaskTitle>' --body-file <tempFile>`)
3. Parse the issue URL/number from stdout
4. Edit the file at `tasks.md` — set the task's `**IssueID:**` to the returned issue identifier (e.g., `#42`)
1. Compose `<IssueBody>` following the Issue Body Composition template above
2. Write the file at a temp file with `<IssueBody>` as content
3. Execute the command(`gh issue create --title '<taskPrefix><EscapedTaskTitle>' --body-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'`)
4. Parse the issue URL/number from stdout
5. Edit the file at `tasks.md` — set the task's `**IssueID:**` to the returned issue identifier (e.g., `#42`)

**Jira** (`taskTracking: "jira"`):
1. Write the file at a temp file with `<TaskDescription>` as content
2. Execute the command(`jira issue create --type=Task --summary='<taskPrefix><TaskTitle>' --description-file <tempFile>`)
3. Parse the issue key from stdout (e.g., `PROJ-123`)
4. Edit the file at `tasks.md` — set the task's `**IssueID:**` to the returned key
1. Compose `<IssueBody>` following the Issue Body Composition template above
2. Write the file at a temp file with `<IssueBody>` as content
3. Execute the command(`jira issue create --type=Task --summary='<taskPrefix><EscapedTaskTitle>' --description-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'`)
4. Parse the issue key from stdout (e.g., `PROJ-123`)
5. Edit the file at `tasks.md` — set the task's `**IssueID:**` to the returned key

**Linear** (`taskTracking: "linear"`):
1. Write the file at a temp file with `<TaskDescription>` as content
2. Execute the command(`linear issue create --title '<taskPrefix><TaskTitle>' --description-file <tempFile>`)
3. Parse the issue identifier from stdout
4. Edit the file at `tasks.md` — set the task's `**IssueID:**` to the returned identifier
1. Compose `<IssueBody>` following the Issue Body Composition template above
2. Write the file at a temp file with `<IssueBody>` as content
3. Execute the command(`linear issue create --title '<taskPrefix><EscapedTaskTitle>' --description-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'`)
4. Parse the issue identifier from stdout
5. Edit the file at `tasks.md` — set the task's `**IssueID:**` to the returned identifier

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Confirm source-of-truth files contain the new protocol markers
rg -n -C2 "Issue Body Composition|GitHub Label Protocol|freeform issue bodies are a protocol breach|<EscapedTaskTitle>|spec:<spec-id>" core generator/templates || true

# 2) Confirm regenerated outputs contain the same markers across platform files
rg -n -C1 "Issue Body Composition|GitHub Label Protocol|freeform issue bodies are a protocol breach" \
  platforms/claude/SKILL.md \
  platforms/cursor/specops.mdc \
  platforms/codex/SKILL.md \
  platforms/copilot/specops.instructions.md || true

# 3) Show whether this PR touched likely source files for this generated change
git diff --name-only HEAD~1..HEAD | rg -n "^(core/|generator/templates/|platforms/)" || true

Repository: sanmak/specops

Length of output: 19822


The generated file is correctly produced from source — no manual edits detected. Ensure the fenced code block in the Issue Body Composition template has a language identifier.

The Issue Body Composition protocol text is properly synchronized between core/config-handling.md (source) and all platform outputs. However, the fenced code block showing the template (around line 410 in platforms/codex/SKILL.md) is missing a language identifier on the opening fence. Update the source template in core/config-handling.md to add a language tag (e.g., ```markdown), then regenerate with python3 generator/generate.py --all.

🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 410-410: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@platforms/codex/SKILL.md` around lines 397 - 498, The fenced code block for
the "Issue Body Composition" template is missing a language tag; edit the
template in core/config-handling.md (the "Issue Body Composition" section that
contains the triple-backtick block showing the IssueBody template) and change
the opening fence from ``` to ```markdown (or another appropriate language),
then regenerate the platform docs by running python3 generator/generate.py --all
so platforms/codex/SKILL.md is updated with the language-annotated code fence.


**Jira and Linear**: Label/tag support varies. For Jira, use `--label` flag if available in the CLI version. For Linear, use `--label` flag. If the flag is unavailable or fails, skip labels silently — labels are enhancement, not requirement. Do not block issue creation on label failure.

**Shell safety**: `<TaskTitle>` and `<IssueBody>` contain user-controlled text. Before interpolating into shell commands, write the title and body to temporary files and pass via file-based arguments (e.g., `--body-file`). If file-based arguments are unavailable for the tracker CLI, single-quote the values with internal single-quotes escaped (`'` → `'\''`). Never pass unescaped user text directly in shell command strings. In command templates below, `<EscapedTaskTitle>` denotes the title after applying this escaping.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify where title composition currently relies on escaping only TaskTitle
rg -n -C 2 "EscapedTaskTitle|taskPrefix|--title|--summary" platforms/cursor/specops.mdc

# Confirm there is no dedicated escaped placeholder for the full composed title
rg -n "EscapedIssueTitle|EscapedFullTitle|EscapedTitle" platforms/cursor/specops.mdc

Repository: sanmak/specops

Length of output: 3862


🏁 Script executed:

#!/bin/bash
# Check if taskPrefix is sanitized or escaped anywhere
rg -n "taskPrefix|config.team.taskPrefix" platforms/cursor/specops.mdc | head -20

# Look for any configuration validation or escaping of taskPrefix
rg -n -B 2 -A 2 "config.team" platforms/cursor/specops.mdc | grep -A 5 -B 5 "taskPrefix"

Repository: sanmak/specops

Length of output: 1003


🏁 Script executed:

#!/bin/bash
# Look for config schema or validation
rg -n "config\.team\.|schema|validation" platforms/cursor/specops.mdc | head -15

# Find all shell command patterns that might use taskPrefix or similar prefix patterns
rg -n "create.*--title|create.*--summary" platforms/cursor/specops.mdc | grep -v "EscapedTaskTitle"

Repository: sanmak/specops

Length of output: 3605


Escape the complete composed title, not only <EscapedTaskTitle>.

Line 477 defines <EscapedTaskTitle>, but commands at lines 482, 489, and 496 compose <taskPrefix><EscapedTaskTitle>. Since config.team.taskPrefix is user-controlled, if it contains ' or shell metacharacters, escaping breaks and allows injection. Escape the final composed title as one unit (e.g., <EscapedIssueTitle>) encompassing both the prefix and title together.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@platforms/cursor/specops.mdc` at line 477, The composed command uses
config.team.taskPrefix + EscapedTaskTitle which escapes only the title and
leaves the prefix unescaped, enabling shell injection; fix by creating a single
escaped final title (e.g., compute EscapedIssueTitle =
shellEscape(config.team.taskPrefix + TaskTitle) where shellEscape replaces '\''
with '\''\\\'\'' or, preferably, write the full composed title and IssueBody to
temporary files and pass via file-based args (e.g., --title-file/--body-file) to
the tracker CLI; replace all uses of the current EscapedTaskTitle concatenation
in the command templates with EscapedIssueTitle (or the file-argument) and
ensure IssueBody is similarly passed via file or fully escaped.

Comment on lines 182 to +194
**Jira** (`taskTracking: "jira"`):
1. WRITE_FILE a temp file with `<TaskDescription>` as content
2. RUN_COMMAND(`jira issue create --type=Task --summary='<taskPrefix><TaskTitle>' --description-file <tempFile>`)
3. Parse the issue key from stdout (e.g., `PROJ-123`)
4. EDIT_FILE `tasks.md` — set the task's `**IssueID:**` to the returned key
1. Compose `<IssueBody>` following the Issue Body Composition template above
2. WRITE_FILE a temp file with `<IssueBody>` as content
3. RUN_COMMAND(`jira issue create --type=Task --summary='<taskPrefix><EscapedTaskTitle>' --description-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'`)
4. Parse the issue key from stdout (e.g., `PROJ-123`)
5. EDIT_FILE `tasks.md` — set the task's `**IssueID:**` to the returned key

**Linear** (`taskTracking: "linear"`):
1. WRITE_FILE a temp file with `<TaskDescription>` as content
2. RUN_COMMAND(`linear issue create --title '<taskPrefix><TaskTitle>' --description-file <tempFile>`)
3. Parse the issue identifier from stdout
4. EDIT_FILE `tasks.md` — set the task's `**IssueID:**` to the returned identifier
1. Compose `<IssueBody>` following the Issue Body Composition template above
2. WRITE_FILE a temp file with `<IssueBody>` as content
3. RUN_COMMAND(`linear issue create --title '<taskPrefix><EscapedTaskTitle>' --description-file <tempFile> --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'`)
4. Parse the issue identifier from stdout
5. EDIT_FILE `tasks.md` — set the task's `**IssueID:**` to the returned identifier
Copy link

Choose a reason for hiding this comment

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

P2 Jira/Linear label flags block issue creation on failure

The graceful degradation section states "Do not block issue creation on label failure," but the command templates for Jira and Linear embed --label flags inline in the same command as issue creation:

jira issue create ... --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'
linear issue create ... --label '<priorityLabel>' --label 'spec:<spec-id>' --label '<typeLabel>'

If the CLI version doesn't support --label (e.g., older Jira CLI), the entire command fails — not just the label application — and issue creation is blocked entirely. This directly contradicts the stated intent of "If the flag is unavailable or fails, skip labels silently."

A retry-without-labels fallback step needs to be described explicitly, e.g.:

  1. Attempt issue creation with --label flags
  2. If the command fails due to an unrecognised flag, retry using the command without any --label flags
  3. Only then apply the Graceful Degradation rule

This problem also appears identically in all four generated platform files:

  • platforms/claude/SKILL.md (Jira/Linear steps)
  • platforms/codex/SKILL.md (Jira/Linear steps)
  • platforms/copilot/specops.instructions.md (Jira/Linear steps)
  • platforms/cursor/specops.mdc (Jira/Linear steps)

@sanmak sanmak merged commit d23dd96 into main Mar 21, 2026
11 checks passed
@sanmak sanmak deleted the feat/add-rich-issue-body-composition-and-github-auto-labels branch March 21, 2026 16:18
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.

2 participants