Skip to content

feat(task-utils): bring MCP task server up to date, factored for ticket-utils reuse (from #157) - #216

Open
alex-nsheaps[bot] wants to merge 6 commits into
mainfrom
claude/task-utils-mcp-up-to-date
Open

feat(task-utils): bring MCP task server up to date, factored for ticket-utils reuse (from #157)#216
alex-nsheaps[bot] wants to merge 6 commits into
mainfrom
claude/task-utils-mcp-up-to-date

Conversation

@alex-nsheaps

@alex-nsheaps alex-nsheaps Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Splits the task-utils material out of the bundled, conflicting PR #157 and reconciles it onto current main (which has since migrated to the nx build system — the primary cause of #157's conflicts).

Brings task-utils up to date with:

  • MCP task server (mcp/, Bun/TS): task_create / task_update / task_list / task_get — a fallback for contexts where the built-in Task tools are unavailable (e.g. Claude Code on the web), so the write-gate hook stays satisfiable. Flat-YAML store under .claude/tasks/<id>.yaml, best-effort templated git auto-commit/push, shipped as source + built on-device (mcp/build.sh).
  • Redesigned hook suite: flat-YAML store libs, write-gate, 0-or-1 in_progress invariant, legacy/pull sync, native-task advisory, scope guard.
  • Skills: manage-tasks (renamed from task-manage) + new mcp-task-tools.
  • Docs: plans + research + build report from Add opt-out for require-task-in-progress gate via env var #157, plus a new docs/mcp-base-reuse.md.

Factored for ticket-utils reuse

The MCP base is structured so the SAME scaffolding can back a future ticket-utils MCP server:

  • mcp/src/git-helper.tstryGitAutoCommit() already takes the commit message as a parameter; only buildCommitMessage() is task-flavoured.
  • mcp/src/store.ts — flat-file CRUD + git-root resolution is format-agnostic; only the env-var name, store sub-path, and record type are task-specific.
  • mcp/build.sh / launch.sh / prewarm.sh + the server.ts bootstrap are fully generic.

The generic-vs-task-specific boundary and the recommended extraction path are documented in docs/mcp-base-reuse.md. No ticket-utils code is built here — this only keeps the base reusable and says so.

Wiring reconciled to current main (NOT copied from #157's stale base)

  • mise.toml: added build-task-mcp / test-task-mcp tasks and chained them into the nx build/test fan-out, so mise run build / mise run test (what CI runs) now also compile + test the MCP server. The MCP server is intentionally not a root workspace package (it ships as source and builds on-device).
  • .claude-plugin/marketplace.json: updated the existing task-utils entry only (description, +mcp keyword, version 0.4.0). Add opt-out for require-task-in-progress gate via env var #157's marketplace.json was discarded (it was built on a stale base that removed reddit/review-utils).
  • plugin.json bumped to 0.4.0 to match.
  • Integration test made self-contained (build-if-missing) so it passes under nx test ordering.
  • TS sources reformatted to the repo's prettier config (printWidth: 100).

Validation (all run locally, green)

  • mise run test-task-mcp66 pass / 0 fail (unit + integration) + all 7 hook-integration tests pass.
  • mise run validate → all plugin manifests + marketplace validate.
  • prettier --check (plugins workspace) → clean.
  • bash -n on all new shell scripts → clean.
  • bun install --frozen-lockfile (mcp) → lockfile intact.

Toolchain: bun 1.3.13/1.3.14, mise 2026.5.16 (both available locally).

Notes

Co-Authored-By: Agent Alex Picard <alex-nsheaps[bot]@users.noreply.github.com>

…ored for ticket-utils reuse

Reconciles the task-utils redesign from PR #157 onto current main (nx-based):
the Bun/TS MCP task server (task_create/update/list/get fallback for contexts
without the built-in Task tools), the redesigned hook suite (flat-YAML store,
write-gate, 0-or-1 invariant, legacy/pull sync, native-task advisory), the
manage-tasks + mcp-task-tools skills, and supporting docs.

Wiring adapted to current main (NOT copied from #157's stale base):
- mise.toml: added build-task-mcp / test-task-mcp tasks; chained into the nx
  build/test fan-out so CI compiles + tests the MCP server (it is not a root
  workspace package — it ships as source and builds on-device via mcp/build.sh).
- marketplace.json: updated the existing task-utils entry (description, +mcp
  keyword, version 0.4.0) — additive, existing entries untouched.
- integration test made self-contained (build-if-missing) so it passes under
  nx test ordering as well as `mise run test-task-mcp`.
- ts sources reformatted to the repo's prettier config (printWidth 100).

ticket-utils reuse: the MCP base (git-helper auto-commit engine, store flat-file
CRUD + git-root resolution, server bootstrap, build/launch/prewarm scripts) is
generic and intended to back a future ticket-utils MCP server. The reuse
boundary (what is generic vs task-specific) is documented in
docs/mcp-base-reuse.md. No ticket-utils code is built here.

Source PR #157 left open for Nate to close.

Co-Authored-By: Agent Alex Picard <alex-nsheaps[bot]@users.noreply.github.com>
@alex-nsheaps alex-nsheaps Bot added the request-review Force an AI code review on a draft PR (open non-draft PRs review automatically) label May 29, 2026
@github-actions

github-actions Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Plugin Version Preview

Preview only — plugin versions and marketplace.json are bumped automatically on merge to main, not in this PR. Manual bumps to higher versions are preserved. See the file annotations for the pending change on each plugin.json.

Plugin Base Current Action
task-utils 0.3.0 0.4.0 Already bumped

@henry-nsheaps henry-nsheaps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: Correctness 90% | Security 95% | Maintainability 88% | Simplicity 85%

Overview

Reconciles task-utils + MCP task server onto current nx main. 50 files, 2 commits, 66 unit/integration + 7 hook tests. The core acceptance criterion (MCP-created task satisfies the write-gate hook) is verified end-to-end. PR body is thorough and accurate.

What was done well

  • Two clean commits: the main feat commit + auto-bump chore. No fixup/WIP commits.
  • Atomic JSON→YAML migration: task-store-lib.sh shared lib ensures hooks and MCP server agree on store location. task-sync-from-legacy.sh correctly handles both JSON and YAML legacy formats.
  • build.sh: Lock-guarded, atomic temp-then-move build with version-pinned binary invalidation. Well-engineered.
  • Deletion path checked before terminal-status guard in tasks.ts (correct ordering — deleted cannot hit the "completed is terminal" check).
  • Dual enforcement: MCP server re-implements the same invariants (0-or-1 in_progress, validation-steps required, RESULT lines required) that the hooks enforce for built-in Task tools. Intentional and correctly documented in tasks.ts.
  • Reuse factoring (git-helper.ts, store.ts, build.sh, launch.sh, prewarm.sh) is solid. The generic/task-specific boundary documented in docs/mcp-base-reuse.md is a good pattern for the future ticket-utils server.
  • Test coverage: hook-integration test exercises the full create→promote→gate→complete lifecycle, which is the core acceptance criterion.

Follow-ups:

P2 — Atomicity veto disk-fallback uses jq against a YAML file

hooks/task-invariant.sh ~line 235–237:

TASK_SUBJECT="$(jq -r '.tool_input.subject // empty' <<<"$INPUT" 2>/dev/null || true)"
if [[ -z "$TASK_SUBJECT" ]]; then
  # Fallback: read from disk
  TASK_SUBJECT="$(jq -r '.subject // empty' "$TASK_FILE" 2>/dev/null || true)"
fi

TASK_FILE is now $FLAT_STORE/${TASK_ID}.yaml (YAML), but jq only parses JSON. When an agent calls TaskUpdate(taskId=N, status=in_progress) without supplying a subject (the common case — subject doesn't change on status transitions), the disk-fallback always silently returns empty and the atomicity keyword veto is bypassed.

The primary path (reading tool_input.subject from the JSON hook input) works correctly. The fix is one line — replace the jq disk read with the same grep/sed pattern used elsewhere in the file:

TASK_SUBJECT="$(grep -m1 '^subject: ' "$TASK_FILE" 2>/dev/null | sed 's/^subject: //; s/^"//; s/"$//')"

P2 (not P1) because the atomicity check also runs in-process in tasks.ts for MCP tool calls, and jq silently returns empty rather than producing a wrong value — it degrades gracefully.


P2task-sync-pull.sh ignores the syncPullEnabled / syncPullIntervalSecs settings-file keys

task-utils.settings.yaml documents syncPullEnabled: true and syncPullIntervalSecs: 60 as user-configurable, but task-sync-pull.sh reads only TASK_UTILS_SYNC_PULL and TASK_UTILS_PULL_INTERVAL_SECS env vars. Neither settings-file key is ever consulted. Users who set these in plugins.settings.yaml will see no effect.

Fix: source plugin-settings-lib.sh and call plugin_get_config "syncPullEnabled" "true" / plugin_get_config "syncPullIntervalSecs" "60" in addition to the existing env-var opt-out — matching the pattern used in require-task-in-progress.sh.


P2mise run test-task-mcp uses cd … && command chains

mise.toml test-task-mcp task:

run = """
cd plugins/claude-code/task-utils/mcp && bun test
cd "$MISE_PROJECT_ROOT" && bash plugins/claude-code/task-utils/mcp/test/hook-integration.test.sh
"""

The adjacent build-task-mcp task correctly uses the dir key. Prefer dir = "plugins/claude-code/task-utils/mcp" for the bun test line (and a separate task or dir = "." with an explicit path for the hook test), consistent with the project's bash-scripting conventions.


🤖 Automated review by Henry Oldenburg (QA). Session: henry/agents#216.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

move all the docs in docs/research in this pr into nsheaps/.org@main and remove from this PR so it's scoped just for the task-utils plugin + mcp server

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

move the implementation of each hook to on top of each other, with the bottom being stacked on top of the mcp server pr

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

make the mcp server it's own pr. Make it follow repo patterns. Make the service entry point in /services/task-mcp-service and use lib/ and package/ etc to properly abstract re-usable bits. Not building the ticket server in this PR but we know we're gonna be re-using it, and we know that tasks between orgs, and tickets between projects between orgs can all have different schemas stemming from the base.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

You didn't do this

@@ -1,15 +1,15 @@
---
name: task-manage
name: manage-tasks

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

it should be called task-manage, this is an old artifact. but we might wanna keep other stuff here

Comment thread plugins/claude-code/task-utils/skills/tool-task-mcp/SKILL.md
… fixes)

- Rename skill manage-tasks → task-manage (comment 3325267832)
- Rename skill mcp-task-tools → tool-task-mcp (comment 3325270819)
- Remove docs/research/ from plugin dir — to be moved to nsheaps/.org@main (comment 3325250273)
- Update all cross-references in README.md, plugin.json, and SKILL.md files

Architectural feedback (MCP server split + hook stacking) posted to Discord for Nate ack before executing.

@alex-nsheaps alex-nsheaps Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Immediate fixes landed in (pushed to branch):\n- Skill renamed → (comment #3325267832)\n- Skill renamed → (comment #3325270819)\n- removed from plugin dir (comment #3325250273) — 9 files deleted; need to move them to separately\n\nAwaiting your direction on two architectural items:\n\n1. MCP server split + service structure (comment #3325263429): You said to make the MCP server its own PR, with entry point at using and structure. My plan: move out of this plugin into a new tree with proper layering, open a new PR for it. This PR would then contain only the hooks + skills (no MCP server). Does that match your intent?\n\n2. Hook stacking (comment #3325254850): You said "move the implementation of each hook to on top of each other, with the bottom being stacked on top of the mcp server pr". I read this as: the hooks should be separate commits stacked on top of the new MCP server PR (i.e., hooks PR depends on MCP service PR). Is that correct? Or did you mean something about how the hooks are ordered within this PR?\n\nHolding on both until I hear back.

## 4. Doctrine — breakdown pattern (the worked example)

Canonical reference: `nsheaps/agents/docs/journal/2026/05/16/entry002-managing-tasks-example.md`. Excerpt:
Canonical reference: `nsheaps/agents/docs/journal/2026/05/16/managing-tasks-example.md`. Excerpt:

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

reference incorrect. remove file reference

alex-nsheaps Bot and others added 2 commits June 9, 2026 14:12
…SKILL.md

Line 89 referenced nsheaps/agents/docs/journal/2026/05/16/managing-tasks-example.md
which does not exist. Replaced with generic label per Nate review comment.

Co-Authored-By: Agent Alex Picard <alex-nsheaps[bot]@users.noreply.github.com>
…-service (#231)

The MCP server is now its own PR (agents#231) at services/task-mcp-service/
with a lib/src split (generic store-base + git-helper in lib/, task-specific
code in src/). This PR retains only the plugin + hooks.

- Remove plugins/claude-code/task-utils/mcp/ entirely
- Update .mcp.json launch path → services/task-mcp-service/launch.sh
- Update hooks.json prewarm path → services/task-mcp-service/prewarm.sh
- Update mise.toml build-task-mcp / test-task-mcp → services/task-mcp-service/

Co-Authored-By: Agent Alex Picard <alex-nsheaps[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

request-review Force an AI code review on a draft PR (open non-draft PRs review automatically)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant