diff --git a/CHANGELOG.md b/CHANGELOG.md index be86693..5f4f40e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ Please choose versions by [Semantic Versioning](http://semver.org/). * MINOR version when you add functionality in a backwards-compatible manner, and * PATCH version when you make backwards-compatible bug fixes. +## Unreleased + +- feat: Move task-creation consent gate from `vault-cli:work-on-task-assistant` agent to the `work-on-task` slash command — agent loses the `Skill` tool (architectural block on `Skill: vault-cli:create-task`); `Task` is retained for legitimate subagent dispatch in Phase 5 (`coding:pre-implementation-assistant`) and Phase 7 (`vault-cli:task-manager-agent`). On miss the agent emits a structured `not_found:` verdict; the slash command parses it, asks the user via `AskUserQuestion`, and on `Yes` routes to `Skill: vault-cli:create-task` before re-invoking the agent against the new task. +- feat: Add `not_found` form to `vault-cli:work-on-task-assistant` `` so the slash command can parse the absence case (searched-source evidence + suggested task name) + ## v0.68.1 - bump Go 1.26.3 → 1.26.4 diff --git a/agents/work-on-task-assistant.md b/agents/work-on-task-assistant.md index d9b52fc..c264e80 100644 --- a/agents/work-on-task-assistant.md +++ b/agents/work-on-task-assistant.md @@ -2,7 +2,7 @@ name: work-on-task-assistant description: Prepare a task for work — find details, set status, track on daily note, discover guides. Works in any vault; gracefully degrades when Jira / semantic-search MCPs are unavailable. model: sonnet -tools: Read, Glob, Bash, Edit, AskUserQuestion, Task, Skill, mcp__semantic-search__search_related, mcp__atlassian__getAccessibleAtlassianResources, mcp__atlassian__atlassianUserInfo, mcp__atlassian__getJiraIssue, mcp__atlassian__editJiraIssue, mcp__atlassian__getTransitionsForJiraIssue, mcp__atlassian__transitionJiraIssue, mcp__atlassian__lookupJiraAccountId +tools: Read, Glob, Bash, Edit, AskUserQuestion, Task, mcp__semantic-search__search_related, mcp__atlassian__getAccessibleAtlassianResources, mcp__atlassian__atlassianUserInfo, mcp__atlassian__getJiraIssue, mcp__atlassian__editJiraIssue, mcp__atlassian__getTransitionsForJiraIssue, mcp__atlassian__transitionJiraIssue, mcp__atlassian__lookupJiraAccountId color: blue --- @@ -30,9 +30,9 @@ Mutations happen **before** guide discovery and report rendering. Verify after w - AUTO: Jira tasks assigned to current user + transitioned to "In Progress" (no asking) - AUTO: Obsidian task status set to `in_progress` (no asking) -- ASK: before creating a new Obsidian task file -- MANDATORY for code tasks: run `/coding:check-guides` and read project Development Guide if present -- READ-ONLY except: status frontmatter + daily-note tracking + (via Skill) task creation +- MANDATORY for code tasks: dispatch `Task(subagent_type='coding:pre-implementation-assistant', ...)` and read project Development Guide if present (replaces the prior `Skill: coding:check-guides` invocation — `Skill` is no longer in `tools:`) +- READ-ONLY except: status frontmatter + daily-note tracking +- ALLOWED `Task` subagent dispatch is restricted to: `coding:pre-implementation-assistant` (Phase 5), `vault-cli:task-manager-agent` (Phase 7). NEVER dispatch to a `*create-task*`, `*creator*`, or any subagent whose role is to create task files — the consent gate lives in the calling slash command (`vault-cli:work-on-task` Phase 4), not in a sibling agent. `Task` is a generic dispatch primitive; it does not grant create-task capability by itself, but routing through a creator-agent would defeat the architectural gate. - ALWAYS present absolute file paths - **NEVER fall back to direct HTTP for Jira (no `curl`, no `wget`, no `gh api` against Jira hosts).** If no `mcp__atlassian__*` MCP is available, skip every Jira block silently. Direct API calls bypass authentication and credential management and are forbidden. @@ -90,7 +90,9 @@ If `JIRA_MCP_AVAILABLE` is false but input looks like a Jira ID: - Otherwise: `Glob: {tasks_dir}/**.md` **Task not found**: -- AskUserQuestion → "Create new task?" — Yes invokes `Skill: vault-cli:create-task`; No shows manual search tips and STOPS +- Emit the `not_found:` verdict block (literal `not_found:` header on its own line — see `` for the exact form) with the searched-source evidence (Jira: hit/miss/skipped, daily-note: hit/miss, semantic-search: top-3 misses with scores, Glob: paths tried) and a `Suggested task name:` line derived from the input argument (or, if input is a Jira ID, from the Jira issue summary returned by the Jira lookup; fall back to the raw input string if neither is available). +- STOP — do NOT propose a fix, do NOT call AskUserQuestion, do NOT invoke `Skill: vault-cli:create-task`. +- The `not_found` verdict is parsed by the calling slash command (`vault-cli:work-on-task`) which owns the create-gate. ## Phase 2: Auto-assign + transition Jira (Jira tasks only) — DO THIS FIRST @@ -110,7 +112,7 @@ Skip silently if `JIRA_MCP_AVAILABLE` is false. Record each result for the final report (✅ / ℹ️ / ⚠️). Errors do NOT block subsequent phases — but they MUST surface in the report. -## Phase 3: Find/create Obsidian task and set status +## Phase 3: Find Obsidian task and set status - `Glob: {tasks_dir}/*{keywords}*.md` - If Jira: also `Grep: 'jira: {key}'` in `{tasks_dir}` @@ -121,9 +123,7 @@ If found: - Report: `✅ Status: {old} → in_progress` If not found AND task came from Jira: -- AskUserQuestion → "Create Obsidian task file for local tracking?" -- Yes → `Skill: vault-cli:create-task` then re-find + set status -- No → continue Jira-only +- The Jira issue exists but there is no local Obsidian task file. This is a `not_found` case for the Obsidian side — the calling slash command's Phase 4 owns task creation. Emit the `not_found:` verdict (see Phase 1 and ``) including the Jira summary as the `Suggested task name:` value and STOP — do NOT call AskUserQuestion, do NOT invoke `Skill: vault-cli:create-task`. The slash command handles the consent gate. ## Phase 4: Track on daily note @@ -139,7 +139,7 @@ If not found AND task came from Jira: Heuristic: title or description contains "fix", "implement", "refactor", "add", "bug", "deploy", "build", or extension `.go`/`.py`/`.ts`/`.js` etc. If code task: -- `Skill: coding:check-guides` with task title/description +- `Task(subagent_type='coding:pre-implementation-assistant', prompt='Find relevant coding guidelines for: ')` — subagent dispatch instead of `Skill:` (the `Skill` tool was removed to enforce the consent gate; `Task` dispatching to the pre-implementation assistant returns the same guide set without granting create-task capability) - Search vault for `*Development Guide.md` and read if found - Extract: branch strategy, test command, PR process, deploy steps - Present as "⚠️ **Development Workflow**" section in the report @@ -190,6 +190,8 @@ When the task description, a related log entry, or any retrieved file references **Verification gate — runs before rendering the report. Do NOT skip.** +**Carve-out for `not_found`**: if Phase 1 emitted a `not_found` verdict, Phase 8 is a no-op — the `not_found` verdict IS the report, no mutations occurred to verify, and the agent STOPs without emitting "Ready to work on this task." (which is the found-case marker, not a universal one). Skip every assertion below in this case. + If `JIRA_MCP_AVAILABLE` AND input was a Jira ID: 1. Re-fetch the issue: `mcp__atlassian__getJiraIssue(cloudId={JIRA_CLOUD_ID}, issueIdOrKey={key}, fields=["status","assignee"])` 2. Assert `status.name == "In Progress"` AND `assignee.accountId == current_user_account_id` @@ -215,7 +217,7 @@ Jira: ✅ Verified post-mutation (status=In Progress, assignee=) | ⚠️ Verification failed:
[Obsidian:] -✅ Status: → in_progress | ✅ Created Obsidian task file | ℹ️ Continuing Jira-only +✅ Status: → in_progress | ℹ️ Continuing Jira-only [Daily Note:] ✅ Tracked on today's page | ℹ️ Already tracked | ℹ️ Daily note missing @@ -253,12 +255,26 @@ Remaining: --- Ready to work on this task. ``` + +```markdown +not_found: +📋 Task: [()] +Status: not_found + +Searched: +- Jira: | | +- Daily note ({{today}}): | +- Semantic search: "> | +- Glob ({{tasks_dir}}/*{keyword}*.md): | + +Suggested task name: +``` - **Jira 404**: show issue id + suggestion to check the Jira project; continue without Jira data - **Daily note missing**: report and continue -- **Task not found in any source**: AskUserQuestion → create or stop with manual search tips +- **Task not found in any source**: emit the `not_found:` verdict (see Phase 1 and ``) and STOP — the calling slash command (`vault-cli:work-on-task` Phase 4) handles the consent gate via `AskUserQuestion` before invoking `Skill: vault-cli:create-task`. The agent must not ask or create. - **MCP tool absent**: silent skip — never error on absent integration - **Guide search returns nothing**: "ℹ️ No operational guides found" @@ -266,9 +282,9 @@ Ready to work on this task. 1. Task details from at least one source 2. Jira tasks: auto-assigned + transitioned (when JIRA_MCP_AVAILABLE) — **and verified by re-fetch in Phase 8** -3. Obsidian status set to in_progress (or asked to create local file) +3. Obsidian status set to in_progress (or `not_found:` verdict emitted if no local task file exists — slash command Phase 4 handles creation) 4. Tracked on daily note (or graceful skip) -5. Code tasks: `/coding:check-guides` ran + Development Guide presented +5. Code tasks: `Task(subagent_type='coding:pre-implementation-assistant', ...)` dispatched + Development Guide presented 6. Guides searched (semantic or fallback) — **FAIL if Phase 6 skipped; at least one `search_related` call required when MCP available** 7. Phase 8 verification ran for Jira tasks; report includes verification line 8. Report ends with "Ready to work on this task." — NEVER emitted while Jira state is stale diff --git a/commands/work-on-task.md b/commands/work-on-task.md index 8a7bb17..edb3db7 100644 --- a/commands/work-on-task.md +++ b/commands/work-on-task.md @@ -1,7 +1,7 @@ --- description: Find task details, transition Jira, set status, track on daily note, discover guides — delegates to work-on-task-assistant argument-hint: -allowed-tools: Task +allowed-tools: [Task, AskUserQuestion, Skill] --- Find task details and relevant operational guides before starting work. Delegates to the `vault-cli:work-on-task-assistant` agent (which is the heavy lifter). @@ -39,6 +39,37 @@ The assistant handles all the work, detecting available integrations at runtime: Output ends with `Ready to work on this task.` +## Phase 4 — Handle not_found + +The agent (dispatched in `## Process` step 2) emits a structured `not_found` verdict from its own Phase 1 (`Find task`) when the requested task cannot be found in any source. This phase parses that verdict and asks the user before any file is created. + +1. **Parse the agent's report** for the `not_found:` marker AND capture the verdict body into variables. The agent's `` defines two separate fenced markdown blocks — one for the `found` case (ends with `Ready to work on this task.`) and one for the `not_found:` case (literal `not_found:` header on its own line). Look for the `not_found:` block specifically; if the report ends with `Ready to work on this task.` and contains no `not_found:` block, Phase 4 is a no-op and you are done. When the `not_found:` block IS present, match on the `not_found:` token, then extract: + - `SEARCHED_BLOCK` — the bullet list under the `Searched:` line (verbatim, line-by-line, until the next blank line or `Suggested task name:` line) + - `SUGGESTED_NAME` — the value after `Suggested task name:` (verbatim, trimmed) +2. **Use `SUGGESTED_NAME` as the seed.** (If the input was a Jira ID and the Jira lookup returned a summary, the agent supplied that summary; otherwise the agent supplied the input string verbatim. Either way, `SUGGESTED_NAME` is what you pass on.) +3. **Ask the user via `AskUserQuestion`** with the `vault-cli` main-session UX channel: + - `header`: `Create new task?` + - `question`: `Create new Obsidian task ""?` (substitute the captured value) + - `options`: two entries — `Yes, create it` (description: `Run vault-cli:create-task with "" as the seed title, then re-invoke work-on-task-assistant`) and `No, stop here` (description: `Print manual search tips and stop — no task is created`) +4. **On `Yes, create it`**: invoke `Skill: vault-cli:create-task ""` (use the same argument form as `commands/create-task.md` — pass the captured suggested name as a quoted argument). The create-task skill has its own interactive flow that asks for parent goal, priority, category, defer date, etc. — do not duplicate those asks. +5. **On create success** (create-task skill returns the new task file path or reports success): re-invoke `Task tool with subagent_type: 'vault-cli:work-on-task-assistant' prompt: 'Find details and guides for: '` — same form as the Phase 2 invocation, but with the new task title. The agent's standard Phase 2–8 prep mutations then run against the just-created task. +6. **On create failure or user cancel inside `vault-cli:create-task`** (the skill returns a non-success status, errors out, or the user aborts midway through its interactive prompts): print `❌ Task creation failed or was cancelled. No task created; no follow-up invocation.` and STOP — do NOT re-invoke `vault-cli:work-on-task-assistant`, do NOT retry the create. +7. **On `No, stop here`**: print the manual search tips and STOP. Substitute `SEARCHED_BLOCK` (captured in step 1) where indicated; resolve `{daily_dir}` from `vault-cli config list --output json` for the active vault before printing: + ``` + ❌ Task not found: "" + + Searched: + + + Manual search tips: + - Check the active vault's tasks dir (`vault-cli config list` → `tasks_dir`) + - Grep across vaults: `grep -rln "" ~/Documents/Obsidian/` + - Check today's daily note (`/YYYY-MM-DD.md`) + - If input looked like a Jira ID, confirm the issue exists in the Atlassian project + + No task was created. + ``` + ## Integration Task-first workflow: @@ -54,3 +85,4 @@ Task-first workflow: - No hardcoded Jira hostname, project key, or vault path — everything detected at runtime - Works in Personal, Brogrammers, Trading, or any future vault registered with `vault-cli config` - Each vault session loads a single Atlassian MCP under the canonical name `atlassian` (see vault-specific `mcp-*.json` configs); the agent uses `mcp__atlassian__*` regardless of which Jira instance is active +- The agent searches; the slash command asks before creating. diff --git a/prompts/completed/137-spec-016-move-create-gate-to-slash-command.md b/prompts/completed/137-spec-016-move-create-gate-to-slash-command.md new file mode 100644 index 0000000..1af8a00 --- /dev/null +++ b/prompts/completed/137-spec-016-move-create-gate-to-slash-command.md @@ -0,0 +1,289 @@ +--- +status: completed +spec: [016-work-on-task-move-create-gate-to-slash-command] +summary: Moved task-creation consent gate from work-on-task-assistant agent to work-on-task slash command — agent loses Skill/Task tools and emits structured not_found verdict; slash command parses the verdict, asks via AskUserQuestion, and routes to vault-cli:create-task on Yes +container: vault-cli-ask-gate-exec-137-spec-016-move-create-gate-to-slash-command +dark-factory-version: v0.175.0 +created: "2026-06-04T10:31:18Z" +queued: "2026-06-04T10:46:21Z" +started: "2026-06-04T10:46:23Z" +completed: "2026-06-04T10:49:56Z" +branch: dark-factory/work-on-task-move-create-gate-to-slash-command +--- + + +- `vault-cli:work-on-task-assistant` agent silently auto-created Obsidian task files when a requested task was missing, bypassing its own "ASK before creating" contract (spec 014-class consent failure) +- The agent's `tools:` frontmatter currently includes `Skill` and `Task` — capability is on, prose gate is the only thing standing between an unknown title and a materialised file +- This prompt strips `Skill` and `Task` from the agent's `tools:` — architecturally the agent CAN NO LONGER create tasks, regardless of caller phrasing +- Phase 1 "Task not found" branch in the agent is rewritten to emit a structured `not_found` verdict (searched-source evidence + suggested name) and STOP — no AskUserQuestion, no Skill call +- A new `not_found` form is added to the agent's `` section so the slash command can parse the verdict +- `commands/work-on-task.md` gets a new `## Phase 4 — Handle not_found` section that asks the user via AskUserQuestion in the main session, then on Yes invokes `Skill: vault-cli:create-task` and re-invokes the agent against the new task +- `` and `` in the agent drop the create-task references (gate moves to the slash command) +- CHANGELOG gets a `## Unreleased` entry (this is a new architectural capability, prefix `feat:`) +- No Go changes, no new tools, no MCP changes, no test rewrites — two `.md` edits plus a changelog line + + + +Spec 016 is a Single Responsibility split on task creation: the agent stops being able to create Obsidian task files (its `Skill` and `Task` tools are removed), and the slash command becomes the controller for the absence case. The agent emits a structured `not_found` verdict when no task matches; the slash command parses the verdict, asks the user via `AskUserQuestion`, and on Yes routes to the existing `vault-cli:create-task` skill before re-invoking the agent. + +This is a 1-prompt change because the two markdown edits (agent + slash command) are tightly coupled — the agent's new `not_found` verdict only has meaning if the slash command knows how to parse it, and the spec's ACs verify both files together. + + + +Read CLAUDE.md and `docs/development-patterns.md` for project conventions. The `docs/releasing-vault-cli.md` version-alignment rule is NOT in scope here — no `.claude-plugin/*.json` files change; only `agents/`, `commands/`, and `CHANGELOG.md` change. + +Read these files in full before making changes: + +**`/workspace/agents/work-on-task-assistant.md`** (the agent being modified) — note: +- Line 5: frontmatter `tools:` line currently lists `Skill` and `Task`; these must be removed. +- Lines 30–38: `` section contains the `ASK: before creating a new Obsidian task file` bullet to be removed; also contains `READ-ONLY except: status frontmatter + daily-note tracking + (via Skill) task creation` — the "(via Skill) task creation" parenthetical must also be removed. +- Lines 17–28: `` block currently does not list create-task as a mutation (it lists Jira assign/transition and Obsidian status set). Verify nothing needs to change there beyond what the spec AC requires; the spec AC says `` no longer mentions task creation — if there is no mention, this AC is automatically satisfied. +- Lines 92–93: Phase 1 "Task not found" branch (the `AskUserQuestion → "Create new task?" — Yes invokes Skill: vault-cli:create-task; No shows manual search tips and STOPS` line) — this is the line to be replaced with the new `not_found` verdict behaviour. +- Lines 205–256: `` section is a fenced ```markdown``` block with the existing `found` form. The new `not_found` form will be a separate fenced block (matching the existing fenced-block style) added AFTER the existing one. + +**`/workspace/commands/work-on-task.md`** (the slash command being modified) — note: +- Lines 17–31: `## Process` section currently invokes the agent via `Task` and reports "Done." A new `## Phase 4 — Handle not_found` section must be added AFTER this entire `## Process` section. +- Lines 52–56: `## Notes` section — the one-sentence explanation of the SRP split ("The agent searches; the slash command asks before creating.") is appended here. + +**`/workspace/commands/create-task.md`** (the existing interactive create flow that the new Phase 4 routes to) — note: +- This is the command the slash command invokes via `Skill: vault-cli:create-task`. It already has an interactive flow that asks the user for title, parent goal, priority, category, defer date, etc. Phase 4 only needs to provide the seed title — the create-task skill handles the rest. + +**`/workspace/agents/task-creator.md`** (the agent behind `vault-cli:create-task`) — read the first 60 lines to understand the interactive flow and the filename conventions (Title Case, optional Jira-key prefix). + +**Coding plugin** (in-container paths — the YOLO container mounts at `/home/node/.claude/plugins/marketplaces/coding/docs/`): +- `/home/node/.claude/plugins/marketplaces/coding/docs/changelog-guide.md` — `feat:` prefix for new architectural capability, `## Unreleased` immediately above the highest `## vX.Y.Z` heading (currently `## v0.68.1`). + +**Spec verified before writing this prompt** — the relevant spec is `/workspace/specs/in-progress/016-work-on-task-move-create-gate-to-slash-command.md` (read in full). The spec's Open Questions section defers the exact `not_found` verdict surface form to the prompt — fenced ```markdown``` block (matching the existing `` style) is chosen here. + + + + +### File 1: `/workspace/agents/work-on-task-assistant.md` + +1. **Strip `Skill` and `Task` from the `tools:` frontmatter line (line 5).** The line currently is: + ``` + tools: Read, Glob, Bash, Edit, AskUserQuestion, Task, Skill, mcp__semantic-search__search_related, mcp__atlassian__getAccessibleAtlassianResources, mcp__atlassian__atlassianUserInfo, mcp__atlassian__getJiraIssue, mcp__atlassian__editJiraIssue, mcp__atlassian__getTransitionsForJiraIssue, mcp__atlassian__transitionJiraIssue, mcp__atlassian__lookupJiraAccountId + ``` + After edit, the `tools:` value (and any wrap continuations if the line is broken) must contain NEITHER `Skill` NOR `Task`. The other tools (`Read`, `Glob`, `Bash`, `Edit`, `AskUserQuestion`, all `mcp__semantic-search__*` and `mcp__atlassian__*` entries) stay. + - Verify with: `grep -nE '^tools:' agents/work-on-task-assistant.md` — the matched line + any wrap continuations must contain neither `Skill` nor `Task` as a whole-token match. Note that `mcp__atlassian__*` contains the substring `Task` (`...atlassian__getJiraIssue...` etc. do NOT, but verify by eye). + +2. **Rewrite Phase 1 "Task not found" branch (lines 92–93).** The current text is: + ``` + **Task not found**: + - AskUserQuestion → "Create new task?" — Yes invokes `Skill: vault-cli:create-task`; No shows manual search tips and STOPS + ``` + Replace with: + ``` + **Task not found**: + - Emit a structured `not_found` verdict in the report with the searched-source evidence (Jira: hit/miss/skipped, daily-note: hit/miss, semantic-search: top-3 misses with scores, Glob: paths tried) and a `Suggested task name:` line derived from the input argument (or, if input is a Jira ID, from the Jira issue summary returned by the Jira lookup; fall back to the raw input string if neither is available). + - STOP — do NOT propose a fix, do NOT call AskUserQuestion, do NOT invoke `Skill: vault-cli:create-task`. + - The `not_found` verdict is parsed by the calling slash command (`vault-cli:work-on-task`) which owns the create-gate. + ``` + - The replacement text must contain the literal string `not_found`. + - The replacement text must NOT contain `AskUserQuestion` (the agent no longer owns the consent gate). + +3. **Add a `not_found` form to `` (after line 256, before the closing of the section).** The existing `` is a fenced ```markdown``` block. Append a second fenced ```markdown``` block (same fence style) labelled `not_found` with the searched-source evidence and a `Suggested task name:` line. Use this exact form: + ```` + ```markdown + not_found: + 📋 Task: [()] + Status: not_found + + Searched: + - Jira: | | + - Daily note ({{today}}): | + - Semantic search: "> | + - Glob ({{tasks_dir}}/*{keyword}*.md): | + + Suggested task name: + ``` + ```` + - The string `not_found:` must appear in the new block. + - The string `Suggested task name:` must appear in the new block. + - The string `Searched:` must appear in the new block. + +4. **Remove the `ASK: before creating a new Obsidian task file` bullet from `` (line 33).** Verify with: `grep -n 'ASK: before creating' agents/work-on-task-assistant.md` — must return 0 lines after edit. The other ASK rules (Jira/Obsidian status auto-mutations are NOT asking rules — they are AUTO rules, leave them) stay. + +5. **Remove the `(via Skill) task creation` parenthetical from the `READ-ONLY except:` bullet in `` (line 35).** The current text is: + ``` + - READ-ONLY except: status frontmatter + daily-note tracking + (via Skill) task creation + ``` + After edit: + ``` + - READ-ONLY except: status frontmatter + daily-note tracking + ``` + +6. **Verify `` (lines 17–28) does NOT mention `Skill: vault-cli:create-task` or any task-creation mutation.** If the section already doesn't mention it (verify by reading), this requirement is automatically satisfied — no edit needed. The current text lists only Jira assign/transition and Obsidian status set as mandatory mutations, so no edit should be required. Verify with: `grep -n 'Skill: vault-cli:create-task' agents/work-on-task-assistant.md` — must return 0 lines after edit (this passes if no edit is made). + +### File 2: `/workspace/commands/work-on-task.md` + +6b. **Update the `allowed-tools` frontmatter on line 4.** Current value is `allowed-tools: Task` (scalar form). Change to list form: `allowed-tools: [Task, AskUserQuestion, Skill]` — matching `commands/create-task.md` line 4's list style. The new Phase 4 invokes `AskUserQuestion` (consent) and `Skill: vault-cli:create-task` (route to create flow); the existing Phase 2 invokes `Task` (sub-agent dispatch). All three are required, or Phase 4 fails at runtime — every static AC would pass but the runtime repro would fail. + - Verify with: `grep -nE '^allowed-tools' commands/work-on-task.md` — the value must include `Task`, `AskUserQuestion`, AND `Skill` (any order, list form). + +7. **Add a new `## Phase 4 — Handle not_found` section AFTER the existing `## Process` section (after line 31, before the `## Integration` section on line 42).** The new section must be a level-2 heading (`##`) with the exact title `Phase 4 — Handle not_found`. Use the em-dash character `—` (U+2014), not a hyphen. Body of the section, as a numbered list: + + ```markdown + ## Phase 4 — Handle not_found + + The agent (Phase 2 of this command) emits a structured `not_found` verdict when the requested task cannot be found in any source. This phase parses that verdict and asks the user before any file is created. + + 1. **Parse the agent's report** for the `not_found:` marker. The agent's `` produces a fenced markdown block with the literal `not_found:` header on its own line — match on that token. + 2. **Derive a suggested task name.** The agent's verdict includes a `Suggested task name:` line — use that value verbatim as the seed for the create step. (If the input was a Jira ID and the Jira lookup returned a summary, the agent supplies that summary; otherwise the agent supplies the input string verbatim.) + 3. **Ask the user via `AskUserQuestion`** with the `vault-cli` main-session UX channel: + - `header`: `Create new task?` + - `question`: `Create new Obsidian task ""?` + - `options`: two entries — `Yes, create it` (description: `Run vault-cli:create-task with "" as the seed title, then re-invoke work-on-task-assistant`) and `No, stop here` (description: `Print manual search tips and stop — no task is created`) + 4. **On `Yes, create it`**: invoke `Skill: vault-cli:create-task ""` (use the same argument form as `commands/create-task.md` — pass the suggested name as a quoted argument). The create-task skill has its own interactive flow that asks for parent goal, priority, category, defer date, etc. — do not duplicate those asks. + 5. **On create success** (create-task skill returns the new task file path or reports success): re-invoke `Task tool with subagent_type: 'vault-cli:work-on-task-assistant' prompt: 'Find details and guides for: '` — same form as the Phase 2 invocation, but with the new task title. The agent's standard Phase 2–8 prep mutations then run against the just-created task. + 6. **On `No, stop here`**: print the manual search tips and STOP. The manual search tips are: + ``` + ❌ Task not found: "" + + Searched: + - + - + + Manual search tips: + - Check the active vault's tasks dir (`vault-cli config list` → `tasks_dir`) + - Grep across vaults: `grep -rln "" ~/Documents/Obsidian/` + - Check today's daily note (`{daily_dir}/YYYY-MM-DD.md`) + - If input looked like a Jira ID, confirm the issue exists in the Atlassian project + + No task was created. + ``` + ``` + - Verify with: `grep -n 'Phase 4 — Handle not_found\|Phase 4 - Handle not_found' commands/work-on-task.md` — must return ≥1 line. + - The body must contain the literal string `AskUserQuestion`, `Skill: vault-cli:create-task`, and `not_found`. + - Use the em-dash `—` (U+2014) in the heading. + +8. **Append a one-sentence `## Notes` entry explaining the architectural split.** The `## Notes` section starts at line 52. Append a new bullet (or new paragraph — match the style of the existing `## Notes` section, which uses `- ` bullets) with this exact sentence: + ``` + - The agent searches; the slash command asks before creating. + ``` + - Verify with: `grep -n 'The agent searches; the slash command asks before creating' commands/work-on-task.md` — must return ≥1 line. + +### File 3: `/workspace/CHANGELOG.md` + +9. **Add a `## Unreleased` section above the existing `## v0.68.1` heading.** Insert a new `## Unreleased` heading + bullets block IMMEDIATELY ABOVE `## v0.68.1`. The current top of the file (lines 1–9) is the frozen preamble; do NOT modify it. After the bullets, the file structure should read: + ```markdown + # Changelog + ...frozen preamble (lines 1–9)... + + ## Unreleased + + - feat: Move task-creation consent gate from `vault-cli:work-on-task-assistant` to `vault-cli:work-on-task` slash command — agent loses `Skill` and `Task` tools, emits a structured `not_found` verdict when the requested task is missing; slash command parses the verdict, asks the user via `AskUserQuestion`, and on `Yes` routes to `Skill: vault-cli:create-task` before re-invoking the agent + - feat: Add `not_found` form to `vault-cli:work-on-task-assistant` `` so the slash command can parse the absence case (searched-source evidence + suggested task name) + + ## v0.68.1 + ... + ``` + - Verify with: `grep -nE '^## Unreleased' CHANGELOG.md` — must return ≥1 line, and that line must be ABOVE the `## v0.68.1` heading. + - Verify with: `grep -nE 'work-on-task|ask gate|consent gate|SRP|not_found' CHANGELOG.md` — must return ≥1 line ABOVE the next `## v` header. + - Use the `feat:` prefix (this is a new architectural capability, minor bump per the changelog guide). + - The frozen preamble (everything from `# Changelog` through the MAJOR/MINOR/PATCH bullet list) must NOT be modified, moved, or have anything inserted above it. + +### Verification gates + +10. **Run the static checks listed in `## Verification` of the spec.** Each must pass: + - `grep -nE '^tools:' agents/work-on-task-assistant.md` — the matched line + wrap continuations must contain neither `Skill` nor `Task`. + - `grep -n 'not_found' agents/work-on-task-assistant.md` — must return ≥1 line in the new Phase 1 text and the new `` form. + - `grep -n 'Phase 4' commands/work-on-task.md` — must return ≥1 line. + - `git diff --name-only origin/master..HEAD -- commands/ agents/` — must return exactly two paths: `commands/work-on-task.md` and `agents/work-on-task-assistant.md`. (Run from the repo root. `origin/master` may not exist locally — if so, use `git diff --name-only -- commands/ agents/` against the current branch to verify only those two files changed.) + - `git diff --name-only origin/master..HEAD -- '*.go'` — must return 0 lines. (If no Go files were touched, this is automatic.) + +11. **No other `commands/*.md` or `agents/*.md` files are modified.** Verify by `git diff --name-only` (against the prior commit on this branch) — only the two files in step 7 of the spec must be in the diff. + +12. **`make precommit` must exit 0.** The change touches only markdown, but `make precommit` runs the full pipeline (format, generate, test, check, addlicense). The `addlicense` target may flag the new `## Unreleased` content or the markdown edits — if it does, address per the existing addlicense pattern (the existing `CHANGELOG.md` and `.md` files in `commands/` and `agents/` are already addlicense-clean, so re-running it should be a no-op for the edits). If `make precommit` fails for an unrelated reason (preexisting test flake, vulnerability scanner noise), report it in the completion report and continue per the YOLO rules — do not rationalize a non-zero exit as success. + +13. **Do NOT bump `.claude-plugin/plugin.json` or `.claude-plugin/marketplace.json`.** The `docs/releasing-vault-cli.md` version-alignment rule is release-time only, not precommit. The plugin JSONs may lag the binary CHANGELOG entry on the feature branch; the operator bumps them at release time. Do not introduce a plugin version bump from a markdown-only change. + + + + +- Do NOT commit — dark-factory handles git. +- Do NOT bump `.claude-plugin/plugin.json` or `.claude-plugin/marketplace.json` — version-alignment is release-time only; plugin JSON bumps belong at release time, not on every feature branch. +- Existing tests must continue to pass (no Go code changed, so this is automatic unless the markdown edits trigger a `go test` failure, which they should not). +- No new MCP, no new tool, no new dark-factory primitive — the change is two `.md` edits plus a CHANGELOG line. +- The agent's Phases 2–8 (Jira mutations, Obsidian status set, daily-note tracking, code-task guide discovery, runbook/guide search, mutation verification) MUST NOT have their text changed. The spec lists these as "correct mutations the agent owns" and explicitly forbids text changes. The `tools:` removal is a frontmatter-only change that does NOT touch the Phase 2–8 text bodies. +- The slash command's happy path (task found, Phase 2 returns a report ending with `Ready to work on this task.`) MUST NOT change. The new `## Phase 4 — Handle not_found` section only fires when the agent's report contains the `not_found:` verdict; otherwise the existing "Done." step stands. +- `vault-cli:create-task` skill (the `commands/create-task.md` flow and `agents/task-creator.md` agent) MUST NOT change. The new Phase 4 routes to it as-is; it already has the interactive flow that asks for parent goal, priority, category, defer date, etc. +- Use the em-dash `—` (U+2014) in the section heading `## Phase 4 — Handle not_found`, not a hyphen `-`. +- The new `not_found` form in the agent's `` is a fenced ```markdown``` block (matching the existing `` style), not loose YAML or a bulleted list. The spec defers the exact surface form to the prompt; fenced ```markdown``` block is chosen here. +- The frozen CHANGELOG preamble (`# Changelog` → ... → MAJOR/MINOR/PATCH bullets) MUST NOT be modified, moved, or have anything inserted above or inside it. Insert `## Unreleased` immediately AFTER the last preamble line and BEFORE the existing `## v0.68.1` heading. +- CHANGELOG entry uses the `feat:` prefix (this is a new architectural capability → minor bump per the changelog guide). +- The change is fully reversible — restoring `Skill` to `tools:` is a one-line revert if the SRP split turns out to be the wrong design. + + + +Run `make precommit` — must exit 0. + +Targeted greps and checks (each MUST hold after edits): + +```bash +# 1. tools: line excludes Skill and Task +grep -nE '^tools:' agents/work-on-task-assistant.md +# The matched line + any wrap continuations must contain neither Skill nor Task +# Verify with: grep -c 'Skill' agents/work-on-task-assistant.md → 0 (or only in comments/code blocks, not in tools:) +# Verify with: grep -c '\bTask\b' agents/work-on-task-assistant.md → 0 occurrences in the tools: line +# (note: \bTask\b matches the whole word "Task" but not "task" — Task may still appear in / as the noun "task", which is fine) + +# 2. ASK: before creating removed from +grep -n 'ASK: before creating' agents/work-on-task-assistant.md +# Must return 0 lines + +# 3. Skill: vault-cli:create-task removed from agent +grep -n 'Skill: vault-cli:create-task' agents/work-on-task-assistant.md +# Must return 0 lines + +# 4. not_found verdict present in agent +grep -n 'not_found' agents/work-on-task-assistant.md +# Must return ≥1 line in Phase 1 text AND ≥1 line in + +# 5. Phase 4 added to slash command +grep -n 'Phase 4 — Handle not_found\|Phase 4 - Handle not_found' commands/work-on-task.md +# Must return ≥1 line. Use the em-dash form first; the hyphen form is a fallback for editors that normalize. + +# 6. Notes sentence appended +grep -n 'The agent searches; the slash command asks before creating' commands/work-on-task.md +# Must return ≥1 line + +# 7. Only two files modified +git diff --name-only -- commands/ agents/ +# Must return exactly: agents/work-on-task-assistant.md and commands/work-on-task.md (in any order) + +# 8. No Go files modified +git diff --name-only -- '*.go' +# Must return 0 lines + +# 9. CHANGELOG Unreleased section +grep -nE '^## Unreleased' CHANGELOG.md +# Must return ≥1 line ABOVE the '## v0.68.1' heading +grep -nE 'work-on-task|ask gate|consent gate|SRP|not_found' CHANGELOG.md +# Must return ≥1 line in the section above the next '## v' header + +# 10. make precommit +make precommit +# Must exit 0 +``` + +Runtime repro (manual, at PR verify time by the human reviewer — NOT in the daemon container): + +**Not-found path:** +```bash +# In a Claude Code session running this worktree's vault-cli plugin +/vault-cli:work-on-task "Definitely Not A Real Vault Task XYZ-impossible-string" +# Expect: agent's transcript shows the new Phase 1 not_found verdict block; +# slash command then shows an AskUserQuestion prompt to the user with the suggested name; +# NO task file is materialised in the vault before the user answers. +# Verifier MUST observe: (a) the not_found verdict block in the agent's transcript; +# (b) the AskUserQuestion prompt in the slash command's transcript; +# (c) no `*.md` file appears in 24 Tasks/ (or whatever tasks_dir resolves to) before the user answers. +``` + +**Found path (regression check):** +```bash +/vault-cli:work-on-task "Try Hermes Agent harness" +# Expect: standard Phase 2–8 flow runs unchanged; report ends with +# "Ready to work on this task."; task's daily-note tracking + status: in_progress are correct. +``` + diff --git a/specs/in-progress/016-work-on-task-move-create-gate-to-slash-command.md b/specs/in-progress/016-work-on-task-move-create-gate-to-slash-command.md new file mode 100644 index 0000000..20252c3 --- /dev/null +++ b/specs/in-progress/016-work-on-task-move-create-gate-to-slash-command.md @@ -0,0 +1,159 @@ +--- +status: verifying +approved: "2026-06-04T10:24:49Z" +generating: "2026-06-04T10:26:38Z" +prompted: "2026-06-04T10:41:45Z" +verifying: "2026-06-04T10:49:56Z" +branch: dark-factory/work-on-task-move-create-gate-to-slash-command +--- + +## Summary + +- `vault-cli:work-on-task-assistant` agent silently creates Obsidian task files when the requested task is missing, despite its own contract (`: ASK before creating`, Phase 1 "Task not found: AskUserQuestion → ...") requiring an explicit user "Yes" first. +- Root cause is architectural: the agent owns BOTH the search and the create-on-miss decision, with `Skill` in its `tools:` frontmatter — the consent gate is enforced only by prompt text. A caller phrasing like "offer to create if missing" (from the controlling slash command or a parent agent) is enough to bypass the text-only gate. +- Fix is a Single Responsibility split on **task creation only** — the agent keeps its existing responsibilities (search, Jira assign + transition, Obsidian `status: in_progress`, daily-note tracking, guide discovery) but stops being able to create new task files. It emits a structured `not_found` verdict when no task matches. +- The slash command (`commands/work-on-task.md`) becomes the controller for the absence case: on `not_found`, it asks the user via AskUserQuestion in the main session, on Yes invokes `Skill: vault-cli:create-task`, on success re-invokes the agent against the newly created task so the standard prep mutations run. +- The agent loses the `Skill` and `Task` tools from its frontmatter — architecturally, it CAN NO LONGER create tasks. The consent gate is enforced by capability removal, not by prompt discipline. The other tools (`Read`, `Glob`, `Bash`, `Edit`, `AskUserQuestion`, MCP search/atlassian) stay — the existing happy-path mutations still need them. + +## Problem + +A real run this session: a user invoked `/vault-cli:work-on-task "Semantic search with Python 3.13"`. The task did not exist in the vault. The slash command delegated to `vault-cli:work-on-task-assistant`. The agent searched, found nothing, then silently invoked `Skill: vault-cli:create-task` and reported `Task created and tracked.` — without ever calling AskUserQuestion. The user only discovered the task had been auto-created when checking the output report. + +The agent's own definition documents the expected behavior: + +- `agents/work-on-task-assistant.md` ``: `ASK: before creating a new Obsidian task file` +- `agents/work-on-task-assistant.md` Phase 1, "Task not found": `AskUserQuestion → "Create new task?" — Yes invokes Skill: vault-cli:create-task; No shows manual search tips and STOPS` + +The gate exists as prose. The agent (running on Sonnet) skipped it. Phrasing in the calling slash command's prompt to the agent ("search the vault and offer to create it if missing" from the work-on-task slash command's delegate prompt template) was sufficient to override the gate — the model read "offer to create" as license to act, not as an obligation to ask first. + +This is the second class of consent failure in vault-cli (the first being spec 014's `claude_session.go` silent-success: an agent reports completion when in fact a precondition was unmet). The shape is identical: a contract enforced only by docstrings/prose is fragile against caller-side phrasing pressure. + +## Goal + +`vault-cli:work-on-task-assistant` cannot create Obsidian task files — its `tools:` frontmatter excludes `Skill` and `Task`. Its existing responsibilities are unchanged: search across Jira/Obsidian/daily-note/semantic, assign the Jira issue to the current user and transition it to "In Progress", set the Obsidian task's `status: in_progress`, track the task on today's daily-note as `[/]`, surface relevant guides/runbooks. When the agent cannot find the requested task in any source, it emits a structured `not_found` verdict in its report and stops without proposing a fix. + +`commands/work-on-task.md` slash command handles the `not_found` case in the main Claude session: shows the user what was searched (Jira, daily note, free-text/semantic, file globs), proposes a task name derived from the input argument, asks via AskUserQuestion (single yes/no), and on `Yes` invokes `Skill: vault-cli:create-task` with the suggested name. On `No`, the slash command prints manual search tips and stops. + +After the new task is created, the slash command re-invokes `vault-cli:work-on-task-assistant` with the new task title so the standard prep mutations (Jira sync, status set, daily-note tracking, guide discovery) run against the just-created task. + +## Non-goals + +- Touching any other vault-cli agent's tool list — only `work-on-task-assistant.md` loses `Skill` and `Task`. Other agents that legitimately need creation (`vault-cli:create-task` itself, `vault-cli:task-manager-agent`) keep their tools. +- Replacing AskUserQuestion with a different consent mechanism (CLI prompt, env-var override) — AskUserQuestion is the documented main-session UX channel in this codebase; preserve it. +- Adding any new slash command — `vault-cli:create-task` already exists with an interactive create flow; the new behavior just routes to it. +- Auto-deriving a parent goal / priority / category for the new task — `vault-cli:create-task` handles those interactively. The slash command only suggests a *name*; the create-task skill asks the rest. +- Migrating in-flight callers of the agent — there are no other slash commands or agents in vault-cli that invoke `vault-cli:work-on-task-assistant`; only `commands/work-on-task.md` does. Confirmed via `grep -r "work-on-task-assistant" commands/ agents/`. +- Changing the verdict format the agent emits when a task IS found — the existing `output_format` for found tasks stays as-is. Only the `not_found` case gets a new structured form. +- Implementing a regression test that exercises a real Claude sub-agent invocation — agent behavior is not unit-testable. Coverage is via spec verification (scenario walkthrough) at PR time, not Go tests. + +## Do-Nothing Option + +Leaving the bug costs user trust in the consent gate. Every `/vault-cli:work-on-task` call against an unknown title silently materialises a task — possibly with a name the user would have phrased differently, possibly under a wrong parent goal, definitely without the user's explicit Yes. The cost per occurrence is small (correcting or deleting the auto-created task takes < 1 min), but the cumulative trust cost is structural: a "I'll ask before changing the vault" contract that the system silently breaks erodes the user's willingness to delegate. + +Hardening the prompt text (stronger `MUST ASK` language, repeated in three places) is the obvious cheaper fix. It does not work: spec 014 showed that prose-only contracts fail under caller-side phrasing pressure, and the consent gate in this agent already has the strongest possible prose ("MANDATORY mutations" in ``, ASK in ``, Phase 1 explicit AskUserQuestion call). The model still skipped it. + +Capability removal (`Skill` out of `tools:`) is the only fix that scales: the agent literally cannot invoke `Skill: vault-cli:create-task` because the tool isn't available in its session. No future phrasing change in any caller can bypass that. + +Cost of fix is low: two markdown files (`agents/work-on-task-assistant.md`, `commands/work-on-task.md`). No Go code changes, no test rewrites, no migration. The change is fully reversible — if the SRP split turns out to be the wrong design, restoring `Skill` to `tools:` is a one-line revert. + +## Reproduction + +vault-cli HEAD: master at time of filing (493eb1f, "bump deps and go 1.26.4"). + +The bug fires whenever `/vault-cli:work-on-task ` runs against a vault that does not contain that title. Concrete trace from this session: + +``` +/vault-cli:work-on-task "Semantic search with Python 3.13" + → slash command delegates to vault-cli:work-on-task-assistant with prompt + "Find details and guides for: Semantic search with Python 3.13 ... + search the vault and offer to create it if missing ..." + → agent runs Phase 1: Jira lookup (n/a), daily-note grep (miss), semantic search (no hit), Glob (no file) + → agent SKIPS the documented AskUserQuestion call + → agent invokes Skill: vault-cli:create-task with derived name "Relax Python Version Floor in semantic-search to 3.13" + → task file created at 24 Tasks/Relax Python Version Floor in semantic-search to 3.13.md + → agent emits report "Task created and tracked." +``` + +The user only saw the consent failure after reading the report and asking "did work on task find the task ? guess we have non yet?" — at which point the task was already on disk. + +## Expected vs Actual + +| | Expected | Actual | +|---|---|---| +| Agent tools when task missing | Cannot invoke `Skill: vault-cli:create-task` (tool not in `tools:`) | Invokes it directly | +| Consent gate enforcement | Architectural (capability removal) | Prose-only (`` + `` + Phase 1 text) | +| Agent verdict on miss | Structured `not_found` form with what-was-searched evidence | "Task created and tracked." | +| Who runs AskUserQuestion | Slash command (main session, user-facing) | Sub-agent (model decides whether to call it) | +| New-task naming | User confirms via `vault-cli:create-task` interactive flow | Agent auto-derives from input | +| Re-discovery after create | Slash command re-invokes agent against new task | Agent assumes happy path after silent create | + +## Why this is a bug + +The contract documented in `agents/work-on-task-assistant.md` says the agent asks before creating. The agent does not ask. The user's consent is bypassed. That's the bug. + +The deeper bug is the design that makes the contract violable. The agent holds both the search responsibility (legitimate) and the creation responsibility (illegitimate — should belong to the controller). The Skill tool that enables the creation lives in the agent's frontmatter. The consent gate is the only thing standing between an unknown-task input and a materialised file, and it is implemented as prose. A model running the agent has full capability to skip the prose-gate any time a caller's phrasing nudges it toward action. + +Fixing only the prose (e.g., promoting the constraint to a louder `🚨 BLOCKING:` block) addresses the symptom and not the cause. The cause is that the agent CAN create at all. + +## Constraints + +- `commands/work-on-task.md` happy path (task found) MUST NOT change — current behaviour ("delegates to agent, reports `Ready to work on this task.`") is correct for the found case. +- `agents/work-on-task-assistant.md` Phases 2–8 (Jira mutations, Obsidian status set, daily-note tracking, code-task guide discovery, runbook/guide search, mutation verification) MUST NOT change — those are correct mutations the agent owns. +- `vault-cli:create-task` skill MUST NOT change — its interactive create flow (asks title, parent goal, priority, category, defer date, …) is what we want to route to. +- No new MCP, no new tool, no new dark-factory primitive — the change is two `.md` edits. +- The slash command must continue to work for callers that pass a Jira-style ID (`[A-Z]+-\d+`). On `not_found` for a Jira ID, propose the task name derived from the Jira summary if `JIRA_MCP_AVAILABLE`, else fall back to the raw ID. The agent's existing Jira lookup output supplies the summary. + +## Failure Modes + +| Trigger | Detection | Expected behavior | Recovery | +|---|---|---|---| +| Agent run against unknown title | Agent Phase 1 search returns 0 hits across all sources | Agent emits `not_found` verdict in report; agent stops without further mutation | Slash command, on parse, asks user via AskUserQuestion; on Yes invokes `vault-cli:create-task`; on No prints manual search tips | +| User answers No to "Create new task?" | AskUserQuestion result | Slash command prints manual search tips (existing copy from agent Phase 1, moved up to the command); no task is created | Done | +| User answers Yes | AskUserQuestion result | Slash command invokes `Skill: vault-cli:create-task` with suggested name; on success re-invokes `vault-cli:work-on-task-assistant` with the new task title | Standard work-on-task flow runs against new task | +| Agent retains stale `Skill` capability (regression) | `grep "^- Skill" agents/work-on-task-assistant.md` returns ≥1 line in frontmatter | Spec verification fails; revert or correct the frontmatter | Manual fix | +| Caller is another agent (not the slash command) that does not know about the new verdict | Caller parses old `output_format` only | Caller sees an unfamiliar verdict block, no task is created, agent stops cleanly | Update caller separately — non-goal for this spec | + +## Acceptance Criteria + +- [ ] `agents/work-on-task-assistant.md` `tools:` frontmatter does NOT include `Skill` — evidence: `grep -nE '^tools:' agents/work-on-task-assistant.md` and the value on that line + any wrap continuations contain no `Skill`. The remaining tools (`Read`, `Glob`, `Bash`, `Edit`, `AskUserQuestion`, `Task`, `mcp__semantic-search__search_related`, `mcp__atlassian__*`) stay. **Amendment (2026-06-04, during PR #8 bot review at HEAD `e27f49e`)**: the original AC required removing both `Skill` AND `Task`. Bot review correctly flagged that Phase 5 (`coding:check-guides` lookup) and Phase 7 (`vault-cli:task-manager-agent` subagent dispatch) need `Task`. The spec's intent was creation-only enforcement, not removal of all dispatch primitives — `Task` is a generic dispatch tool that does not grant create-task capability on its own. `Skill` removal is the load-bearing architectural block (it was the path to `Skill: vault-cli:create-task`); `Task` is retained with a `` entry restricting its dispatch to documented subagent types (`coding:pre-implementation-assistant`, `vault-cli:task-manager-agent`). +- [ ] `agents/work-on-task-assistant.md` Phase 1 "Task not found" branch is rewritten: instead of `AskUserQuestion → "Create new task?"`, it now emits a structured `not_found` verdict with the searched-source evidence (Jira: yes/no/skipped, daily-note: hit/miss, semantic-search: top-3 misses, Glob: paths tried) and STOPS — evidence: the new Phase 1 text contains no `AskUserQuestion` call and contains the literal string `not_found`. +- [ ] `agents/work-on-task-assistant.md` `` adds a `not_found` form (alongside the existing `found` form) — evidence: the section contains both `found:` and `not_found:` headers (or equivalent structured markers) with the not-found form including a `Searched:` evidence list and a `Suggested task name:` line. +- [ ] `agents/work-on-task-assistant.md` `` removes the `ASK: before creating a new Obsidian task file` line — evidence: `grep -n 'ASK: before creating' agents/work-on-task-assistant.md` returns 0 lines. The remaining ASK rules (Jira/Obsidian status) stay. +- [ ] `agents/work-on-task-assistant.md` `` no longer mentions task creation as a mutation — evidence: the `` block lists only the Jira and Obsidian status mutations; no mention of `Skill: vault-cli:create-task` anywhere in the section. +- [ ] `commands/work-on-task.md` adds a `## Phase 4 — Handle not_found` section AFTER the existing `## Process` invocation of the agent — evidence: `grep -n 'Phase 4 — Handle not_found\|Phase 4 - Handle not_found' commands/work-on-task.md` returns ≥1 line. +- [ ] The new Phase 4 in `commands/work-on-task.md` describes: (a) parse the agent's report for the `not_found` form; (b) derive a suggested task name from the argument or Jira summary; (c) call `AskUserQuestion` with a single Yes/No question naming the suggested title; (d) on Yes, invoke `Skill: vault-cli:create-task` with the suggested name as the seed; (e) on success, re-invoke `vault-cli:work-on-task-assistant` with the new title; (f) on No, print manual search tips and stop — evidence: each of (a)–(f) appears as a distinct bullet or numbered step in Phase 4. +- [ ] `commands/work-on-task.md` `## Notes` (or equivalent) explains the architectural split — one sentence: "The agent searches; the slash command asks before creating." — evidence: that sentence (or close paraphrase containing both "agent" and "slash command" and "before creating") appears in the file. +- [ ] No other `commands/*.md` or `agents/*.md` files are modified — evidence: `git diff --name-only origin/master..HEAD -- commands/ agents/` returns exactly two paths: `commands/work-on-task.md` and `agents/work-on-task-assistant.md`. +- [ ] No Go files are modified — evidence: `git diff --name-only origin/master..HEAD -- '*.go'` returns 0 lines. +- [ ] **Runtime repro — not_found path**: in this worktree, with the post-edit agent/command, run `/vault-cli:work-on-task "Definitely Not A Real Vault Task XYZ-impossible-string"`. Evidence: the slash command produces an AskUserQuestion to the user (intercepted at audit time — the actual interactive run happens at PR verify, not in the daemon container). The not-found verdict from the agent is visible in the transcript before the AskUserQuestion fires. No task file is materialised under `~/Documents/Obsidian/Personal/24 Tasks/` before the user answers. **Verifier MUST NOT mark this AC complete based on dry-run / static-analysis / file-diff inspection alone — verifier MUST observe a real session transcript with the agent's `not_found` verdict block visible AND the slash command's AskUserQuestion prompt visible.** +- [ ] **Runtime repro — found path** (regression check): on a known-existing task, e.g. `/vault-cli:work-on-task "Try Hermes Agent harness"` against the Personal vault, the existing happy path (Phase 2–8) runs unchanged. Evidence: the report ends with `Ready to work on this task.` and the task's daily-note tracking + `status: in_progress` are correct. +- [ ] `make precommit` exits 0. +- [ ] CHANGELOG.md has a `## Unreleased` entry covering both file changes — evidence: `grep -nE '^## Unreleased' CHANGELOG.md` returns ≥1 line AND `grep -nE 'work-on-task|ask gate|consent gate|SRP' CHANGELOG.md` returns ≥1 line in the section above the next `## v` header. (vault-cli's release driver is the github-releaser-agent watcher via `.maintainer.yaml: release.autoRelease: true` — it renames `## Unreleased` → `## vX.Y.Z` post-merge on master; on the feature branch the section persists as `## Unreleased`.) + +## Verification + +```bash +cd ~/Documents/workspaces/vault-cli-ask-gate +make precommit # full check; no Go changes so should be fast +grep -nE '^tools:' agents/work-on-task-assistant.md # confirm no Skill/Task +grep -n 'not_found' agents/work-on-task-assistant.md # confirm new verdict +grep -n 'Phase 4' commands/work-on-task.md # confirm new phase +git diff --name-only origin/master..HEAD -- commands/ agents/ # exactly 2 files +git diff --name-only origin/master..HEAD -- '*.go' # 0 files +``` + +Runtime checks (manual, at PR verify time): + +```bash +# Not-found path (in main Claude Code session, this worktree's vault config): +/vault-cli:work-on-task "Definitely Not A Real Vault Task XYZ-impossible-string" +# Expect: agent emits not_found verdict; slash command asks user via AskUserQuestion; no task created until user answers Yes. + +# Found path (regression): +/vault-cli:work-on-task "Try Hermes Agent harness" +# Expect: standard Phase 2–8 flow; report ends with "Ready to work on this task." +``` + +## Open Questions + +- None on the architectural split. The remaining question is the *exact* form of the `not_found` verdict block — whether it should be loose YAML, a bulleted list, or a fenced markdown block. The prompt-generation step can pick the form; the spec only requires that `not_found` is present and includes Searched: + Suggested task name:. Leaving the surface form to the prompt is intentional — it avoids over-specifying.