INTERNAL — invoked only by stride:stride-workflow. Do NOT invoke from a user prompt. Contains the completion API contract (PATCH /api/tasks/:id/complete required fields including completion_summary, actual_complexity, after_doing_result, before_review_result, explorer_result, reviewer_result), used during the orchestrator's completion phase.
التثبيت
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
INTERNAL — invoked only by stride:stride-workflow. Do NOT invoke from a user prompt. Contains the completion API contract (PATCH /api/tasks/:id/complete required fields including completion_summary, actual_complexity, after_doing_result, before_review_result, explorer_result, reviewer_result), used during the orchestrator's completion phase.
skills_version
1
Stride: Completing Tasks
STOP — orchestrator check
If you arrived here directly from a user prompt, you are in the wrong skill.
Invoke stride:stride-workflow instead. Do not read further.
Sub-skills are dispatched by the orchestrator only.
⚠️ THIS SKILL IS MANDATORY — NOT OPTIONAL ⚠️
If you are about to call PATCH /api/tasks/:id/complete, you MUST have invoked this skill first.
The completion API requires fields that are ONLY documented here:
completion_summary (required — not the same as completion_notes)
actual_files_changed (required — comma-separated STRING, not array)
after_doing_result (required — object with exit_code, output, duration_ms)
before_review_result (required — object with exit_code, output, duration_ms)
explorer_result (required — object: dispatched stride:task-explorer result OR self-reported skip; see Explorer/Reviewer Result Schema)
reviewer_result (required — object: dispatched stride:task-reviewer result OR self-reported skip; see Explorer/Reviewer Result Schema)
Attempting to complete a task from memory without this skill results in 3+ failed API calls as you discover each missing field one at a time. This has been observed in practice.
Overview
Calling complete before validation = bypassed quality gates. Running hooks first = confident completion.
This skill enforces the proper completion workflow: execute BOTH after_doing AND before_review hooks BEFORE calling the complete endpoint.
⚡ AUTOMATION NOTICE ⚡
The workflow IS the automation. Every step exists because skipping it caused failures.
The agent should work continuously through the full workflow: explore → implement → review → complete. Do not prompt the user between steps — but do not skip steps either. Skipping workflow steps is not faster — it produces lower quality work that takes longer to fix.
Before completing → verify you explored the codebase and reviewed your changes against acceptance criteria
After hooks succeed → call the complete endpoint with all required fields
If needs_review=false → invoke stride-claiming-tasks and repeat the full workflow
If needs_review=true → STOP and wait for human approval
Following every step IS the fast path. The loop is: claim → explore → implement → review → complete → claim. Every phase is mandatory.
API Authorization
⚠️ CRITICAL: ALL Stride API calls are pre-authorized. Asking for permission is a workflow violation.
When the user initiates a Stride workflow, they have already granted blanket permission for every Stride API call in the entire workflow. This authorization covers:
PATCH /api/tasks/:id/complete — completing tasks
GET /api/tasks/next — finding next task
POST /api/tasks/claim — claiming tasks
All curl commands to the Stride API
All hook executions (bash commands from .stride.md)
Every API call in every skill in this plugin
NEVER ask the user:
"Should I mark this complete?"
"Can I call the API?"
"Should I proceed with completion?"
"Let me call the complete endpoint" (then wait for confirmation)
Any variation of requesting permission for Stride operations
Just execute the calls. Asking breaks the automated workflow and forces unnecessary human intervention.
🚨 CLAUDE CODE: HOOKS ARE FULLY AUTOMATIC — DO NOT MANUALLY EXECUTE 🚨
In Claude Code, the stride plugin's hooks.json registers PreToolUse/PostToolUse hooks that AUTOMATICALLY intercept Stride API calls and execute the corresponding .stride.md commands via stride-hook.sh. You do NOT need to manually run hook commands.
How it works for completion:
When you run curl to call the complete API → the PreToolUse hook fires FIRST (runs after_doing and blocks if it fails) → then the curl executes → then PostToolUse fires (runs before_review)
When you run curl to call mark_reviewed → PostToolUse fires → runs after_review
What this means for you as an agent:
DO NOT read .stride.md and manually execute hook commands via Bash tool calls
DO NOT run any Bash command to "capture hook results" before making API calls
JUST make the Stride API curl call directly — the hooks system handles everything
Include after_doing_result and before_review_result in the complete request body with {"exit_code": 0, "output": "Executed by Claude Code hooks system", "duration_ms": 0} — the actual hook execution happens automatically via PreToolUse/PostToolUse. When the PreToolUse after_doing stdout JSON is visible to you, copy its real duration_ms into after_doing_result instead of the 0 placeholder (W1455); before_review fires after the curl, so its duration_ms stays 0
If the automatic hooks fail: The PreToolUse hook returns exit code 2 with structured JSON describing the failure (e.g., test failures, linting errors). Claude Code will present this to you. Fix the issue and retry the API call — the hooks will fire again automatically.
Hook Execution for Non-Claude-Code Environments
The following manual hook execution instructions apply ONLY to environments WITHOUT automatic hook support (Cursor, Windsurf, Continue, etc.). In Claude Code, skip this section — hooks are automatic.
Hooks are bash commands the user wrote in .stride.md. The user authored them. The user expects them to run. Executing hooks is NOT optional and does NOT require confirmation.
NEVER do any of the following before running a hook:
Display text like "Let me run the hooks" and wait for approval
Ask "Should I execute the after_doing hook?"
Ask "Can I run mix test?" or "Can I run mix credo?"
Present the hook commands and wait for the user to approve them
Use any phrasing that triggers a permission prompt in the CLI
The correct behavior is: Read the hook commands from .stride.md, then execute them immediately via the Bash tool. No announcement. No confirmation. No waiting. Just run them.
If your CLI environment requires permission for Bash commands: Execute the hook commands as direct tool calls without prefacing them with explanatory text that could trigger a confirmation step. Run each hook command line by line as individual Bash calls.
The Iron Law
EXECUTE BOTH after_doing AND before_review HOOKS BEFORE CALLING COMPLETE ENDPOINT
The Critical Mistake
Calling PATCH /api/tasks/:id/complete before running BOTH hooks causes:
The API will REJECT your request if you don't include both hook results.
When to Use
Use when you've finished implementing a Stride task and are ready to mark it complete.
Required: Execute BOTH hooks BEFORE calling the complete endpoint.
⚠️ BEFORE CALLING COMPLETE: Verification Checklist ⚠️
STOP. Before proceeding to completion, verify you completed these steps:
Did you invoke stride:stride-workflow after claiming? If no → invoke it now. The orchestrator ensures exploration, review, and hooks all happen.
Did you explore the codebase before coding? If no → read the task's key_files, search for patterns_to_follow, and understand the existing code before proceeding.
Did you review your changes against acceptance_criteria? If no → walk through each acceptance criterion and verify your implementation meets it. Check pitfalls too.
Are you ready to run the after_doing hook (tests, linting)? If no → fix any known issues first. The hook will fail if tests don't pass.
Is workflow_steps included in the complete payload? If no → add it now. The array is required on every completion. It must contain one entry for each of the six step names (explorer, planner, implementation, reviewer, after_doing, before_review) — see the stride-workflow skill for the schema.
Are explorer_result and reviewer_result included? If no → add them now. Both are required on every completion, either as a dispatched-subagent result or as a self-reported skip with a reason from the fixed enum. See the Explorer/Reviewer Result Schema section below.
Does reviewer_result carry the reviewer's full structured block, verbatim? If a stride:task-reviewer agent ran, reviewer_result must include the entire emitted JSON block — status, issue_counts, issues[], acceptance_criteria[], project_checks[], and the section verdicts — produced by a mechanical whole-object copy of the parsed JSON (reviewer_result = dict(structured) then overlay legacy fields), NOT by hand-typing or sub-selecting keys. Run the mandatory self-check before submitting (see the orchestrator's "Extracting the structured review block"): every section the reviewer produced must be present, and the submitted project_checks count must equal the count the reviewer emitted. Hand-typing, re-typing, or a subset shortcut is FORBIDDEN — no exceptions, no small-task discount. Never re-enumerate which keys to copy; the structured key-set is owned by stride/agents/task-reviewer.md. (A missing or trimmed project_checks leaves the Review queue's Code review panel silently empty — and is now hard-rejected by the server contract.)
Per-file diffs. No agent-side action is required on Stride server v1.16.0+ — the after_doing hook PUTs the snapshot to the server automatically. For older Stride deployments that still expect changed_files in the completion body, see the Per-File Diff Capture (Optional) section below for the inline-cat pattern.
If ANY answer is NO → Go back and do it now. Do NOT proceed to completion.
Skipping these steps is not faster — it produces lower quality work that takes longer to fix. This checklist exists because agents consistently skipped these steps under pressure to deliver quickly.
Run this before everyPATCH /api/tasks/:id/complete. If ANY check fails, DO NOT submit — re-run stride:task-reviewer with the full task inputs (the orchestrator's reviewer-dispatch step passes every supplied field), or fix the passthrough, then re-check. There is no bypass: not for small tasks, not for trivial tasks, and never by submitting now with a note promising to fix it later.
Every section present.reviewer_result carries every section the reviewer emitted — the whole-object copy from "Extracting the structured review block" in the orchestrator. Nothing dropped.
project_checks complete. The submitted project_checks count equals the count the reviewer emitted — never trimmed or sub-selected.
No not_assessed for a task-supplied section. For each of testing_strategy, patterns, pitfalls, and security_considerations: if the task supplied that field, its verdict status is a real assessment (passed/failed), never not_assessed or absent. A task-supplied section coming back not_assessed means the reviewer was not handed it (fix the dispatch) or the verdict is wrong — re-run the reviewer; do not submit. In particular: if the task carried security_considerations, reviewer_result.security_considerations.status MUST be passed/failed.
behaviour_test_matrix verdict present & consistent when the task supplied a matrix. If the task carried a behaviour_test_matrix, reviewer_result.behaviour_test_matrix is present with a real status (passed/failed) and a rows array echoing the task's matrix row for row. Every row carries non-empty category and behaviour strings and a status from planned/passing/failing/not_applicable — neververified/missing/mismatch, which the completion API rejects outright (this is a hard failure in every mode, not a grace-gated warning). Fail-closed consistency: any row with status: "failing" REQUIRES behaviour_test_matrix.status to be "failed" AND a matching issues[] entry with category: "testing". When the task supplied no matrix, the verdict key is simply absent — that is correct, not a gap, and must not be back-filled with an empty not_assessed placeholder. The whole-object passthrough already carries this section, so a missing verdict on a matrix-bearing task means the reviewer was not handed the field (fix the dispatch) — re-run the reviewer; do not submit.
Nested security_considerations.considerations[] present & consistent when a deep review ran. When the stride-security-review considerations-mode dispatch ran (see the stride-workflow Step 5 "Deep security-considerations review" sub-step), reviewer_result.security_considerations.considerations[] MUST be present (it rides through automatically on the verbatim whole-object copy — never trim it) and consistent with the section status: any entry with status partial or unmitigated REQUIRES security_considerations.status: "failed" and a matching category: "security" issue in issues[]. A passed status alongside a partial/unmitigated nested entry is a hard fail — do not submit; fix the escalation. When no deep review ran (plugin absent, or the task's security_considerations was empty), the nested array is simply absent and is not required — its absence never fails this gate.
This gate is not bypassable by submitting a self-reported skip (dispatched: false) when a stride:task-reviewer agent actually ran — a dispatched review must pass every check above. The self-check compares counts, keys, and status enums only; it never prints task content, diffs, or secrets. (The Kanban server now hard-rejects a report that fails any of these, so a failing self-check is also a failing completion — catch it here, before you submit.)
The Complete Completion Process
Claude Code (Automatic Hooks)
Finish your work - All implementation complete
Pre-completion code review (Claude Code Only) - If the task meets the stride-subagent-workflow skill's decision matrix for code review (medium+ complexity OR 2+ key_files), dispatch the stride:task-reviewer agent. Fix any Critical or Important issues. Save the reviewer's output to include as review_report in the completion request.
Call PATCH /api/tasks/:id/complete directly - Include after_doing_result and before_review_result with {"exit_code": 0, "output": "Executed by Claude Code hooks system", "duration_ms": 0} — copying the real duration_ms from the PreToolUse after_doing stdout JSON when it is visible to you (0 stays the documented fallback; before_review fires after the curl so its duration is never known at request time). The hooks.json system will:
PreToolUse: automatically execute .stride.md## after_doing BEFORE the curl runs (blocks if it fails)
PostToolUse: automatically execute .stride.md## before_review AFTER the curl succeeds
If PreToolUse hook fails (after_doing): Claude Code reports the failure. Fix the issue (test failures, lint errors, etc.) and retry the curl call.
Check needs_review flag:
needs_review=true: STOP and wait for human review
needs_review=false: Execute after_review hook (automatic), then AUTOMATICALLY invoke stride-claiming-tasks to claim next task
Other Environments (Manual Hooks)
Finish your work - All implementation complete
Read .stride.md after_doing section - Get the validation command
Execute after_doing hook (blocking, 120s timeout)
Execute each line from .stride.md## after_doing one at a time via direct Bash tool calls — NO permission prompts
Capture: exit_code, output, duration_ms
If after_doing fails: FIX ISSUES, do NOT proceed
Read .stride.md before_review section - Get the PR/doc command
Execute each line from .stride.md## before_review one at a time via direct Bash tool calls — NO permission prompts
Capture: exit_code, output, duration_ms
If before_review fails: FIX ISSUES, do NOT proceed
Both hooks succeeded? Call PATCH /api/tasks/:id/complete WITH both results
Check needs_review flag:
needs_review=true: STOP and wait for human review
needs_review=false: Execute after_review hook, then AUTOMATICALLY invoke stride-claiming-tasks to claim next task WITHOUT prompting
Completion Workflow Flowchart
Work Complete
↓
[Claude Code Only] Check decision matrix for code review
↓
Medium+ OR 2+ key_files? ─YES→ Dispatch stride:task-reviewer
↓ NO (or no subagent access) ↓
↓ Issues found? ─YES→ Fix issues
↓ ↓ NO ↓
←─────────────────────────────────────←──────────────←─┘
↓
Read .stride.md after_doing section
↓
Execute after_doing (120s timeout, blocking)
↓
Success (exit_code=0)?
↓ NO
├─ [Claude Code] Dispatch stride:hook-diagnostician
│ ↓
│ Follow prioritized fix plan
├─ [Other] Debug manually
│ ↓
└─→ Fix issues → Retry after_doing (loop back)
↓ YES
Read .stride.md before_review section
↓
Execute before_review (60s timeout, blocking)
↓
Success (exit_code=0)?
↓ NO
├─ [Claude Code] Dispatch stride:hook-diagnostician
│ ↓
│ Follow prioritized fix plan
├─ [Other] Debug manually
│ ↓
└─→ Fix issues → Retry before_review (loop back)
↓ YES
Call PATCH /api/tasks/:id/complete WITH both hook results
↓
needs_review=true? ─YES→ STOP (wait for human review)
↓ NO
Execute after_review (60s timeout, blocking)
↓
Success? ─NO→ Log warning, task still complete
↓ YES
AUTOMATICALLY invoke stride-claiming-tasks (NO user prompt)
↓
Claim next task and begin implementation
↓
(Loop continues until needs_review=true task is encountered)
Hook Execution Pattern
Claude Code: Hooks Are Automatic
In Claude Code, do NOT manually execute hooks. The hooks.json system handles everything:
Just make the complete curl call → PreToolUse fires after_doing (blocks if it fails) → curl executes → PostToolUse fires before_review
If after_doing fails, the PreToolUse hook blocks the curl with exit 2 and reports the failure — fix the issue and retry
Other Environments: Manual Hook Execution
For environments without automatic hooks (Cursor, Windsurf, Continue, etc.):
All hook commands are pre-authorized. Execute them immediately via direct Bash tool calls. Do NOT announce, ask permission, or present commands for review.
Executing after_doing Hook
Read the ## after_doing section from .stride.md
Set environment variables (TASK_ID, TASK_IDENTIFIER, etc.)
Execute each command line immediately via Bash tool calls — NO permission prompts, NO confirmation text
When a blocking hook fails, dispatch the stride:hook-diagnostician agent as the first step before attempting manual fixes. The diagnostician parses the raw output, categorizes issues by severity, and returns a prioritized fix plan — saving time on complex multi-tool failures.
When to dispatch: Any blocking hook failure (after_doing or before_review) where exit_code is non-zero.
What to provide the diagnostician:
hook_name: The hook that failed (e.g., "after_doing" or "before_review")
exit_code: The non-zero exit code
output: The full stdout/stderr output from the hook
duration_ms: How long the hook ran before failing
What you get back: A structured analysis with issues ordered by fix priority (compilation errors → git failures → test failures → security warnings → credo → formatting). Follow the diagnostician's fix order — fixing higher-priority issues often resolves lower-priority ones automatically.
Fallback for non-Claude Code environments: If you don't have access to the Agent tool (Cursor, Windsurf, Continue, etc.), skip the diagnostician and proceed directly to manual debugging using the steps below.
If after_doing fails:
DO NOT call complete endpoint
[Claude Code Only] Dispatch stride:hook-diagnostician with the hook name, exit code, output, and duration
Follow the diagnostician's prioritized fix plan, or if unavailable, read test/build failures carefully
Fix the failing tests or build issues
Re-run after_doing hook to verify fix
Only call complete endpoint after success
Common after_doing failures:
Test failures → Fix tests first
Build errors → Resolve compilation issues
Linting errors → Fix code quality issues
Coverage below target → Add missing tests
Formatting issues → Run formatter
If before_review fails:
DO NOT call complete endpoint
[Claude Code Only] Dispatch stride:hook-diagnostician with the hook name, exit code, output, and duration
Follow the diagnostician's fix plan, or if unavailable, fix the issue manually
Re-run before_review hook to verify
Only proceed after success
Common before_review failures:
PR already exists → Check if you need to update existing PR
Authentication issues → Verify gh CLI is authenticated
Branch issues → Ensure you're on correct branch
Network issues → Retry after connectivity restored
API Request Format
After BOTH hooks succeed, send the completion request. On Stride server
v1.16.0+ the after_doing hook PUTs .stride-changed-files.json to the
server before the completion curl executes, so the agent's completion body
does NOT need to include changed_files. For older Stride deployments
that still expect changed_files in the body, see the
Per-File Diff Capture (Optional) section
below for the inline-cat pattern.
Curl invocation rules (preserve stdout — or your file diffs are silently dropped)
The plugin hook captures your changed_files diff and refreshes the env cache
(TASK_ID, TASK_BASE_REF) by reading the API response off the Bash tool's
stdout. Hide that response and the hook goes blind: the diff is never
captured/uploaded and the completed task shows changed_files: [] in Review —
with no error. Three rules, always:
Never -o / --output (nor -o /dev/null). It removes the response from
stdout entirely — the hook cannot see it.
Never pipe the response into a transformer (jq, head, awk, grep,
sed, …). They alter or truncate what the hook reads.
Always pipe into tee — the one blessed pipe, because it passes stdout
through unchanged (the hook sees it) and writes a full copy for the
truncation fallback:
Capture the response (D118). The tee above writes the full, untruncated
response to the canonical file $CLAUDE_PROJECT_DIR/.stride/.last-api-response.jsonand passes it through to stdout, so the PostToolUse hook still sees the
response and has an untruncated copy to read when the harness truncates the
large /complete stdout (the reviewer_result alone can run to tens of KB). This
is what lets the hook reliably detect an after_goal entry on a goal's last
child. The .stride/ directory is created by the orchestrator; if you invoke the
curl outside the orchestrator, mkdir -p "$CLAUDE_PROJECT_DIR/.stride" first.
Best-effort, not the guarantee. The capture is a fast path: it lets the
hook short-circuit to the file. It is not required for correctness. On a shell
without tee, use --output "$CLAUDE_PROJECT_DIR/.stride/.last-api-response.json"
(the response goes to the file only, not stdout) — or skip capture entirely.
When the file is absent or the response is truncated with no capture, the hook
falls back to a fresh, hook-initiated GET /api/tasks/:id/after_goal_status
(D119), which is immune to harness truncation and needs no agent cooperation.
Do not treat the grace-window worker as the push mechanism — it only flips
the goal to Done; the ## after_goal section is what performs any push.
The resulting request body has this shape (illustrative — populated values
match the --arg substitutions above):
{"agent_name":"Claude Opus 4.6","time_spent_minutes":45,"completion_notes":"All tests passing. PR #123 created.","completion_summary":"Brief one-line summary for tracking.","actual_complexity":"small","actual_files_changed":"lib/foo.ex, test/foo_test.exs","review_report":"## Review Summary\n\nApproved — 0 issues found.","after_doing_result":{"exit_code":0,"output":"Running tests...\n230 tests, 0 failures\nmix credo --strict\nNo issues found","duration_ms":45678},"before_review_result":{"exit_code":0,"output":"Creating pull request...\nPR #123 created: https://github.com/org/repo/pull/123","duration_ms":2340},"explorer_result":{"dispatched":true,"summary":"Explored lib/foo.ex and test/foo_test.exs; identified existing error-tuple pattern to mirror","duration_ms":12450},"reviewer_result":{"dispatched":true,"duration_ms":15300,"summary":"Reviewed the diff against all 5 acceptance criteria and the 3 pitfalls; no issues found","issues_found":0,"acceptance_criteria_checked":5,"schema_version":"1.6","status":"approved","issue_counts":{"critical":0,"important":0,"minor":0},"issues":[],"acceptance_criteria":[{"criterion":"Toggle persists across sessions","status":"met","evidence":"lib/foo.ex:142; test/foo_test.exs:88"}],"project_checks":[],"testing_strategy":{"status":"passed","note":"Tests cover the new toggle persistence."},"patterns":{"status":"passed","note":"Follows the existing settings-update pattern."},"pitfalls":{"status":"passed","note":"No listed pitfall violated."},"security_considerations":{"status":"passed","note":"Theme preference scoped to the authenticated user; no injection surface."}},"workflow_steps":[{"name":"explorer","dispatched":true,"duration_ms":12450},{"name":"planner","dispatched":true,"duration_ms":8200},{"name":"implementation","dispatched":true,"duration_ms":1820000},{"name":"reviewer","dispatched":true,"duration_ms":15300},{"name":"after_doing","dispatched":true,"duration_ms":45678},{"name":"before_review","dispatched":true,"duration_ms":2340}]}
When stride:task-reviewer was dispatched, reviewer_result carries the
reviewer agent's structured JSON block (schema_version, status,
issue_counts, issues[], acceptance_criteria[], project_checks[], and the
per-section testing_strategy/patterns/pitfalls/security_considerations verdicts — the
fields the Kanban review queue actually renders) copied verbatim, merged
with the dispatch telemetry (dispatched: true, duration_ms) and the derived
legacy summary fields (issues_found, acceptance_criteria_checked,
summary). Do NOT send only the thin legacy envelope — it strips the issues,
acceptance verdicts, and code-review checks the reviewer produced. Extract the
fenced ```json block per the stride-workflow skill, "Extracting the
structured review block" (Step 5); the block's schema is owned by
stride/agents/task-reviewer.md. The reviewer's full prose+JSON response is
saved separately as review_report.
Critical:after_doing_result, before_review_result, explorer_result, reviewer_result, and workflow_steps are all REQUIRED. The API will reject requests without them.
Schema reference: The workflow_steps array must match the schema documented in the stride-workflow skill — key-for-key. Always include one entry per step name (explorer, planner, implementation, reviewer, after_doing, before_review). Skipped steps use {"name": "<step>", "dispatched": false, "reason": "<why>"}.
Optional: Include review_report when a task-reviewer agent produced a structured review. Omit it when no review was performed (e.g., small tasks with 0-1 key_files).
When manual testing was performed via the stride-exploratory-testing plugin (the optional, gated Step 5.5 in stride-workflow / Phase 3.5 in stride-subagent-workflow), its findings are recorded in existing completion fields — never in a new server-validated field and never as a 7th workflow_steps name. This keeps the strict-completion-validation contract intact; the server rejects nothing.
Record the session's results in these two existing carriers:
completion_notes — append a short manual-testing summary: the session's Explored/Found/Unknown outcome and any bugs surfaced (with severity). This is the primary carrier and is always available, even when no reviewer ran.
reviewer_result.testing_strategy.note — when a reviewer ran, reflect the manual-testing verdict inside the existing tolerant testing_strategy verdict note (e.g. append "Manual/exploratory session: <one-line outcome>." to the note). This reuses the tolerant-field approach already used for reviewer_result; do not add a new top-level key. When no reviewer ran, skip this carrier and rely on completion_notes alone.
Fallback (plugin not used) — completion is unchanged. When the stride-exploratory-testing plugin was not used — because it is not installed, the task had no manual_tests, or this is a non-Claude-Code environment — record nothing extra. The completion payload is exactly what it would have been before this integration; no field is added, removed, or made required.
Security: the recorded summary must not include real credentials, private data, or internal hostnames captured during exploration — redact them before writing to completion_notes or the testing_strategy note.
Optional (back-compat only): On Stride server v1.16.0+, the after_doing hook PUTs .stride-changed-files.json to the server before the completion curl executes, so the agent does NOT need to send changed_files in the body. For older Stride deployments, the body still accepts changed_files — see the Per-File Diff Capture (Optional) section below for the inline-cat pattern that targets those servers. The encoding rules (500-line truncation marker, binary placeholder, {path, diff} shape) live in docs/diff-contract.md and should not be duplicated into the example.
Explorer/Reviewer Result Schema
Every /complete call must include both explorer_result and reviewer_result as top-level objects. Each is either a dispatched-subagent result or a self-reported skip. Server-side validation is pre-validated by Kanban.Tasks.CompletionValidation; invalid payloads are logged during the grace-period rollout and rejected with 422 once :strict_completion_validation flips.
Shape 1 — dispatched subagent (preferred on Claude Code)
"explorer_result":{"dispatched":true,"summary":"<40+ non-whitespace characters describing what was explored>","duration_ms":12000}"reviewer_result":{"dispatched":true,"duration_ms":8000,"summary":"<40+ non-whitespace characters describing what was reviewed>","issues_found":0,"acceptance_criteria_checked":5,"schema_version":"1.6","status":"approved","issue_counts":{"critical":0,"important":0,"minor":0},"issues":[],"acceptance_criteria":[{"criterion":"<verbatim criterion>","status":"met","evidence":"<file:line>"}],"project_checks":[],"testing_strategy":{"status":"passed","note":"<rationale>"},"patterns":{"status":"passed","note":"<rationale>"},"pitfalls":{"status":"passed","note":"<rationale>"},"security_considerations":{"status":"passed","note":"<rationale>"}}
When stride:task-reviewer was dispatched, reviewer_result is the reviewer
agent's emitted structured JSON block (schema_version, status,
issue_counts, issues[], acceptance_criteria[], project_checks[], and the
per-section testing_strategy/patterns/pitfalls/security_considerations verdicts) copied
verbatim and merged with the dispatch telemetry plus the derived legacy
summary fields. The structured fields are what the Kanban review queue renders
(issue list, acceptance verdicts, code-review checks); omitting them strips the
review down to a count with no detail. Extract the fenced ```json block per
the stride-workflow skill's "Extracting the structured review block" (Step 5)
— that section owns the legacy↔structured field mapping (e.g. issues_found = sum(issue_counts), acceptance_criteria_checked = len(acceptance_criteria)).
The structured block's schema itself is owned by
stride/agents/task-reviewer.md; do not redefine it here. The legacy
acceptance_criteria_checked and issues_found integers remain required (for
back-compat) when dispatched is true. If the reviewer emitted no parseable
```json fence, fall back to the legacy-only envelope and omit the structured
keys — never invent them (see the stride-workflow Step 5 fallback).
Copy exactly the keys the reviewer agent produced — passthrough verbatim; never
maintain an enumerated allow-list of which structured keys to copy. The
structured key-set is owned by stride/agents/task-reviewer.md (see its
"Consumption invariant"); an enumerated copy-list in a consumer is what silently
dropped project_checks. An approved review still
emits issues: [] and project_checks: [] (the agent emits those arrays
unconditionally), so the empty arrays in the examples above are real, not
placeholders. But keys the agent did NOT emit — e.g. per-section
testing_strategy/patterns/pitfalls/security_considerations verdicts on schema versions that don't
produce them — must be omitted entirely, not sent as empty placeholders (per
stride-workflow Step 5).
The same passthrough covers the nested security_considerations.considerations[] breakdown (reviewer schema 1.5+): when a deep security-considerations review ran (the stride-security-review considerations-mode dispatch merges its consideration_verdicts into reviewer_result.security_considerations.considerations[] — see stride-workflow Step 5), that nested array rides through to the PATCH /complete payload automatically because the whole-object copy is verbatim — do NOT add it as a separate enumerated key, and do NOT strip it. When no deep review ran (plugin absent, or the task's security_considerations was empty), the nested array is simply absent — it is never a hard-required field.
{"dispatched":false,"reason":"<one of the 5 enum values below>","summary":"<40+ non-whitespace characters explaining why and what was self-reported>"}
The reason must be exactly one of:
Reason
When to use
no_subagent_support
Platform has no subagent dispatch available (Codex/OpenCode graceful fallback)
small_task_0_1_key_files
Decision matrix: task is small with 0–1 key_files
trivial_change_docs_only
Docs-only change with no code impact
self_reported_exploration
Explored the codebase manually rather than dispatching the explorer agent
self_reported_review
Self-reviewed the diff against acceptance criteria rather than dispatching the reviewer agent
Free-form reasons are rejected — the enum is the contract.
Minimum summary length
Summaries must contain at least 40 non-whitespace characters. Trivial summaries like "explored files" or "reviewed code" are rejected. The minimum is counted after stripping all whitespace, so inserting spaces does not help.
422 rejection example
When strict mode is on and a payload fails validation:
{"error":"completion validation failed","failures":[{"field":"explorer_result","errors":[{"field":"summary","message":"must be a string of at least 40 non-whitespace characters"}]}],"required_format":{/* both shapes documented above */},"documentation":"https://.../AI-WORKFLOW.md#completing-tasks"}
Grace-period rollout
Until the server flips :strict_completion_validation to true, missing or invalid explorer_result/reviewer_result produces a structured warning log but the request succeeds. Emit the fields correctly now — agents that lag the rollout will start getting 422 rejections on the flip day.
Review vs Auto-Approval Decision
After the complete endpoint succeeds:
If needs_review=true:
Task moves to Review column
Agent MUST STOP immediately
Wait for human reviewer to approve/reject
When approved, human calls /mark_reviewed
Execute after_review hook
Task moves to Done column
If needs_review=false:
Task moves to Done column immediately
Execute after_review hook (60s timeout, blocking)
AUTOMATICALLY invoke stride-claiming-tasks skill to claim next task
Continue working WITHOUT prompting the user
CRITICAL AUTOMATION: When needs_review=false, the agent should AUTOMATICALLY continue to the next task by invoking the stride-claiming-tasks skill. Do NOT ask "Would you like me to claim the next task?" or "Should I continue?" - just proceed automatically.
Red Flags - STOP
"I'll mark it complete then run tests"
"The tests probably pass"
"I can fix failures after completing"
"I'll skip the hooks this time"
"Just the after_doing hook is enough"
"I'll run before_review later"
"Let me run the after_doing hook" (then wait for user to approve) — NEVER prompt for hook permission
"Should I execute mix test?" — hooks are pre-authorized, just run them
"Should I claim the next task?" (Don't ask, just do it when needs_review=false)
"Would you like me to continue?" (Don't ask, auto-continue when needs_review=false)
All of these mean: Run BOTH hooks BEFORE calling complete, and auto-continue when needs_review=false.
Rationalization Table
Excuse
Reality
Consequence
"Tests probably pass"
after_doing catches 40% of issues
Task marked done with failing tests
"I can fix later"
Task already marked complete
Have to reopen, wastes review cycle
"Just this once"
Becomes a habit
Quality standards erode completely
"before_review can wait"
API requires both hook results
Request rejected with 422 error
"Hooks take too long"
2-3 minutes prevents 2+ hours rework
Rushing causes failed deployments
Common Mistakes
Mistake 1: Calling complete before executing hooks
❌ curl -X PATCH /api/tasks/W47/complete
# Then running hooks afterward
✅ # Execute after_doing hook first
START_TIME=$(date +%s%3N)
OUTPUT=$(timeout 120 bash -c 'mix test' 2>&1)
EXIT_CODE=$?
# ...capture results# Execute before_review hook second
START_TIME=$(date +%s%3N)
OUTPUT=$(timeout 60 bash -c 'gh pr create' 2>&1)
EXIT_CODE=$?
# ...capture results# Then call complete WITH both results
curl -X PATCH /api/tasks/W47/complete -d '{...both results...}'
Mistake 3: Continuing work after needs_review=true
❌ PATCH /api/tasks/W47/complete returns needs_review=true
Agent continues to claim next task
✅ PATCH /api/tasks/W47/complete returns needs_review=true
Agent STOPS and waits for human review
Mistake 4: Manually executing hooks in Claude Code
❌ Agent reads .stride.md, runs "mix test" and "mix credo" via Bash tool
Agent captures exit code and duration
Agent then makes the complete curl call
(This triggers permission prompts and duplicates what hooks.json does)
✅ Agent just makes the complete curl call directly:
curl -X PATCH .../api/tasks/:id/complete -d '{...}'
(hooks.json PreToolUse auto-runs after_doing via stride-hook.sh
hooks.json PostToolUse auto-runs before_review via stride-hook.sh)
Mistake 5: Prompting user for permission to run hooks (non-Claude-Code)
❌ Agent says "Let me run the after_doing hooks"then waits for user approval
❌ Agent asks "Should I execute mix test?"
❌ Agent presents hook commands and pauses for confirmation
✅ Agent reads .stride.md after_doing section
Agent immediately executes each command via Bash tool calls
No announcement, no confirmation, no waiting
(The user authored these hooks — they are pre-authorized)
Mistake 6: Not fixing hook failures
❌ after_doing fails with test errors
Agent calls complete endpoint anyway
✅ after_doing fails with test errors
Agent fixes tests, re-runs hook until success
Only then calls complete endpoint
Implementation Workflow
Complete all work - Implementation finished
Execute after_doing hook AUTOMATICALLY - Run tests, linters, build (DO NOT prompt user)
Check exit code - Must be 0
If failed: Fix issues, re-run, do NOT proceed
Execute before_review hook AUTOMATICALLY - Create PR, generate docs (DO NOT prompt user)
Check exit code - Must be 0
If failed: Fix issues, re-run, do NOT proceed
Call complete endpoint - Include BOTH hook results
Check needs_review flag - Stop if true, continue if false
If false: Execute after_review hook AUTOMATICALLY (DO NOT prompt user)
Claim next task - Continue the workflow
Quick Reference Card
CLAUDE CODE COMPLETION WORKFLOW (automatic hooks):
├─ 1. Work is complete ✓
├─ 2. [Optional] Dispatch task-reviewer for code review ✓
├─ 3. Call PATCH /api/tasks/:id/complete directly ✓
│ (hooks.json PreToolUse auto-runs after_doing first
│ hooks.json PostToolUse auto-runs before_review after)
├─ 4. PreToolUse hook failed? → Fix issues, retry curl ✓
├─ 5. needs_review=true? → STOP, wait for human ✓
└─ 6. needs_review=false? → after_review auto-fires, claim next ✓
🚨 DO NOT manually execute .stride.md commands in Claude Code
🚨 DO NOT run separate Bash commands to "capture hook results"
🚨 JUST make the curl call — hooks.json handles everything
OTHER ENVIRONMENTS (manual hooks):
├─ 1. Work is complete ✓
├─ 2. Execute after_doing (120s timeout, blocking) ✓
├─ 3. Hook fails? → FIX, retry, DO NOT proceed ✓
├─ 4. Execute before_review (60s timeout, blocking) ✓
├─ 5. Hook fails? → FIX, retry, DO NOT proceed ✓
├─ 6. Both succeed? → Call PATCH /api/tasks/:id/complete WITH both results ✓
├─ 7. needs_review=true? → STOP, wait for human ✓
└─ 8. needs_review=false? → Execute after_review, claim next ✓
API ENDPOINT: PATCH /api/tasks/:id/complete
REQUIRED BODY: {
"agent_name": "Claude Opus 4.6",
"time_spent_minutes": 45,
"completion_notes": "...",
"review_report": "..." (optional — include when task-reviewer ran),
"skills_version": "1.0",
"after_doing_result": {
"exit_code": 0,
"output": "Executed by Claude Code hooks system",
"duration_ms": 0
},
"before_review_result": {
"exit_code": 0,
"output": "Executed by Claude Code hooks system",
"duration_ms": 0
},
"explorer_result": {
"dispatched": true,
"summary": "<40+ non-whitespace chars>",
"duration_ms": 12000
},
"reviewer_result": {
"dispatched": true,
"duration_ms": 8000,
"summary": "<40+ non-whitespace chars>",
"issues_found": 0,
"acceptance_criteria_checked": 5,
"schema_version": "1.6",
"status": "approved",
"issue_counts": {"critical": 0, "important": 0, "minor": 0},
"issues": [],
"acceptance_criteria": [{"criterion": "<verbatim>", "status": "met", "evidence": "<file:line>"}],
"project_checks": [],
"testing_strategy": {"status": "passed"},
"patterns": {"status": "passed"},
"pitfalls": {"status": "passed"},
"security_considerations": {"status": "passed"}
},
"workflow_steps": [
{"name": "explorer", "dispatched": true, "duration_ms": 12450},
{"name": "planner", "dispatched": true, "duration_ms": 8200},
{"name": "implementation", "dispatched": true, "duration_ms": 1820000},
{"name": "reviewer", "dispatched": true, "duration_ms": 15300},
{"name": "after_doing", "dispatched": true, "duration_ms": 45678},
{"name": "before_review", "dispatched": true, "duration_ms": 2340}
]
}
reviewer_result (dispatched) = the task-reviewer agent's fenced ```json block
(schema_version/status/issue_counts/issues[]/acceptance_criteria[]/project_checks[]/testing_strategy/patterns/pitfalls/security_considerations)
merged with dispatched:true + duration_ms + derived legacy issues_found/acceptance_criteria_checked.
See stride-workflow Step 5 for extraction; schema owned by stride/agents/task-reviewer.md.
SKIP FORM for explorer_result / reviewer_result (when subagent not dispatched):
{"dispatched": false, "reason": "<enum>", "summary": "<40+ non-whitespace chars>"}
Reason enum: no_subagent_support, small_task_0_1_key_files, trivial_change_docs_only,
self_reported_exploration, self_reported_review
VERSION: Send skills_version from your SKILL.md frontmatter with every complete request
Real-World Impact
Before this skill (completing without hooks):
40% of completions had failing tests
2.3 hours average time to fix post-completion
65% required reopening and rework
After this skill (hooks before complete):
2% of completions had issues
15 minutes average fix time (pre-completion)
5% required rework
Time savings: 2+ hours per task (90% reduction in post-completion rework)
Completion Request Field Reference
Field
Type
Required
Description
agent_name
string
Yes
Name of the completing agent
time_spent_minutes
integer
Yes
Actual time spent on the task
completion_notes
string
Yes
Summary of what was done
completion_summary
string
Yes
Brief summary for tracking
actual_complexity
enum
Yes
"small", "medium", or "large"
actual_files_changed
string
Yes
Comma-separated file paths (NOT an array)
changed_files
array
No
Per-file diff entries — see the Per-File Diff Capture section below
after_doing_result
object
Yes
Hook result (see format below)
before_review_result
object
Yes
Hook result (see format below)
workflow_steps
array
Yes
Telemetry array with one entry per step name. See stride-workflow skill for full schema.
explorer_result
object
Yes
stride:task-explorer dispatch result OR self-reported skip. See Explorer/Reviewer Result Schema section.
reviewer_result
object
Yes
stride:task-reviewer dispatch result OR self-reported skip. See Explorer/Reviewer Result Schema section.
review_report
string
No
Structured review report from task-reviewer agent. Include when a review was performed; omit when no review was done.
RIGHT — actual_files_changed as comma-separated string:
"actual_files_changed":"lib/foo.ex, lib/bar.ex"
Per-File Diff Capture (Optional)
The completion payload accepts an optional top-level changed_files array — one
entry per file the agent touched, with the unified-patch text alongside the
path. The Stride server is the consumer; the review-queue UI renders these
diffs inline so reviewers approve or reject without leaving Stride.
The full encoding rules — field shape, the 500-line truncation marker, the
binary-file placeholder, and the backward-compatibility guarantees — live in
the contract doc and are the single source of truth:
Contract:docs/diff-contract.md
(defines path / diff keys, exact truncation marker string, exact binary
placeholder string, the 500-line inclusive cap, and the optional-field rules)
How the stride plugin produces this data. After a successful after_doing
hook the plugin captures the agent's working-tree state versus the
$TASK_BASE_REF anchor — committed changes, staged-but-uncommitted changes,
modified-but-unstaged changes, AND untracked-new files (not in .gitignore)
all surface in a single snapshot. Untracked new files appear as synthesized
new-file unified patches (diffed against /dev/null); untracked binaries use
the binary placeholder. The plugin applies the contract's truncation and
binary conventions and writes the JSON array to
$CLAUDE_PROJECT_DIR/.stride-changed-files.json. The snapshot is per-project,
refreshed at the end of every after_doing, and cleaned up on after_review.
Working-tree semantic (v1.15.0+). The snapshot reflects the agent's
working state at completion time, regardless of commit state. An agent that
edits a file and calls /complete WITHOUT committing first still produces a
populated snapshot — the diff is captured from the working tree against
$TASK_BASE_REF, not from ..HEAD. Earlier plugin versions (≤ 1.14.x)
required a commit before completion or the snapshot was empty.
Claim-time dirty-baseline exclusion (W1457). At claim time the
before_doing branch records every path that is already modified or
untracked, with its blob hash, to .stride-dirty-baseline. At capture time
a path is excluded from the snapshot only when it appears in that baseline
AND its blob hash is unchanged — i.e. it is a pre-existing edit unrelated to
the task. A baselined file that is modified again during the task IS
included (hash differs), as are ambiguous cases (deleted after claim,
unhashable — when in doubt, include). A missing baseline (older claim)
disables the exclusion. Independently of the baseline, .stride.md,
.stride_auth.md (credentials — never uploaded under any circumstances),
and the hook's own bookkeeping artifacts are hard-excluded by name.
Upload flow (v1.16.0+). The plugin's after_doing hook now uploads the
snapshot to the Stride server itself: immediately after writing
.stride-changed-files.json, the hook issues a fire-and-forget
PUT {URL}/api/tasks/{TASK_ID}/changed_files. The request body is NOT the
raw snapshot: the file bytes are wrapped in a base64 transport envelope —
{"changed_files": {"encoding": "base64", "data": "<base64>"}} — so an edge
request filter cannot misread a unified code diff as an attack and drop the
upload (the envelope and its rules are owned by
docs/diff-contract.md;
do not duplicate them here). URL and Bearer token are resolved from
$PROJECT_DIR/.stride_auth.md FIRST (its **API URL:** and **API Token:**
lines — placeholder example: stride_dev_<token>), falling back to values
extracted from the agent's intercepted completion curl when the auth file is
absent or incomplete — so the upload works whether the curl used literal
values or $STRIDE_API_URL/$STRIDE_API_TOKEN shell variables. The PUT
runs BEFORE the agent's completion request executes (inside the PreToolUse
path) so the server has the diff data attached to the task by the time
/complete lands. The agent's completion body does NOT need to include
changed_files.
Limitations
Nested git repositories are invisible to the capture. The snapshot
diffs only the outer project repository. Work done inside a nested repo
with its own .git directory (e.g. a plugin subrepo that the outer
project gitignores) never appears in changed_files — the outer git diff/ls-files nets cannot see inside it. The working convention: put
the subrepo commit hash(es) in completion_notes so reviewers can find
the real diff in the subrepo's history.
Pre-existing dirty files are excluded by design via the claim-time
dirty baseline above — if a reviewer reports a "missing" diff for a file,
check whether it was already dirty before the claim and unchanged since.
Backwards compatibility
Server version
How changed_files reaches the server
v1.16.0+
after_doing hook PUTs the snapshot. Agent body does NOT need changed_files.
≤ v1.15.x
Hook only writes the snapshot to disk. Agent must inline-read it in the completion body via the legacy pattern below.
Both modes coexist: on a v1.16.0+ server, sending changed_files in the body
still works (the server treats the PUT-uploaded value as authoritative). On
older servers, the hook PUT 404s harmlessly (fire-and-forget) and the inline
body remains the only path. If you are unsure of the deployed server version
or you want a single curl that works against both, use the legacy inline
pattern below — it remains valid against every supported server.
Legacy inline pattern (≤ v1.15.x deployments). Inline the snapshot read
inside the curl invocation using jq -n --argjson cf, with the absolute
$CLAUDE_PROJECT_DIR path so the read works regardless of the Bash call's
CWD. The inline-cat must live inside the SAME curl invocation: the
PreToolUse-on-complete hook writes .stride-changed-files.json during the
curl call, so any earlier Bash tool call that reads the file runs BEFORE the
hook has populated it.
If .stride-changed-files.json is absent — older plugin install, non-git
project, capture failed, jq missing on the agent's machine — the inlined
|| echo '[]' fallback produces an empty array. Empty changed_files is a
valid shape; the server accepts it. Do NOT synthesize diffs by hand to "fill
in" the field; emit only what the plugin captured (or []). Both shapes
below are valid completions:
changed_files in the completion body is strictly optional — completion
payloads that omit it remain fully valid forever, regardless of server
version.
Hook Result Format Reminder
Both after_doing_result and before_review_result use the same format:
Field
Type
Required
Description
exit_code
integer
Yes
0 for success, non-zero for failure
output
string
Yes
stdout/stderr output from hook execution
duration_ms
integer
Yes
How long the hook took in milliseconds
WRONG — missing required fields:
"after_doing_result":{"output":"tests passed"}
RIGHT — all three fields present:
"after_doing_result":{"exit_code":0,"output":"All 230 tests passed\nmix credo --strict: no issues","duration_ms":45678}
Handling Stale Skills
The API response may include a skills_update_required field when your skills are outdated:
When you see skills_update_required:
Run /plugin update stride to get the latest skills
Retry your original action
Arriving from stride-workflow
If you are following the stride:stride-workflow orchestrator, you arrive here at Step 6-7 with all prerequisites already satisfied:
Task was claimed with proper before_doing hook (Step 2)
Codebase was explored and patterns identified (Step 3)
Implementation is complete (Step 4)
Code review was performed against acceptance criteria (Step 5)
You can proceed directly to hook execution and completion. The orchestrator has already guided you through all prior steps.
Previous Skill Before Completing (Standalone Mode)
If you are using this skill standalone (not via the orchestrator), you should have already invoked:
stride:stride-workflow (recommended) — The orchestrator handles the full lifecycle. If you used it, you've already completed all prior steps.
stride:stride-claiming-tasks — To claim the task with proper before_doing hook execution
stride:stride-subagent-workflow (Claude Code only) — To explore, plan, and review based on the decision matrix
If you skipped prior workflow steps, the after_doing hook is likely to fail. Go back and verify.
References: For the full field reference, see api_schema in the onboarding response (GET /api/agent/onboarding). For endpoint details, see the API Reference. For hook failure diagnosis, see stride/agents/hook-diagnostician.md.