Create/Update Request Skill

SkillProductivity

Create, update, or scan per-task request tickets for progress tracking. These are date-prefixed non-lifecycle docs under requests/, NOT feature-level requirements (use /req-analyze for those). Use when: tracking task progress, updating completion status, scanning incomplete requests, checking request status dashboard. Not for: feature-level problem-space analysis (use req-analyze for 1-requirements.md lifecycle doc), tech specs (use tech-spec), code implementation (use feature-dev). Output: request ticket with status tracking, referencing parent tech-spec.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Create/Update Request Skill skill

What this skill tells your AI

The instructions your AI receives, as published by sd0xdev/sd0x-harness in skills/create-request/SKILL.md and read by ahel’s review.

Trigger

  • Keywords: create request, new request, write request, build request, update request, sync progress, scan requests, request status, incomplete requests, request dashboard

Mode Overview

flowchart LR
    A[/create-request] --> B{Mode?}
    B -->|--status| C[Scan: Discover → Parse → Filter → Report]
    B -->|--update-all| F[Batch Update: Scan → Git Verify → Batch Edit → Report]
    B -->|--update| D[Update: Load → Analyze → Map → Update → Report]
    B -->|default| E[Create: Gather → Explore → Generate → Confirm]

Modes

ModeTrigger ConditionAction
createNo file specified / new requestGather info -> Fill template -> Create file
updateFile specified / update requestRead current state -> Check implementation -> Update progress
update-all--update-all flagBatch scan → git verify → update all stale docs → report
scan--status flagScan all requests -> Parse metadata -> Filter incomplete -> Report

Arguments

FlagApplies ToDescription
--verify-ac--update (single)Dispatch Explore agent to verify AC completion with evidence (file:line). Supports auto-detected path via feature context 5-level cascade. Not available with --update-all.

When NOT to Use

  • Feature-level requirements analysis (use /req-analyze — produces 1-requirements.md, a Phase 1 lifecycle doc for problem-space analysis; see Relationship section below)
  • Viewing request structure (use request-tracking)
  • Writing tech spec (use /tech-spec)
  • Code development (use feature-dev)

Relationship with /req-analyze

Request tickets are work breakdown units derived from /tech-spec, not requirements documents themselves. They live in a different document class per @rules/docs-numbering.md.

Dimension/create-requestrequests/YYYY-MM-DD-*.md/req-analyze1-requirements.md
Doc classRequest ticket (date-prefixed, non-lifecycle — per @rules/docs-numbering.md)Lifecycle (Phase 1, numeric prefix)
Count per featureMany (one per task)One (upsert)
Position in workflowAfter /tech-spec (execution phase)Before /tech-spec (design phase)
Content focusExecution — Status, Progress, AC checklist, Related FilesProblem space — 5-Why, FR/NFR, MoSCoW, stakeholders
GranularitySingle task (≤ 8 substantive ACs; gate receipts excluded from the budget, never from the lifecycle count)Feature-wide
Update patternStatus tracking (scan / update / update-all / --verify-ac)Document upsert
AudienceExecutors, progress trackersDesigners, decision-makers

Workflow ordering

/req-analyze → /tech-spec → /create-request → /feature-dev
   (Phase 1)    (Phase 2)    (ticket per task)    (implement)

A request ticket references its parent /tech-spec for technical detail and may optionally link to 1-requirements.md for problem-space rationale (when /req-analyze was run).

A feature directory may also carry intent-<key>.md (ancillary — Design record, written by /req-analyze or /tech-spec): constraints only — North star, Non-goals, INV-* invariants, acceptance sketch — read by both the designer and the implementer. Tickets never restate it; the implementing skills load it themselves before writing code.

Anti-patterns to avoid

Anti-patternCorrect approach
Writing 5-Why / stakeholder analysis inside a request ticketPut it in 1-requirements.md via /req-analyze; ticket just references it
Adding ## Progress / ## Status tables to 1-requirements.mdProgress tracking belongs in request tickets, not the lifecycle requirements doc
Creating one request ticket per whole feature (AC > 8)Split by layer or functional area; see Granularity Guide in references/template.md
Treating 1-requirements.md as a prerequisite for creating requestsIt is advisory-only; requests work standalone when only tech-spec exists

Create Mode Workflow

Phase 1: Gather     -> Collect feature, title, priority, requirements
Phase 1.5a: Quick   -> AC count + layer keyword scan (pre-Explore)
Phase 2: Explore    -> Search related code + tech specs
Phase 1.5b: Refined -> Layer mixing (Related Files) + scope breadth + WBS (post-Explore)
Phase 3: Generate   -> Fill template + create file(s)
Phase 4: Confirm    -> Display result + suggest next steps

Phase 1.5: Granularity Check

Assess whether the request should be split into multiple focused tickets. This runs in two passes to balance early detection with accurate analysis.

Signal Detection

SignalDetectionWeight
AC count > 8Count per § Pre-Render AC Count below — this whole phase runs in Create Mode, where no ticket is rendered yet — then exclude receipts per § Quality-Gate AC ClassifierPrimary
Layer mixing1.5a: keyword scan for rules/, hooks/, scripts/ in requirements text. 1.5b: classify Related Files into behavior-layer (.md rules/skills) vs code-layer (.sh/.js hooks/scripts)Primary
Scope breadthRequirements has 3+ functionally independent areasPrimary
WBS groups ≥ 2Tech spec has Work Breakdown heading with 2+ independent task groups (secondary, high-confidence only)Secondary (×0.5)
Effort > 3 daysTech spec WBS has multiple M/L itemsSecondary (×0.5)

Pre-Render AC Count

Phase 1.5 runs inside the Create Mode workflow, before Phase 3 renders anything, so § Live Checkbox ACs — which reads a rendered ## Acceptance Criteria section — has no input here and would count zero, silently suppressing every split suggestion this phase exists to produce.

One rule, governing every count taken before the ticket exists: the overall {N}, and each {AC_count_A} / {AC_count_B} in the split suggestion after grouping. Count the criteria gathered at Phase 1 item 6, one per list item, whatever form the user wrote them in — numbered, hyphenated or plain lines. Then exclude receipts per § Quality-Gate AC Classifier, applied to those same strings — one of that classifier's two permitted uses. The subgroup counts are the same units as the total, or a split "into two tickets of ≤ 8" can be proposed out of groups that were never measured the same way as the number that triggered it.

Live Checkbox ACs

Every path that counts ACs in a ticket that exists — Scan Mode's AC Progress, the § AC-Form Preflight, Phase 2.5's verification input and decision table, Phase 3's Progress mapping, Phase 4 and batch mode — counts the same items, or the same ticket gets two different AC counts depending on who is looking.

The qualifier is load-bearing: this definition reads a rendered section, so the only counts that do not come from here are Create Mode's, defined at § Pre-Render AC Count.

An AC is a top-level hyphen-form task-list item inside ## Acceptance Criteria that is live document text — ^ {0,3}-\s+\[(?: |x|X)\] after live-text masking. The indent bound is load-bearing: a deeper indent under a paragraph is a continuation of that paragraph, so Example only: followed by an indented - [x] illustrative checkbox is visible prose, not a task list, and an unbounded ^\s*[-*] counts it as a checked AC. CommonMark also allows * and + bullets and ordered task items; this repo's template emits hyphens and the corpus contains no other form, so the extractor accepts the hyphen form only and anything else reaches the § AC-Form Preflight's Need Human exit rather than being promoted. A checkbox inside a fenced block, an HTML comment, or an indented code example is illustration, not an acceptance criterion, and a section holding nothing else has no ACs at all — which is the § AC-Form Preflight's no-mutation exit, not an empty AC set. Some tickets record ACs as an AC → evidence table instead; that is a valid form which none of these paths can count, and it takes the same exit.

Quality-Gate AC Classifier

Scope: display and granularity only. This classifier never touches status derivation. Exactly two paths use it — Scan Mode's AC Progress (what the dashboard shows) and Phase 1.5's split signal. Phase 2.5's decision table, Phase 4's lifecycle and batch mode's Status rule count every AC and do not consult it.

That boundary is the point. Classifying free-text ACs with a regex is inherently approximate: six successive refinements each measured clean against the whole corpus, and each was then shown to admit a behavioural requirement or drop a real receipt. Where a misread only shifts a displayed count it is visible; where it shifts the split suggestion it may not be, since an undercount can suppress the suggestion silently. Both are advisory and reversible, which is the property that matters. Where it fed status derivation, a false positive removed an AC from the set a ticket had to satisfy — so a ticket could reach Completed without the work. The fix is not a better regex; it is not letting an approximate signal decide a durable record.

