Skip to content
Merged
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"plugins": [
{
"name": "task-orchestrator",
"version": "2.4.0",
"version": "2.4.1",
"description": "Skills, hooks, and workflows for MCP Task Orchestrator. Schema-aware context, note-driven workflow, and session hooks.",
"author": {
"name": "Jeff Picklyk",
Expand Down
84 changes: 80 additions & 4 deletions .claude/skills/prepare-release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,42 @@ Rules for each bullet:
- Do not mention internal class names, Kotlin types, or file paths
- Example: `Added \`includeAncestors\` to \`query_items\` — eliminates parent-walk call chains for breadcrumb context`

### 4d. Detect plugin content changes

Check if any files under `claude-plugins/` changed since the last tag:

```bash
git diff <LAST_TAG>...HEAD --name-only -- claude-plugins/
```

If the output is non-empty, plugin content changed.

**Read the current plugin version from the authoritative source** — do not assume it matches any
git tag. The version in the repository files may have been bumped in a previous standalone plugin PR
without a corresponding project release tag:

```bash
cat claude-plugins/task-orchestrator/.claude-plugin/plugin.json | grep '"version"'
```

Determine the plugin bump level using the same semver rules as the project version, but scoped
to plugin content:

| Condition | Plugin Bump |
|-----------|-------------|
| Breaking change to skill interface, hook behavior, or output style contract | **major** |
| New skill, new hook, new output style added | **minor** |
| Content fixes, wording, skill adjustments, script tweaks | **patch** |

Note the plugin bump level separately from the project bump level — they are independent.
If no plugin files changed, skip plugin versioning entirely.

**Standalone plugin release:** If plugin content changed but there are no project-level changes
(no new tools, no bug fixes, no API changes), this is a plugin-only release. In this case:
- Skip Steps 5 and 8a (no project version bump needed)
- The release branch and PR are still created, but only contain plugin version files + changelog
- Use commit message: `chore: bump plugin version to X.Y.Z`

---

## Step 5 — Infer Bump Level
Expand Down Expand Up @@ -125,6 +161,9 @@ Output the following block and **stop**. Wait for the user to confirm or request
**Bump level:** <major | minor | patch>
**Reason:** <one sentence>

**Plugin version:** <CURRENT → NEW> (<bump level>) — or "No plugin changes"
**Release type:** project release | plugin-only release

### Changelog Draft

## [X.Y.Z] - YYYY-MM-DD
Expand Down Expand Up @@ -166,7 +205,29 @@ VERSION_MINOR=1
VERSION_PATCH=0
```

### 8b. Insert new section into `CHANGELOG.md`
### 8b. Update plugin version files (if plugin content changed)

Skip this step if no plugin files changed in Step 4d.

Read the current plugin version from `claude-plugins/task-orchestrator/.claude-plugin/plugin.json`
(already retrieved in Step 4d). Calculate the new version using the plugin bump level from Step 4d.

Update **both** files with the new version:

1. `claude-plugins/task-orchestrator/.claude-plugin/plugin.json` — update the `version` field
2. `.claude-plugin/marketplace.json` — update `plugins[name="task-orchestrator"].version`

Also update the version table in `claude-plugins/CLAUDE.md`:
- Find the row for `task-orchestrator` and replace the version number

Stage the three files (in addition to version.properties):
```bash
git add claude-plugins/task-orchestrator/.claude-plugin/plugin.json \
.claude-plugin/marketplace.json \
claude-plugins/CLAUDE.md
```

### 8c. Insert new section into `CHANGELOG.md`

Read `CHANGELOG.md`. Find the first `## [` versioned entry (after the header). Insert the
new section **immediately above** it, with a trailing `---` separator and a blank line:
Expand All @@ -185,15 +246,29 @@ new section **immediately above** it, with a trailing `---` separator and a blan

Do not modify any existing entries.

### 8c. Stage, commit, and push
If plugin content changed (Step 4d), add under the appropriate section:
- Bumped plugin version to X.Y.Z (<reason>)

### 8d. Stage, commit, and push

```bash
git add version.properties CHANGELOG.md
git status # confirm only these two files are staged
# Plugin files (if changed — already staged from 8b)
git status # confirm only expected files are staged
git commit -m "release: bump to vX.Y.Z"
git push origin release/vX.Y.Z
```

**Standalone plugin release** (no project version bump — see Step 4d):

```bash
git add CHANGELOG.md
# Plugin files already staged from 8b
git status # confirm only plugin + changelog files are staged
git commit -m "chore: bump plugin version to X.Y.Z"
git push origin release/plugin-vX.Y.Z
```

---

## Step 9 — Pre-PR Checklist
Expand Down Expand Up @@ -276,5 +351,6 @@ Or use the Actions tab:
**Common mistakes to avoid:**
- Do not include raw commit hashes or internal file paths in the changelog
- Do not bump version without confirmation from the user
- Do not stage files other than `version.properties`, `CHANGELOG.md` (and `README.md` if fixes were needed)
- Do not stage files other than `version.properties`, `CHANGELOG.md`, plugin version files (if changed), and `README.md` (if fixes were needed)
- Do not create the PR if there are no commits ahead of the last tag
- Do not bump plugin versions outside of the release workflow
53 changes: 15 additions & 38 deletions claude-plugins/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,29 @@
# claude-plugins/ — Version Bump Requirement
# claude-plugins/ — Plugin Versioning

**Any change to plugin content in this directory requires a version bump.** However, the version bump should be done **once**, after all content changes are complete — not by each individual edit or subagent.
Plugin versions are bumped by the `/prepare-release` skill — either alongside a project release
or as a standalone plugin-only PR. They are **not** bumped per individual change during development.

Claude Code caches plugin content (skills, hooks, output styles, scripts) keyed by version number.
Without a version bump, Claude Code will continue serving the old cached copy — changes will not
take effect until the user removes and re-adds the marketplace.
During development, plugin changes (skills, hooks, output styles, scripts) are picked up by
removing and re-adding the marketplace in Claude Code. No version bump is needed for local iteration.

## What Triggers a Bump
## Current Plugin Versions

| Plugin | Directory | Current Version |
|--------|-----------|-----------------|
| `task-orchestrator` | `claude-plugins/task-orchestrator/` | `2.4.1` |

Changes to **any** file inside a plugin directory:
- `skills/` — skill markdown files
- `hooks/` — hook config JSON or referenced scripts
- `output-styles/` — output style markdown files
- `scripts/` — hook scripts (`.mjs`, `.sh`, etc.)
- `.claude-plugin/plugin.json` — plugin manifest
> Updated automatically by `/prepare-release`. Do not bump manually.

## What to Update
## Version Files

Two files must be kept in sync for each affected plugin:
Two files must stay in sync for each plugin:

| File | Field |
|------|-------|
| `.claude-plugin/marketplace.json` | `plugins[name="<plugin>"].version` |
| `claude-plugins/<plugin>/.claude-plugin/plugin.json` | `version` |

Both must carry the **same version string** after the bump.

## Versioning Convention

Use semantic versioning (`major.minor.patch`):
- **patch** — content fixes, wording, minor skill adjustments
- **minor** — new skill, new hook, new output style
- **major** — breaking changes to skill interface or hook behavior

## Current Plugin Versions

| Plugin | Directory | Current Version |
|--------|-----------|-----------------|
| `task-orchestrator` | `claude-plugins/task-orchestrator/` | `2.4.0` |

> Update this table when versions change.

## Delegation Warning

When multiple subagents edit plugin files in parallel, **only the orchestrator (or a single designated agent) should bump versions.** Subagents editing individual skill files must NOT independently bump version files — this causes cascading increments (e.g., 2.3.8 → 9 → 10 → 11) that must be corrected afterward. The orchestrator bumps once after all edits land.

## After Bumping

Re-add the marketplace in Claude Code to pull the updated cache:
1. Remove the marketplace (Claude Code settings → Plugins → Remove)
2. Re-add it pointing to this repo root
When multiple subagents edit plugin files in parallel, subagents must NOT modify version files.
Version bumps are handled by the orchestrator or by `/prepare-release` at release time.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "task-orchestrator",
"version": "2.4.0",
"version": "2.4.1",
"description": "Claude Code integration for MCP Task Orchestrator — schema-aware context, note-driven workflow",
"skills": "./skills",
"hooks": "./hooks/hooks-config.json",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@

You are a workflow orchestrator for the MCP Task Orchestrator. You plan, delegate, track, and report. Implementation is performed by subagents.

## Session Start

**First action every session:** invoke `/work-summary` before responding to the user.

## Note Schema Workflow

Items with schema tags (configured in `.taskorchestrator/config.yaml`) require notes before advancing through gates. The `schema-workflow` internal skill handles the full lifecycle — creating notes using `guidancePointer` and advancing through phases. Use `get_context(itemId=...)` to inspect gate status at any point.
Expand All @@ -14,12 +10,6 @@ If `get_context` returns no `noteSchema` for a tagged item, schemas may not be c

## Efficient Patterns

**2-call work summary (zero follow-up traversal):**
```
get_context(includeAncestors=true) → active items with full ancestor chains
query_items(operation="overview") → root containers with child counts
```

**Scoped role filter:** `query_items(operation="search", role="work")` — resolves to all work-phase statuses.

**Batch transitions:** `advance_item(transitions=[{itemId, trigger}, ...])` — prefer over sequential calls.
Expand Down
22 changes: 16 additions & 6 deletions claude-plugins/task-orchestrator/skills/batch-complete/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,24 @@ Before executing, show the user what will happen. Call:
query_items(operation="overview", itemId="<rootId>")
```

Parse the child counts by role and present a preview table:
Parse the child counts by role and present a preview table. Use the trigger chosen (or likely to be chosen) to set the action label — `trigger="complete"` shows "will be completed"; `trigger="cancel"` shows "will be cancelled":

```
◆ Impact Preview — "Auth System Feature"
◆ Impact Preview — "Auth System Feature" [trigger: complete]
○ queue: 3 items (will be completed)
◉ work: 1 item (active — will be force-completed)
◉ review: 1 item (active — will be force-completed)
✓ terminal: 2 items (already done — will be skipped)
```

```
◆ Impact Preview — "Auth System Feature" [trigger: cancel]
○ queue: 3 items (will be cancelled)
◉ work: 1 item (active — will be force-cancelled)
◉ review: 1 item (active — will be force-cancelled)
✓ terminal: 2 items (already done — will be skipped)
```

**For `itemIds` path** (no root item): call `query_items(operation="get", id="<uuid>")` on each item and build the same role-grouped preview table from the individual results. For large lists (10+ items), use `query_items(operation="search")` with filters instead of individual get calls.

**If any items are in `work` or `review`**, warn the user that active work will be force-completed (gate checks still apply). Use `AskUserQuestion` with three options:
Expand All @@ -78,16 +86,16 @@ Wait for the user's choice before continuing. Record whether to use `trigger="co

**Skip this step if `trigger="cancel"` was already chosen in Step 2** — cancel bypasses all gates, so gate checking is unnecessary.

For `trigger="complete"`, check gate status. Call `get_context` on the root item (or each specific item if using `itemIds`):
For `trigger="complete"`, gate previewing is best-effort. `complete_tree` performs the definitive gate check during execution and reports any failures in its response. A lightweight pre-check is still useful to surface issues before committing — call `get_context` on each child from Step 2's results rather than on the root item (the root itself is not completed by `complete_tree`, only its descendants are):

```
get_context(itemId="<rootId>")
get_context(itemId="<child-uuid>") ← repeat for each child listed in Step 2
```

If gate warnings exist, display them:
If any child's gate status shows missing required notes, display them:

```
⊘ Gate Warnings:
⊘ Gate Warnings (preview — definitive check runs at execution):
"Implement login" — missing: implementation-notes (work, required)
"Write tests" — missing: test-results (work, required)
```
Expand All @@ -106,6 +114,8 @@ Call `get_context(itemId=...)` to retrieve `guidancePointer` for items with miss

Wait for the user's choice. If they choose option 2, switch to `trigger="cancel"` for the execution step.

If `complete_tree` reports gate failures in Step 4, fill the missing notes and rerun `complete_tree` — items already in terminal are silently skipped on subsequent runs.

---

## Step 4 — Execute
Expand Down
28 changes: 18 additions & 10 deletions claude-plugins/task-orchestrator/skills/create-item/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ Classify the existing structure:

### Category mapping

| Item type | Target category container |
|-----------|--------------------------|
| Bug / error / crash / unexpected behavior | Bugs |
| Feature / enhancement / new capability | Features |
| Tech debt / refactor / cleanup / improvement | Tech Debt |
| Observation / friction / optimization / missing capability | Observations |
| Action item / follow-up / reminder / TODO | Action Items |
| General / unclear | Best-effort match — ask if uncertain |
| Item type | Target category container | Signal keywords |
|-----------|--------------------------|-----------------|
| Bug / error / crash / unexpected behavior | Bugs | bug, error, crash, broken, failure, wrong, exception |
| Feature / enhancement / new capability | Features | feature, add, implement, new, support, capability, enhancement |
| Tech debt / refactor / cleanup / improvement | Tech Debt | refactor, cleanup, simplify, debt, improve, migrate, restructure |
| Observation / friction / optimization / missing capability | Observations | slow, performance, optimize, latency, friction, missing, gap, observe |
| Action item / follow-up / reminder / TODO | Action Items | todo, follow up, remind, action, track, check |
| General / unclear | Best-effort match — ask if uncertain | |

### Anchoring decision tree

Expand All @@ -73,7 +73,9 @@ Empty (no project root exists):

## Step 4 — Apply tags via schema discovery

Read `.taskorchestrator/config.yaml` to discover available note schemas (this is a file read, not an MCP call). In Docker, the path is resolved via the `AGENT_CONFIG_DIR` env var. Each schema key is a tag that activates gate enforcement when applied to an item.
Read `.taskorchestrator/config.yaml` to discover available note schemas (this is a file read, not an MCP call). In Docker, the config is mounted at a path controlled by the `AGENT_CONFIG_DIR` env var — read `$AGENT_CONFIG_DIR/.taskorchestrator/config.yaml` if that variable is set, otherwise use `.taskorchestrator/config.yaml` relative to the working directory. Each schema key is a tag that activates gate enforcement when applied to an item.

**Error handling:** If the config file is not found, cannot be read, or contains invalid YAML, skip schema-based tagging and create the item without tags. Inform the user: "No schema config found — item created without schema tags." Do not abort item creation due to a missing or malformed config.

**Infer the best schema match from context:**

Expand Down Expand Up @@ -126,7 +128,13 @@ Default to single item when scope is unclear. Use `create_work_tree` only when t
Check `expectedNotes` in the create response. For each note where `required: true` and `role: "queue"`:
- Extract relevant content from the conversation
- Check each `expectedNotes` entry for a `guidance` field — use it as the authoring instruction for note content. Guidance takes precedence over free-form inference.
- Upsert: `manage_notes(operation="upsert", notes=[{itemId, key, role, body}])`
- Batch all notes into a single call rather than one call per note:
```
manage_notes(operation="upsert", notes=[
{itemId: "<uuid>", key: "reproduction-steps", role: "queue", body: "..."},
{itemId: "<uuid>", key: "root-cause", role: "queue", body: "..."}
])
```
- If conversation content is too sparse for a meaningful note body, leave it — do not fabricate content

---
Expand Down
Loading
Loading