Add opt-out for require-task-in-progress gate via env var - #157
Draft
nsheaps wants to merge 50 commits into
Draft
Conversation
…0.1.1) require-task-in-progress.sh blocks all Write/Edit/MultiEdit/NotebookEdit unless a Task is in_progress, but the TaskCreate/TaskUpdate tools that create that state are not enabled in every Claude Code context — notably Claude Code on the web — leaving the gate permanently unsatisfiable. Add an env-var opt-out: TASK_UTILS_REQUIRE_TASK=0 makes the hook exit 0 with no decision (normal permission handling still applies). Unset or any other value keeps the gate enforced, so there is no behavior change for existing consumers. Documented in the hook header and README. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
Contributor
Plugin Version StatusVersions are auto-bumped in PRs. Manual bumps to higher versions are preserved.
|
Captures the design plan, the five research documents (Task tools/state, MCP SDK, session-id verification, repo-storage decision, git-auto-commit design), and the execution-phase build report for the task-utils MCP task server. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
…ools contexts Adds a bundled stdio MCP server (task-mcp) exposing task_create, task_update, task_list, and task_get — mirrors the built-in Claude Code Task tools so the require-task-in-progress.sh write-gate stays satisfiable where the built-ins are unavailable (notably Claude Code on the web). - Storage is FLAT in the CWD git repo (<repo>/.claude/tasks/<id>.json), overridable with TASK_UTILS_TASK_DIR. - Re-implements the task-invariant.sh lifecycle invariants in-process (born-pending, 0-or-1 in_progress, validation-steps, RESULT lines). - Best-effort templated git auto-commit + push on every task write. - Built with bun into a committed self-contained dist/server.js bundle; run via bun. 66 unit/integration tests + a hook write-gate test. - .gitignore exception so the task-utils MCP bundle is tracked. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
…session store
Adds hooks/task-store-lib.sh, a shared store-resolution library sourced by both
PreToolUse hooks. require-task-in-progress.sh now resolves the flat MCP store
(TASK_UTILS_TASK_DIR, else the CWD git repo's .claude/tasks) AND still scans the
legacy ${CLAUDE_CONFIG_DIR:-$HOME/.claude}/tasks/<session_id>/ store the built-in
Task tools write to — an in_progress task in either store satisfies the
write-gate. task-invariant.sh scans both stores for the 0-or-1 in_progress
invariant. The TASK_UTILS_REQUIRE_TASK=0 opt-out is preserved.
https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
…P fallback - Version 0.1.1 -> 0.1.2 in plugin.json and the repo marketplace.json. - New skills/mcp-task-tools/SKILL.md guiding correct use of the task-mcp MCP tools when the built-in Task tools are unavailable. - manage-tasks/SKILL.md gains an MCP-fallback note in the lifecycle section. - README documents the MCP server, the flat/legacy storage model, and the best-effort git auto-commit. - mise.toml adds build-task-mcp and test-task-mcp tasks. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
Sub-agent git worktrees are created under .claude/worktrees/ as local working areas; they must never be committed (a nested worktree) and were showing up as untracked. Ignore the directory. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
The marketplace.json had a manually-added `mcp` tag that `update-marketplace` would not preserve (tags are generated from directory presence, not metadata). The `mcp` keyword also appeared in marketplace.json but not in plugin.json (the source of truth), so every CI `update-marketplace` run produced a diff. Fixes: - Add "mcp" to plugin.json keywords so update-marketplace propagates it - Remove manual "mcp" tag from marketplace.json (not directory-generated) - Regenerate marketplace.json via update-marketplace + prettier for consistency After this commit, `mise run update-marketplace` is idempotent on this branch and the auto-version-bump CI job sees no drift to commit. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
…ith update-marketplace) The previous commit formatted marketplace.json with prettier (compact arrays). The update-marketplace script generates jq-expanded format, so the file would always show as modified when CI ran update-marketplace. Commit the jq-expanded format so the script is idempotent and CI auto-version-bump sees no drift. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
Replace the committed `bun build --target=node` JS bundle with an
on-device `bun build --compile` native executable. The plugin now ships
TypeScript source only; the platform-specific binary is built lazily on
the end user's machine on first use and is never committed.
- mcp/build.sh: idempotent, lock-guarded build-if-missing. Compiles to
${CLAUDE_PLUGIN_DATA}/bin/task-mcp (persists across plugin updates),
keyed by plugin version so a bump triggers a one-time rebuild. Atomic
mkdir lock + temp-path/mv publish make it loop-safe and crash-safe.
- mcp/launch.sh: the MCP server's launch command — builds (if missing)
then execs the binary. Load-bearing: the server cannot start without a
binary, no hook-ordering race.
- mcp/prewarm.sh: SessionStart hook that kicks the build off in the
background so the binary is usually ready before the MCP server connects.
- .mcp.json: launch via mcp/launch.sh; pass CLAUDE_PLUGIN_DATA.
- .gitignore / mcp/.gitignore: dist/ is ignored — binary never committed.
- server.ts: isMain uses import.meta.main (compiled-binary safe; the old
argv[1] path check never matched a compiled binary). Version 0.1.3.
- mise build-task-mcp + tests: build/run the compiled binary directly.
mise run check green: 66/66 unit tests, all 7 hook-integration tests.
https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
The MCP server binary is keyed by plugin version, so the version bump in plugin.json + marketplace.json triggers the one-time on-device rebuild on update. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
- docs/research/native-build-strategy.md: new — rationale, binary location, build triggering, dependency handling, idempotency, verification evidence. - docs/plans/mcp-task-server.md §7: mark Strategy A superseded by Strategy C (on-device native compile). - README.md: document the on-device build flow + bun requirement. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
writing-agent-team-agents/SKILL.md and tmux-usage/SKILL.md lacked the --- frontmatter block, producing a validation warning on every `claude plugin validate` run. Add name + description frontmatter to both, eliminating the warning so the plugin validates cleanly. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
Documents the investigation of GitHub Actions run 26240378240 failing the validate job, root-cause analysis, local verification results, and the changes made (native-build commits + agent-utils frontmatter fix). https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
… PR #157) Records root-cause analysis, local verification evidence, and commit hashes for both the validate fix (313a3f0) and the lint fix (0a7fc5a). https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
… (phase 1) - store.ts: import yaml package, change filePath/listIds/read/write to use .yaml extension and yaml.parse/yaml.stringify - server.ts: bump SERVER_VERSION to 0.1.4 - package.json: add yaml@2.9.0 dependency, bump version to 0.1.4 - store.test.ts: update flat-file test expectation to .yaml - integration.test.ts: update file existence checks and parse to YAML All 66 unit + integration tests pass. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
- task-store-lib.sh: change count_in_progress_flat to use *.yaml glob and grep/awk instead of jq for status extraction - task-invariant.sh: change 0-or-1 flat-store scan to use *.yaml glob and grep/sed/awk instead of jq for id/status/subject extraction - hook-integration.test.sh: update file existence checks and field extraction to use *.yaml and grep/awk patterns All 7 hook-integration tests pass. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
…re (phase 3) - README.md: update Flat (MCP) row to show <task-id>.yaml - skills/mcp-task-tools/SKILL.md: update storage section to <id>.yaml - skills/manage-tasks/SKILL.md: update MCP fallback note to <id>.yaml https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
…phase 4) - .claude-plugin/plugin.json: version 0.1.3 -> 0.1.4 - .claude-plugin/marketplace.json: regenerated (task-utils 0.1.4) - docs/plans/yaml-conversion.md: add the implementation plan (untracked file) https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
The PR branch adds YAML frontmatter to two agent-utils skills (tmux-usage, writing-agent-team-agents) on top of main's 0.4.1, so the plugin needs a version bump. Run via the canonical auto-bump + update-marketplace flow. This makes the auto-version-bump CI job a clean no-op (agent-utils already bumped, task-utils already at 0.1.4). https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
claude-code 2.1.146 ships a broken native-binary install — `claude plugin validate` errors "claude native binary not installed", failing the validate CI job. mise's npm:@anthropic-ai/claude-code = "latest" floated onto it. Pin to 2.1.143 (last known-good — verified passing in ai-mktpl PR #391's validate run, all plugins green). Also pin jq to 1.8.1 for reproducible CI. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
Pinning claude-code to 2.1.143 alone did not unbreak the validate job — `claude plugin validate` still failed "claude native binary not installed". claude-code's native binary is downloaded by a node postinstall script, and the agents mise.toml never declared `node`, so the postinstall could not run. ai-mktpl's mise.toml has `node` and its validate passes; jack's mise.toml declares `depends = "node"` on claude-code for the same reason. Add node 24.15.0 + `depends = "node"` on the claude-code tool entry. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
The validate task runs `claude plugin validate`, but mise's npm backend installs @anthropic-ai/claude-code with --ignore-scripts, so the postinstall that downloads the platform-native binary never runs — `claude` then errors "claude native binary not installed". ai-mktpl's validate only passed by restoring a stale mise cache; any cache miss hits the same failure. Run claude-code's install.cjs at the top of the validate task. Verified locally: fresh mise install of claude-code 2.1.143 fails `claude --version`, and after running install.cjs `claude plugin validate` succeeds. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
…ooks Add two new hooks to fix RC1 (auto-commit for built-in TaskCreate/TaskUpdate): hooks/task-auto-commit.sh (PostToolUse: TaskCreate|TaskUpdate): - Best-effort git add+commit+push after built-in task tool writes - Attempts legacy store file commit (skips gracefully if outside repo) - Also stages any unstaged flat-store *.yaml changes as secondary path - Programmatic commit messages (never AI-generated) - Exits 0 always; logs to .claude/logs/task-auto-commit.log hooks/task-sync-pull.sh (PreToolUse: Write|Edit|MultiEdit|NotebookEdit): - Throttled pull: at most once per TASK_UTILS_PULL_INTERVAL_SECS (default 60s) - Sentinel file (.last-sync-pull) tracks last pull time - git pull --ff-only; logs failure but does not block on pull error - Conflict detection: scans both flat-store *.yaml and legacy *.json for duplicate task IDs after pull; denies write if duplicates found - Opt-out: TASK_UTILS_SYNC_PULL=0 (mirrors TASK_UTILS_REQUIRE_TASK pattern) hooks/hooks.json updated: - Added PostToolUse entry for TaskCreate|TaskUpdate -> task-auto-commit.sh - Added task-sync-pull.sh before require-task-in-progress.sh in PreToolUse - Added UserPromptSubmit -> task-scope-guard.sh (RC4, added in next commit) https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
…sory RC3 — fix(task-utils): dual-scan legacy store for YAML+JSON in count_in_progress task-store-lib.sh: - Add count_in_progress_store(): scans BOTH *.yaml (MCP flat store) and *.json (built-in TaskCreate/TaskUpdate legacy store) for in_progress tasks - count_in_progress_flat() now delegates to count_in_progress_store() for backward compat; callers unchanged task-invariant.sh: - 0-or-1 invariant scan now loops over both *.yaml and *.json in each scan_dir (TASKS_DIR and FLAT_STORE), extracting id/status/subject from JSON files via jq instead of grep Fixes the critical bug where agents using built-in Task tools always had their tasks invisible to the invariant scan (*.yaml-only), causing: - False allows: second in_progress via MCP while built-in had one - False denies: write-gate denied because it saw 0 in_progress (missing JSON) RC2 — feat(task-utils): enforce atomicity check on pending→in_progress task-invariant.sh: - Added atomicity veto block between 0-or-1 invariant and validation-steps check - Denies pending→in_progress when task subject matches non-atomic keywords: plan, planning, investigate, investigation, figure out, design, audit, improve, improvement, refactor, refactoring, fix everything, update everything, various, miscellaneous, misc, set up everything, cleanup, clean up - Escape hatch: <!-- atomic: confirmed --> anywhere in description bypasses veto - Deny message explains breakdown procedure and escape hatch RC4 — feat(task-utils): add scope-guard advisory for UserPromptSubmit hooks/task-scope-guard.sh (UserPromptSubmit): - Detects scope-expansion phrases in user prompt: "also add", "while you're at it", "additionally", "and also fix", etc. - Emits systemMessage advisory (NOT a blocking deny — OQ6 advisory-only) - Only fires when a task is currently in_progress - Scans both flat-store *.yaml and legacy *.json for in_progress task - Logs to .claude/logs/task-scope-guard.log https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
Version bump: 0.1.4 → 0.1.5 Changes included since 0.1.4: - feat: scaffold plugin-dev plugin + data-storage skill (2a) - chore: migrate .json task files to .yaml in farish (2b) - feat: PostToolUse auto-commit (task-auto-commit.sh) (2d) - feat: throttled PreToolUse pull sync (task-sync-pull.sh) (2d) - fix: dual-scan YAML+JSON for count_in_progress (RC3) (2e) - feat: atomicity veto with escape hatch (RC2) (2e) - feat: scope-guard advisory via UserPromptSubmit (RC4) (2e) Validation: 66 bun tests pass + 7/7 hook-integration tests pass. All new hooks manually validated (allow/deny/advisory paths verified). https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
- task-store-lib.sh: count_in_progress_flat back to YAML-only; remove count_in_progress_store dual-scan; keep resolve_legacy_store_dir for task-sync-from-legacy.sh (R3) to locate legacy files for conversion. - task-invariant.sh: 0-or-1 invariant scans flat YAML store only; task file lookup reads FLAT_STORE/<id>.yaml (not legacy JSON); remove TASKS_DIR/legacy store resolution. - require-task-in-progress.sh: drop LEGACY_STORE + LEGACY_COUNT; gate satisfied by flat YAML store in_progress count only. - hook-integration.test.sh: Test 7 updated — tests flat-store-only conflict detection (two MCP tasks, not flat+legacy cross-store). https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
- hooks/builtin-tasks-detect.sh: new sourced lib; is_builtin_tasks_enabled() checks CLAUDE_CODE_ENABLE_TASKS with same semantics as Claude Code (0/false/off/no → disabled; 1/true/on/yes → enabled; unset → TTY check). - hooks/plugin-settings-lib.sh: new sourced lib; plugin_get_config() implements 3-tier config resolution (project > user > plugin defaults) using plugins.settings.yaml under "task-utils:" block; yq-backed with grep/sed fallback; handles hyphens in namespace keys. - task-utils.settings.yaml: plugin default settings (enabled, nativeTaskMode, syncPullEnabled, syncPullIntervalSecs, requireTaskInProgress); camelCase keys per settings-key-naming.md. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
- hooks/task-sync-from-legacy.sh: new PostToolUse hook; skips if built-in tasks disabled; locates legacy JSON/YAML at ~/.claude/tasks/<sid>/<id>; converts JSON→YAML and writes to flat store (<project>/.claude/tasks/<id>.yaml); git add + commit + push (best-effort, exit 0 always); logs to .claude/logs/task-sync-from-legacy.log. - hooks/hooks.json: replace PostToolUse task-auto-commit.sh entry with task-sync-from-legacy.sh; update description. - hooks/task-auto-commit.sh: deleted (superseded by task-sync-from-legacy.sh). https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
- hooks/task-native-warning.sh: new PreToolUse hook on TaskCreate|TaskUpdate; reads nativeTaskMode from 3-tier plugins.settings.yaml config (project > user > default); silent → exit 0; warn → additionalContext recommending MCP tools; block → permissionDecision: deny. Skips when built-in tasks disabled. Logs to .claude/logs/task-native-warning.log. - hooks/hooks.json: add task-native-warning.sh as second hook in the TaskCreate|TaskUpdate PreToolUse entry (after task-invariant.sh). https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
… + version + docs R5 (MCP audit): grep of mcp/src/ confirmed zero legacy-store references — no code changes needed. The MCP server already writes only to the flat YAML store (<repo>/.claude/tasks/<id>.yaml) and never touches ~/.claude/tasks/<session_id>/. R6 changes: - require-task-in-progress.sh: source plugin-settings-lib.sh; honour requireTaskInProgress: false in plugins.settings.yaml as a second opt-out alongside the legacy TASK_UTILS_REQUIRE_TASK=0 env var. Both disable the write-gate; env var takes priority (backward compat). - plugin.json: version 0.1.5 → 0.2.0; description updated to reflect 0-or-1 invariant on flat YAML store, write-tool gating, PostToolUse legacy-sync, native-task advisory/block, pull sync, and MCP task server as primary task path. - SKILL.md §5: updated to document flat-YAML-only scan (R1), PostToolUse sync (R3), native-task advisory (R4), and nativeTaskMode setting. - README.md: new Configuration section documenting task-utils.settings.yaml 3-tier config, all settings keys, and example project-level override; task storage table updated; hook list updated with task-native-warning.sh and task-sync-from-legacy.sh entries. https://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p
This was referenced May 24, 2026
Enumerates the 4 follow-up tasks identified during the task-utils R1–R6 redesign and tracks each as a GitHub issue: - #168 — R7 in-session validation (blocks #157 merge) - #169 — auto-version-bump workflow false-positive fix - #170 — promote plugin-settings-lib.sh to shared-lib - nsheaps/farish#3 — migrate legacy JSON tasks to YAML Issues chained Blocked-by per handler instruction "execute in order."
This was referenced May 25, 2026
alex-nsheaps Bot
added a commit
that referenced
this pull request
May 25, 2026
) PR #172 pinned to 2.1.143 (Jack's PR #157 commit version). But all agent repos (alex/jack/henry mise.toml) and the bin/agent patcher use 2.1.128. Mismatch causes the launcher's `mise which claude` to resolve differently in CI vs on agents. Bump down to 2.1.128 for parity. Per Nate Discord 02:54Z. Co-authored-by: alex-nsheaps[bot] <279051173+alex-nsheaps[bot]@users.noreply.github.com> Co-authored-by: Agent Alex Picard <alex-nsheaps[bot]@users.noreply.github.com>
alex-nsheaps Bot
added a commit
that referenced
this pull request
May 28, 2026
Per Nate Discord 2026-05-28 02:31Z scope expansion of FXP/1.8 — this ticket tracks the dependency branch: port the Bun task-MCP server from #157, apply the plugin task opt-out + CI fixes, and leave unrelated #157 concerns (baseline backout, YAML store, farish archive) out of scope. GSD-66 blocks GSD-62 (FXP/1.8 ticket-MCP). Co-Authored-By: Agent Alex Picard <alex-nsheaps[bot]@users.noreply.github.com>
alex-nsheaps Bot
added a commit
that referenced
this pull request
May 28, 2026
Per Nate Discord 02:50Z: GSD-62 (simple ticket-MCP) blocks GSD-66, not the reverse. GSD-66 = the significantly expanded thing (port task-MCP from #157 + bolt on multi-backend storage / reconciliation / CLI / shared-code patterns). Added expanded scope sections + research checkpoint. Reframed as "Blocked by GSD-62" not "Blocks GSD-62". Co-Authored-By: Agent Alex Picard <alex-nsheaps[bot]@users.noreply.github.com>
Contributor
|
Superseded by #178 (feat(task-utils): make blocking configurable via plugins.settings.yaml (v0.3.0)), which was merged 2026-05-26. The env-var approach ( plugins:
task-utils:
requireTaskInProgress: falseClosing in favor of the merged implementation. |
This was referenced May 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This branch contains several related improvements to the agents repo.
1. task-utils plugin (earlier commits)
Task*tools are unavailable (web sessions, etc.). Builds natively on-device viamcp/build.sh.TASK_UTILS_REQUIRE_TASK=0disables the require-task-in-progress gate for Tool-less contexts.2. CI fixes (mid-branch)
claude-codeto 2.1.128 (backout target version).nodedependency so claude-code native binary installs correctly in CI validate job.inputs.*usage in workflowif:conditions causingstartup_failure.3. Session history archive
docs/journal/2026/05/22/farish-history.jsonl.4. agent-tools-baseline backout (latest commit)
The
agent-tools-baselinedesign (shared conf.d fragment across agent repos) was reversed:packages/agent-tools-baseline/(the canonical fragment package).config/mise/conf.d/00-agent-baseline.toml(the conf.d fragment)mise/tasks/sync-mise-baselineandmise/tasks/check-mise-baseline.claude/plans/agent-tools-baseline.mdtest.yaml[tools]inmise.tomlwithbun = "1.3.14"andclaude-code = "2.1.128"Test plan
mise.toml [tools]contains explicit tool versions (bun 1.3.14, claude-code 2.1.128, node 24.15.0)conf.d/fragment, no baseline package, no sync/check taskstest.yamllint job has nocheck-mise-baselinestephttps://claude.ai/code/session_01AiWbZuSU6UCjuXnrBBFk9p