One consequence, and it is the correct one: an unchecked Pass /precommit keeps a ticket at In Progress until that gate actually runs. A ticket whose gates have not run is not finished.

An AC is a quality gate only when it is a receipt — its content is that a gate ran, or why it has not. Neither containing a gate command nor merely opening with one is the test: `/precommit` — Try script -> fallback + graceful skip opens with a gate command and is an implementation requirement for /precommit. A receipt is a gate command plus one of:

Receipt markerExample
a receipt word — Pass / Passed / passes / 通過Pass /codex-review-doc
a round N citation`/codex-review-fast` round 1
a named verdict sentinel after a dash — exactly these six pairs: ✅ PASS / ✅ Ready / ✅ Mergeable / ⛔ Blocked / ⛔ Needs revision / ❌ FAIL`/precommit` — ✅ PASS
a gate lifecycle tail — superseded or pending followed within a bounded window by a round N or verdict reference, or tracked below— pending Codex round 30 verdict

A bare marker must also end the receipt — the intended semantics, subject to § Known residuals below, which names the forms the published regex still accepts against this rule. pass, round N and tracked below are ordinary English too, so each must be followed by end-of-AC, a parenthetical, or a paired verdict sentinel — otherwise /precommit passes selected flags through to the underlying runner, round 3 results must be persisted and failure details are tracked below the originating step all read as receipts. A receipt is short; a requirement continues into a sentence.

superseded and pending need that bounded follow-on precisely because they are ordinary English: `/precommit` — pending jobs must resume after the build finishes is a behavioural requirement, and dropping it from the displayed count understates what is left. (Under the old design, where this classifier fed status derivation, the same misread could let a ticket advance without the AC. That is why it no longer does — the consequence is now a wrong number on a dashboard or a misfired split suggestion.) Labels are optional and may be bold or plain (AC-8:, **AC-Q1**).

