You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CLAUDE.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -67,7 +67,7 @@ Priority: 0-4 (0=critical, 4=backlog). Never use "high"/"medium"/"low".
67
67
**This repo is the `dso` plugin.** Skills: interface-contracts, resolve-conflicts, tickets-health, design-onboarding, design-review, design-wireframe, ui-discover, debug-everything, sprint, brainstorm, preplanning, implementation-plan, fix-bug (canonical bug-fix workflow; replaces tdd-workflow for bug fixes), tdd-workflow (new feature TDD only), etc. Commands (commit, end, review) also come from the plugin. Skills are invoked as `/dso:skill-name` (fully qualified, required) or `/skill-name` (command alias, allowed but not preferred in docs). **Skill namespace qualification policy**: all skill invocations in in-scope files (plugins/dso/skills/, plugins/dso/docs/, plugins/dso/hooks/, plugins/dso/commands/, CLAUDE.md) MUST use the qualified `/dso:<skill-name>` form. `plugins/dso/scripts/check-skill-refs.sh` enforces this as a fatal CI check via `plugins/dso/scripts/validate.sh`; it exits non-zero when any unqualified reference is found. `plugins/dso/scripts/qualify-skill-refs.sh` is the one-shot bulk rewriter (idempotent) that transforms `/skill-name` → `/dso:skill-name` across all in-scope files — run it after adding new in-scope content with unqualified refs. Ticket scripts in `plugins/dso/scripts/` (`ticket` dispatcher, `tk-sync-lib.sh`, and 22+ utility scripts). Project-specific config in `.claude/dso-config.conf` (flat KEY=VALUE format; keys: `format.*`, `ci.*`, `commands.*`, `jira.*`, `design.*`, `tickets.*`, `merge.*`, `version.*`). `version.*` config keys: `version.file_path` (path to the file holding the project's semver string; absent = skip version bumping; supported formats: `.json` → `version` key, `.toml` → `version` field, plaintext/no-extension → single semver line). `test.*` config keys: `test.suite.<name>.command` (shell command to run the suite; config-only suites get `runner=config`), `test.suite.<name>.speed_class` (`fast|slow`; overrides auto-discovered default of `unknown`). Config entries merge with auto-discovered suites by name: config wins on explicitly set fields. Use `project-detect.sh --suites [REPO_ROOT]` to discover test suites — outputs a JSON array with `name`, `command`, `speed_class`, `runner` fields (exit 0 always). Heuristics in precedence order: config > Makefile `/^test[-_]/` > pytest dirs > npm scripts > bash runners. **CI workflow generation** (`/dso:project-setup`): when no `.github/workflows/*.yml` exist, `project-detect.sh --suites` feeds directly into `ci-generator.sh --suites-json <json> --output-dir .github/workflows/` to generate `ci.yml` (fast suites, pull_request trigger) and `ci-slow.yml` (slow suites, push-to-main trigger); YAML is validated via actionlint or `yaml.safe_load` before writing. For existing projects with uncovered suites, `/dso:project-setup` prompts the user for each suite: `fast-gate` (append job to gating workflow), `separate` (new workflow file), or `skip` (writes `test.suite.<name>.ci_placement=skip` to `.claude/dso-config.conf` to suppress future prompts). Non-interactive mode defaults fast suites to fast-gate and slow/unknown suites to separate.
68
68
`ci.*` config keys: `ci.workflow_name` (GitHub Actions workflow name for `gh workflow run`; absent = skip post-push CI trigger recovery — **preferred** over deprecated `merge.ci_workflow_name`). `merge.*` config keys: `merge.visual_baseline_path` (path to snapshot dir; absent = skip baseline intent check), `merge.ci_workflow_name` (**deprecated** — use `ci.workflow_name` instead; `merge-to-main.sh` falls back to this key with a deprecation warning when `ci.workflow_name` is absent), `merge.message_exclusion_pattern` (regex passed to `grep -vE` when composing merge message; default `^chore: post-merge cleanup`). Source of truth: `plugins/dso/scripts/merge-to-main.sh`. Phased workflow: `sync → merge → version_bump → validate → push → archive → ci_trigger`; state file at `/tmp/merge-to-main-state-<branch>.json` (4h TTL) records completed phases for `--resume`; lock file at `/tmp/merge-to-main-lock-<hash>` prevents concurrent runs; SIGURG trap saves current phase to state file on interrupt. The `version_bump` phase runs `bump-version.sh --patch` when `version.file_path` is configured and `--bump` is passed (or bump mode is on); patch bumps happen at merge time, not commit time. **Plugin portability**: All host-project path assumptions (app dir, make targets, Python version) are config-driven via `.claude/dso-config.conf` — the plugin is portable to projects with different directory structures. **Host project script invocation**: Host projects call DSO scripts via `.claude/scripts/dso <script-name>` (shim). Install with `bash plugins/dso/scripts/dso-setup.sh [TARGET_REPO]` from the repo root; the shim resolves DSO_ROOT from `CLAUDE_PLUGIN_ROOT` env var or `dso.plugin_root` in `.claude/dso-config.conf`.
69
69
70
-
**Ticket index merge driver**: `.tickets-tracker/.index.json` conflicts auto-resolve via `plugins/dso/scripts/merge-ticket-index.py` (JSON union merge; theirs-wins on true conflicts). `.gitattributes` maps the file to the `tickets-index-merge` driver (register per-clone; see Quick Reference). `worktree-sync-from-main.sh` includes a script-level fallback for CI/fresh-clone environments where the driver is not registered. The pre-commit review gate (`pre-commit-review-gate.sh`) handles merge commits (`MERGE_HEAD`) natively — when MERGE_HEAD exists, it computes the merge base and filters out incoming-only files (files changed on main but not on the worktree branch) from review consideration, since those were already reviewed on main. Fail-safe: if MERGE_HEAD equals HEAD or merge-base computation fails, normal review enforcement applies.
70
+
The pre-commit review gate (`pre-commit-review-gate.sh`) handles merge commits (`MERGE_HEAD`) natively — when MERGE_HEAD exists, it computes the merge base and filters out incoming-only files (files changed on main but not on the worktree branch) from review consideration, since those were already reviewed on main. Fail-safe: if MERGE_HEAD equals HEAD or merge-base computation fails, normal review enforcement applies.
71
71
72
72
**Worktree lifecycle** (`claude-safe`): After Claude exits, `_offer_worktree_cleanup` auto-removes the worktree if: (1) branch is ancestor of main (`is_merged`), AND (2) `git status --porcelain` is empty (`is_clean`). No special filtering — `.tickets-tracker/` files block removal like any other dirty file. `/dso:end` ensures the worktree meets these criteria by: generating technical learnings (Step 2.8) and creating bug tickets (Step 2.85) before commit/merge, and verifying `is_merged` + `is_clean` (Step 4.75) before session summary.
If the script reports ERROR with `CONFLICT_DATA:` prefix (merge conflicts in non-`.tickets/` files): invoke `/dso:resolve-conflicts` to attempt agent-assisted resolution. If resolution succeeds, continue to Step 5. If the script reports a non-conflict ERROR: relay the error message to the user and stop.
209
-
210
-
**CRITICAL — ticket conflict handling**: If a merge conflict occurs in `.tickets/` files (individual ticket `.md` files or archive files), do NOT use `git merge -X ours`, `git checkout --ours -- .tickets/`, or any other "accept worktree blindly" strategy. Main may have received ticket updates from another worktree. Instead, invoke `/dso:resolve-conflicts`, which will show the diff between both versions and ask the user which to keep.
208
+
If the script reports ERROR with `CONFLICT_DATA:` prefix (merge conflicts in non-ticket files): invoke `/dso:resolve-conflicts` to attempt agent-assisted resolution. If resolution succeeds, continue to Step 5. If the script reports a non-conflict ERROR: relay the error message to the user and stop.
211
209
212
210
### 4.5. Sync Tickets to Jira
213
211
@@ -271,11 +269,11 @@ cd "$REPO_ROOT"
271
269
git status --porcelain
272
270
```
273
271
274
-
**All four conditions must be true** before proceeding (exclude `.tickets/` — ticket files sync independently and may appear dirty in worktrees):
275
-
- No unstaged changes (`git diff --quiet -- ':!.tickets/'`)
Copy file name to clipboardExpand all lines: plugins/dso/skills/implementation-plan/SKILL.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -671,7 +671,7 @@ Fill the template placeholders with:
671
671
Parse the JSON `findings` array from the sub-agent response. For each finding:
672
672
673
673
- **If `type: "new_task"`**: Create a new task via `.claude/scripts/dso ticket create` with the finding's title and description, parent set to the story, add dependency on the appropriate existing task(s), and add to the summary table.
674
-
- **If `type: "ac_amendment"`**: Edit `.tickets/<target_task_id>.md` to append the finding's description as an additional acceptance criterion under the `## Acceptance Criteria` section.
674
+
- **If `type: "ac_amendment"`**: Use `.claude/scripts/dso ticket comment <target_task_id> "AC amendment: <description>"` to append the finding's description as an additional acceptance criterion.
Copy file name to clipboardExpand all lines: plugins/dso/skills/preplanning/SKILL.md
+7-7Lines changed: 7 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -53,7 +53,7 @@ This skill implements a five-phase process to transform epics into implementable
53
53
### Step 1: Select and Load Epic (/dso:preplanning)
54
54
55
55
If `<epic-id>` was not provided:
56
-
1. Run `.claude/scripts/dso ticket list` then filter results to epics only (cross-reference with `grep -l '^type: epic' .tickets/*.md`)
56
+
1. Run `.claude/scripts/dso ticket list` then filter results to epics only (filter JSON output where `ticket_type == 'epic'`)
57
57
2. If no open epics exist, report and exit
58
58
3. Present epics to the user (if more than 5, show first 5 with option to see more)
59
59
4. Get user selection
@@ -289,10 +289,10 @@ Parse the blue team's accepted findings and apply each one based on its `type`:
289
289
290
290
| Finding Type | Action |
291
291
|-------------|--------|
292
-
|`new_story`| Create a new story: `.claude/scripts/dso ticket create story "<title>" --parent=<epic-id>`. Then immediately use the Write or Edit tool to add the full body (description, done definitions, considerations) below the YAML frontmatter in `.tickets/<id>.md`. |
293
-
|`modify_done_definition`|Edit the target story's ticket file (`.tickets/<target_story_id>.md`) to add or modify done definitions per the finding's description. |
292
+
|`new_story`| Create a new story: `.claude/scripts/dso ticket create story "<title>" --parent=<epic-id>`. Then use `.claude/scripts/dso ticket comment <id> "<body>"` to add description, done definitions, and considerations. |
293
+
|`modify_done_definition`|Use `.claude/scripts/dso ticket comment <target_story_id> "Done definition update: <description>"` to record the modified done definition. |
294
294
|`add_dependency`| Add the dependency: `.claude/scripts/dso ticket link <target_story_id> <dependency_id> depends_on` (extract dependency ID from the finding's description). |
295
-
|`add_consideration`|Edit the target story's ticket file to append the consideration to its Considerations section. |
@@ -411,7 +411,7 @@ For new stories, create the ticket then immediately write the full story body in
411
411
STORY_ID=$(.claude/scripts/dso ticket create story "As a [persona], [goal]" --parent=<epic-id> --priority=<priority>)
412
412
```
413
413
414
-
Then use the Write or Edit tool to write the full body into `.tickets/<story-id>.md`, preserving the YAML frontmatter (lines 1–N ending with `---`) and replacing everything after it with the structured markdown body:
414
+
Then use `.claude/scripts/dso ticket comment <story-id> "<body>"` to add the structured body content:
415
415
416
416
```markdown
417
417
## Description
@@ -440,7 +440,7 @@ Then use the Write or Edit tool to write the full body into `.tickets/<story-id>
440
440
441
441
Omit the `## Escalation Policy` section if the user selected **Autonomous** in Phase 1 Step 1b. The ticket file must never be left as a bare title — always write the structured body immediately after creation.
442
442
443
-
For modified stories, edit`.tickets/<existing-id>.md` directly to update the title heading and body sections.
443
+
For modified stories, use`.claude/scripts/dso ticket comment <existing-id> "<updated content>"`to record changes.
444
444
445
445
For stories to delete:
446
446
```bash
@@ -818,7 +818,7 @@ After writing the Scope section for each story, verify every "OUT" assertion tha
818
818
| 2: Risk & Scope Scan | Flag cross-cutting concerns, identify split candidates | Lightweight analysis (no sub-agents) |
819
819
| 2.5: Adversarial Review | Red team attack on story map, blue team filter findings (skip if < 3 stories) |`Task` (opus red team, sonnet blue team) |
- If `$MERGE_IN_PROGRESS` is `yes` and no unresolved conflicts remain: report "Merge in progress with all conflicts pre-resolved — run `git commit` to finalize the merge." and exit. Do NOT report "no conflicts detected" — the merge needs committing, not aborting.
60
60
- If `$MERGE_IN_PROGRESS` is `no`: report "No conflicts detected — merge is clean." and exit.
61
61
62
-
Separate `.tickets/` conflicts from code conflicts:
62
+
Separate `.tickets-tracker/` conflicts from code conflicts:
**NEVER use `git checkout --ours -- .tickets/` or `git merge -X ours` for ticket conflicts.** Main may have received updates from another worktree; blindly accepting the worktree version can destroy those updates.
69
-
70
-
Handle `.tickets/` conflicts as follows:
71
-
72
-
-**`.tickets/` files** (individual ticket `.md` files, archive files): **Must show a diff to the user and ask which version to keep.** For each conflicted ticket file:
73
-
1. Show the diff between both versions:
74
-
```bash
75
-
echo"=== Ticket conflict: <file> ==="
76
-
git show :2:<file># ours (worktree version)
77
-
echo"--- vs main version ---"
78
-
git show :3:<file># theirs (main version)
79
-
```
80
-
2. Briefly summarize the differences (e.g., status changes, note additions, field changes)
81
-
3. Ask the user: "Keep worktree version, main version, or merge manually?"
82
-
4. Apply only after receiving explicit user confirmation
83
-
84
-
If only `.tickets/` conflicts existed and all are resolved (with user approval where required): complete the merge and exit.
68
+
If only `.tickets-tracker/` conflicts exist (JSON event files): auto-resolve by accepting ours (`git checkout --ours` + `git add` for each), complete the merge, and exit. Ticket event files are append-only and safe to auto-resolve.
85
69
86
70
If code conflicts exist: proceed to Step 2.
87
71
@@ -175,7 +159,7 @@ If resolution was abandoned (user chose to resolve manually):
175
159
176
160
## Constraints
177
161
178
-
- All `.tickets/`files (individual ticket `.md` and archive files) require user confirmation — never use "ours" strategy on them.
162
+
-`.tickets-tracker/`JSON event files are auto-resolved (accept ours) — they are append-only and safe to resolve without user input.
179
163
- Sub-agent model: **sonnet** — conflict resolution needs code understanding but not architectural reasoning
180
164
- This skill does NOT commit or push — it only completes the merge. The calling skill handles commit/push.
181
165
- Maximum 10 conflicted files. Above that, report to user: "Too many conflicts for agent-assisted resolution. Consider rebasing incrementally."
0 commit comments