^(?:(?:\*\*[^*]{1,24}\*\*|[A-Za-z][\w.-]{0,12})\s*[::]?\s+)?(?:(?:pass(?:ed|es)?|通過)\s+`?/(?:codex-review-fast|codex-review-doc|codex-review|precommit-fast|precommit|pr-review)\b|`?/(?:codex-review-fast|codex-review-doc|codex-review|precommit-fast|precommit|pr-review)`?(?:[^—((::]{0,40}?(?:\bpass(?:ed|es)?\b|通過|\bround\s+\d+\b)(?=\s*$|\s*[((]|\s*[,,—–]\s*[✅⛔❌])|[^—((::]{0,60}?\s*[—–]\s*(?:round\s+\d+|(?:superseded|pending)[^—]{0,30}?(?:round\s+\d+|verdict)|[^—]{0,40}?\btracked below\b(?=\s*$|\s*[((]|\s*[,,—–]\s*[✅⛔❌])|(?:✅\s*(?:PASS|Ready|Mergeable)|⛔\s*(?:Blocked|Needs revision)|❌\s*FAIL))))

Case-insensitive (/i) — `/codex-review-doc` pass is as much a receipt as Pass /codex-review-doc.

Three ways to be a receipt: a receipt word then a gate command; a gate command followed closely by one; or a gate command whose line ends in an explicit verdict tail after a dash — — round 3, — ✅ PASS, — ⛔ Blocked. That third branch is why a separator is not an unconditional boundary: `/codex-review-fast` re-review after the round-2 fixes — round 3, ⛔ Blocked is a receipt whose decisive token sits past the dash. What the tail must not be is prose — `/precommit` — Try script -> fallback has a dash and is an implementation requirement, and a bare is not enough either (— ✅ 已驗證 stays substantive). Only a named verdict sentinel counts, and only as one of the six pairs above — the mark and the word are matched together, not as a cross-product, so ✅ FAIL, ❌ Ready and ⛔ PASS are not receipts. A contradictory sentinel is malformed text, and reading it as a receipt would hide a real AC from the displayed count — or a gate lifecycle tail in the bounded form the table above requires, because an unchecked gate AC recording why its gate has not run yet is still bookkeeping, not work. Two real ones live in docs/features/auto-loop-evolution/requests/2026-08-08-receipt-integrity-issues-9-10-11.md. The bounded window still stops at ( and , so a gate AC whose tail sits past a parenthetical stays counted as work. Two real ones do: docs/features/auto-loop-evolution/requests/2026-08-08-receipt-integrity-issues-9-10-11.md lines 860 and 878, `/precommit` then `/codex-review-doc` … (task #85) — pending …. These are known, intentional exceptions, not oversights: widening past parentheses is where behavioural ACs live, and the failure direction here overstates the displayed remainder rather than understating it. It does not hold the lifecycle open — under the all-AC rule an unchecked receipt does that on its own. Revisit only with a corpus measurement showing the widened form adds no false positive.

Excluded — a receipt that a gate ranKept — the command is the subject of real work
Pass /codex-review-doc(✅ Mergeable) `/precommit` — Try script -> fallback + graceful skip
Pass `/codex-review-fast` → `/precommit` `/pr-review` 整合:自動呼叫 fast mode
`/codex-review-doc` 通過…Stop 回報的事實…且不含 `/codex-review-fast`
AC-8: Pass /codex-review-doc … ✅ Verified…新增 10 個測試(…`/precommit` 路由…)
`/codex-review-fast` round 1 — ⛔ BlockedSkill routing:支援至少 8 個 route target(…)
`/codex-review-doc` pass `/precommit` runner 支援 ecosystem 偵測 — ✅ 已驗證
`/precommit` — ✅ PASS (comment_blocks, lint:fix, build, test)提供 copy-pasteable 修正指令(如 …)

Every row is a real AC from this repo's requests/, and both columns are pinned by test/skills/create-request-scan.test.js. The right column is what a position-only rule got wrong: it dropped implementation work from the displayed count, so the dashboard understated what was left. The left column's last two rows are what a bold-label-only rule got wrong in the other direction — a real receipt counted as work overstates the displayed remainder. It does not hold the lifecycle open: by the all-AC rule an unchecked receipt keeps a ticket open on its own, whatever this classifier says about it.

Known residuals. The published regex is looser than the prose above in places: forms like Pass /precommit must preserve selected flags and `/precommit` — round 3 results must be persisted still match, because the terminator rule reaches the bare post-command markers but not every route. These are accepted approximation residuals, not open defects. Chasing them produced six refinements, each corpus-clean and each then shown to admit prose or drop a receipt; the seventh attempt dropped 26 real receipts. Bounding the classifier to display and granularity is what makes residuals affordable. The cost is a slightly wrong number on a dashboard, or an advisory split signal that fires when it need not (false negative) or stays silent when it should fire (false positive); the route that made them dangerous is closed. Tighten one only with a corpus measurement showing it adds no false negative.

The classifier fails toward substantive — when an AC is genuinely ambiguous, keep it. Since the classifier no longer feeds status, the cost of either error is a display figure or an advisory split signal rather than a lifecycle decision; keeping an ambiguous AC still makes the count honest about what a reader can verify.

Decision Logic

signal_count = primary_count + 0.5 × secondary_count

< 2  → proceed as single request (no suggestion)
≥ 2  → suggest split (advisory AskUserQuestion)
≥ 3  → strongly recommend split

Split Suggestion

When triggered, use AskUserQuestion:

## Granularity Assessment

This request has {N} substantive acceptance criteria (target: ≤8, gate receipts excluded) and {layer_info}.

Suggested split:
1. {Title A} — {scope A} ({AC_count_A} AC)
2. {Title B} — {scope B} ({AC_count_B} AC)

Options:
- "Split into {N} requests" (Recommended)
- "Keep as 1 request"

Split by: layer (behavior vs code) if detected, then functional area if scope breadth detected, then balanced AC groups as fallback.

Sibling Request Output

When user accepts split, create indexed files: YYYY-MM-DD-{title-slug}-r1.md, ...-r2.md, etc. (e.g., 2026-03-18-auth-fix-r1.md, 2026-03-18-auth-fix-r2.md). Each gets its own AC subset (target ≤8 substantive, counted per § Pre-Render AC Count), scoped Related Files, and conditional > **Depends On**: header if dependency exists between siblings.

Create Mode: Interaction

If incomplete info, ask:

1. Feature area: Which feature? (e.g., auth, billing, notifications)
2. Title: Brief description
3. Priority: P0 (urgent) / P1 (high) / P2 (medium)
4. Background: Why is this needed?
5. Requirements: What needs to be done? (list)
6. Acceptance criteria: How do we know it's done?

Update Mode Workflow

Path resolution: --update supports three forms:

FormBehavior
--update <path>Use explicit path (must match docs/features/*/requests/*.md)
--update (no path)Auto-detect from feature context (see references/feature-context-resolution.md)
--update <keyword>Resolve feature key, then find active request(s)

Auto-detection logic (when no explicit path):

  1. Resolve feature context using the 5-level cascade — node scripts/resolve-feature.js, the wrapper that owns the failure payload; the CLI behind it is not the entrypoint 1b. scan_error gatescan_error !== false ⇒ the source sets are unknown, not empty. Report it and take the ⚠️ Need Human exit. This is the step that matters most here: an unreadable requests/ directory returns the same empty set as a feature with no tickets, so without the gate step 5 below reads it as "0 active requests" and creates a duplicate ticket beside the one it could not see. Gate on !== false, not === true: a {} payload from a shell fallback carries no such field, so a non-null key is not evidence of completeness
  2. Scan docs/features/<key>/requests/*.md for incomplete requests (Status not in [Completed, Done, Superseded, Archived] — the closed set is defined once in scripts/lib/request-status.js; keep this list identical to CLOSED_REQUEST_STATUS)
  3. If exactly 1 active request → auto-select
  4. If multiple active requests → AskUserQuestion with numbered list
  5. If 0 active requests → offer to create new via create mode
  6. If feature not resolved → Gate: Need Human
Phase 0: Freeze    -> Reparse Status. Closed (`CLOSED_REQUEST_STATUS`) -> no ordinary update: report frozen, exit.
                      One path continues: an explicitly authorized factual correction (Phase 4.5), which performs
                      that correction and nothing else, recorded in `Progress.Note`
Phase 1: Load      -> Read existing request document
Phase 2: Analyze   -> Analyze Related Files + git changes
Phase 2.4: Preflight -> § AC-Form Preflight (all modes, unconditional)
Phase 2.5: Verify    -> (--verify-ac only) agent-based AC verification
Phase 3: Map       -> Compare implementation with Acceptance Criteria
Phase 4: Update    -> Update Progress / Status / Checkboxes
Phase 5: Report    -> Output change summary

Phase 2: Analyze Implementation Progress

# Get changes for Related Files from request document
git log --oneline --since="<created_date>" -- <related_files>

# Check test status
grep -rE "describe|it\(" test/ --include="*<feature>*"

# Check review status
git log --oneline --grep="codex-review" -- <related_files>

AC-Form Preflight (all modes, unconditional)

This runs in every update mode--update with or without --verify-ac, and --update-all (its step 2). It is defined here, outside the verify-only phase, because that phase declares itself "skipped otherwise": a reader following the mode instructions would otherwise skip the only definition of the check and reach mutation logic with an unparsed AC set.

Order: Phase 0 freeze check → this preflight → any status, Progress-table or checkbox mutation.

That is the whole of what it gates, and the narrowness is deliberate. An authorized factual correction — Phase 4.5's exception: a wrong path, a wrong date, an unfilled template placeholder — runs after Phase 0 and does not pass through this preflight, because it derives nothing from the AC set and asks nothing of it. Gating it here would revoke the one edit Phase 4.5 and /update-docs § Step 1.5 both keep reachable, and revoke it exactly where it is needed most: a ticket recording its ACs as an evidence table has no parsed checkboxes, so it would become the one ticket whose wrong path can never be corrected. Such a correction changes the authorized fact and Progress.Note only, and says so in the report.

Read the ticket's ACs per § Live Checkbox ACs. If there is no readable live checkbox AC set — no ## Acceptance Criteria section at all (docs/features/auto-loop-evolution/requests/2026-08-04-degraded-writer-lost-update.md is a real one); the section present but containing no checkbox items; ACs recorded as an evidence table (docs/features/scope-discipline/requests/2026-08-15-scope-discipline-implementation.md); or any other form this procedure cannot parse — or the section contains a checkbox-like item outside that grammar at all (* [ ], + [ ], 1. [ ], an item indented past three spaces), or mixes task-list items with an evidence table — then no status mutation: report it and take the ⚠️ Need Human exit. Never call an unparsed AC set empty, and never derive a status from one — "every AC is checked" is vacuously true of nothing, and that is how a ticket with no ACs at all would be promoted.

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
188
Forks
24
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
create-request
Source
github.com/sd0xdev/sd0x-harness