git:20261017.2cde835 to git:20261017.19ede76

233 added, 17 removed. Audit A to A.

---
name: ase-task-edit
- argument-hint: "[--help|-h] [--plan|-p <option>] [--dry|-d] [--next|-n <option>[,...]] [<id> | <id>: <instruction> | <instruction>]"
+ argument-hint: "[--help|-h] [--plan|-p <option>] [--mode|-m auto|craft|refactor|resolve|specify] [--approach|-a] [--unverified|-u] [--next|-n <option>[,...]] [<id> | <id>: <instruction> | <instruction> | <issue-id>]"
description: >
Iteratively edit and refine a named plan for a task through a
- conversational loop. Each round, the current plan is shown and the
- user is asked whether to keep refining, mark the plan as done, or
- proceed to the implementation or draft. Use when the user wants
- to plan a task purely through chat-driven refinement.
+ conversational loop. A new plan is optionally composed along the
+ chosen one of several proposed crafting, refactoring, resolution, or
+ specification approaches. Each round, the current plan is shown and the user is
+ asked whether to keep refining, mark the plan as done, or proceed to
+ the implementation or draft. Use when the user wants to plan a task
+ purely through chat-driven refinement, or wants a plan to "craft" a
+ new feature, "refactor" the code base, or "resolve" a problem (also
+ from a bare analyzer issue id like "P1").
user-invocable: true
disable-model-invocation: false
effort: high
---
@${CLAUDE_SKILL_DIR}/../../meta/ase-control.md
@${CLAUDE_SKILL_DIR}/../../meta/ase-skill.md
@${CLAUDE_SKILL_DIR}/../../meta/ase-dialog.md
@${CLAUDE_SKILL_DIR}/../../meta/ase-getopt.md
<purpose name="ase-task-edit">
Iteratively Edit a Task Plan
</purpose>
<expand name="getopt"
arg1="ase-task-edit"
- arg2="--plan|-p=(none|OVERWRITE|REFINE|PRESERVE) --dry|-d --next|-n=(none|DONE|GRILL|DRAFT|IMPLEMENT)... --int-reuse-task --int-source-dir=">
+ arg2="--plan|-p=(none|OVERWRITE|REFINE|PRESERVE) --mode|-m=(auto|craft|refactor|resolve|specify) --approach|-a --unverified|-u --next|-n=(none|DONE|GRILL|DRAFT|IMPLEMENT)... --int-reuse-task --int-source-dir=">
$ARGUMENTS
</expand>
<objective>
Establish and refine the *task plan* purely through a *chat-driven
loop*. The user steers each round via an interactive dialog that offers
continued refinement, finalization, or hand-off to implementation or
draft.
</objective>
@${CLAUDE_SKILL_DIR}/../../meta/ase-format-task.md
@${CLAUDE_SKILL_DIR}/../../meta/ase-format-meta.md
@${CLAUDE_SKILL_DIR}/../../meta/ase-common-task.md
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-common-approach.md
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-tenets.md
Procedure
---------
<define name="apply-refinement">
+ Determine the *kind of change* of the refined plan:
+
+ - If <getopt-option-mode/> is `craft`, `refactor`, `resolve`, or
+ `specify`: Set <task-kind/> to `CRAFTING`, `REFACTORING`,
+ `RESOLVING`, or `SPECIFYING` correspondingly, and set
+ <task-kind-changed>true</task-kind-changed>.
+
+ - Else if <issue-id/> is not empty (`auto` with a retrieved analyzer
+ issue): Set <task-kind/> to `RESOLVING`, as the refinement fixes a
+ reported problem, and set <task-kind-changed>true</task-kind-changed>.
+
+ - Else (`auto`): Set <task-kind/> to the value of the `Kind:`
+ frontmatter key of <task-content/> (or, if it is absent or invalid,
+ *infer* it from the plan content, defaulting to `CRAFTING`), and set
+ <task-kind-changed>false</task-kind-changed>.
+
+ You *MUST* then first forget all previous internalized tenets and then
+ freshly internalize and strictly honor the **GENERIC TENETS** and the
+ **<task-kind/> TENETS** of the **ASE Tenets** in the following
+ refinement of the plan. Do not output anything.
+
+ <if condition="<task-kind/> is equal `SPECIFYING`">
+ <expand name="task-spec-format"/>
+ </if>
+
Treat the <instruction/> as a *refinement instruction* for
the plan, and update <task-content/> in-place by *applying* the
requested <instruction/> to the *plan*.
When refining the plan this way, preserve the overall structure of the
plan and only modify what the user actually requested. Do *not* rewrite
unrelated sections of the plan.
<if condition="<getopt-option-int-source-dir/> is not empty">
The *code basis* of the task is the separate working copy
<getopt-option-int-source-dir/> (e.g. a checkout of the branch of its
`Source` key): read every project file the <instruction/> requires
*exclusively* from there, instead of from the current working copy.
</if>
Attachment blocks of the "backmatter" are *never* dropped by a
refinement, unless the <instruction/> explicitly asks for it. Their
`Data` payloads are *elided* to `[elided: <n/> lines]` markers, which
you *MUST* keep *verbatim*, as `ase_task_save` restores them. Only if
the <instruction/> requires reading or changing the payload of an
attachment, fetch it via the `ase_task_attachment(id:
"<ase-task-id/>", type: "<type/>")` tool of the `ase` MCP server (with
<type/> being the value of its `Type` key), and replace its marker with
the *complete* changed payload as a `|4+` (or `|4-`) literal block
scalar according to the plan <format/>. *Remember* every attachment block whose content the
applied <instruction/> changed as *touched*, so its `Modified` key is
refreshed together with the frontmatter in step 3.1. An attachment the
<instruction/> did not change stays *verbatim* -- an implementation
draft attachment (`Type` key value `text/x-diff; charset=utf-8;
kind="draft"`, from `ase-task-implement --draft`) hence
turns *stale* through a "body" change by its `Modified` key falling
behind the frontmatter, which step 3.3 reports.
+ <if condition="<task-kind-changed/> is equal `true`">
+ Set the `Kind:` frontmatter key of <task-content/> to <task-kind/> --
+ *creating* the key at its position in the key order of the plan
+ <format/> if it is absent.
+ </if>
+
Set <task-content-dirty>true</task-content-dirty>.
</define>
<define name="generate-plan">
<expand name="task-ground-plan" arg1="<getopt-option-int-source-dir/>"/>
+ Determine the *kind of change* of the new plan:
+
+ - If <getopt-option-mode/> is `craft`, `refactor`, `resolve`, or
+ `specify`: Set <task-kind/> to `CRAFTING`, `REFACTORING`,
+ `RESOLVING`, or `SPECIFYING` correspondingly.
+
+ - Else if <issue-id/> is not empty (`auto` with a retrieved analyzer
+ issue): Set <task-kind/> to `RESOLVING`, as the plan fixes a
+ reported problem.
+
+ - Else (`auto`): *Infer* the <task-kind/> from the <instruction/>:
+ set to `SPECIFYING` if the plan predominantly creates or revises the
+ statements of the `SPEC` artifacts, set to `RESOLVING` if it
+ predominantly fixes a defect, set to `REFACTORING` if it
+ predominantly re-structures existing artifacts without changing
+ their observable behavior, and set to `CRAFTING` otherwise (also
+ the default if the inference stays inconclusive).
+
+ Set <approach-kind/> to `specification`, `resolution`, `refactoring`,
+ or `crafting` for the <task-kind/> `SPECIFYING`, `RESOLVING`,
+ `REFACTORING`, or `CRAFTING` correspondingly. You *MUST* then first
+ forget all previous internalized tenets and then freshly internalize
+ and strictly honor the **GENERIC TENETS** and the **<task-kind/>
+ TENETS** of the **ASE Tenets** in the following composition of the
+ plan. Do not output anything.
+
+ <if condition="<task-kind/> is equal `SPECIFYING`">
+ <expand name="task-spec-format"/>
+ </if>
+
+ <if condition="
+ <task-kind/> is equal `RESOLVING` and
+ <ase-project-boxing/> is not equal `black` and
+ <ase-headless/> is not equal `true`
+ ">
+ Investigate and *figure out details* related to the problem of the
+ <instruction/> and report them with the following <template/>:
+
+ <template>
+ <ase-tpl-bullet-signal/> **PROBLEM CONTEXT**: *<context/>*
+ <affected-code-excerpt/>
+ <optional-diagram/>
+
+ <ase-tpl-bullet-signal/> **PROBLEM DETAILS**: *<summary/>*
+ ● [...]
+ ● [...]
+ ● [...]
+ </template>
+
+ Hints:
+
+ - Give a short one-sentence <context/> of the problem plus a short
+ excerpt of the affected code <affected-code-excerpt/>.
+
+ - Give a short one-sentence <summary/> of the problem plus *precise*
+ but *brief* code processing information to understand the problem.
+ Try to keep the number of bullet points (●) in the range of 1-4.
+
+ - In case of a *complex context situation* with complex *structure*
+ (layout, components, dependencies, etc.), complex *control flow*
+ (branching, concurrency, etc.), complex *state machine* (states,
+ transitions, etc.), complex *data flow* (actors, messages, etc.), or
+ complex *data structure* (classes, entities, relationships, etc.),
+ visualize it with an optional diagram <optional-diagram/> by
+ building a Mermaid specification <mermaid-spec/> (e.g. `flowchart
+ TB`, `stateDiagram-v2`, `sequenceDiagram`, `classDiagram`, or
+ `erDiagram`, depending on intent) and dispatching the rendering
+ to the `ase-meta-diagram` sub-agent by calling the tool
+ `Agent(description: "Diagram Rendering", subagent_type:
+ "ase:ase-meta-diagram", prompt: <mermaid-spec/>,
+ run_in_background: false)`, reproducing its
+ returned fenced code block verbatim. Omit <optional-diagram/>
+ entirely for simple or purely local situations.
+ </if>
+
+ <if condition="<getopt-option-approach/> is equal `true`">
+ Determine the overall approach of the new plan, based on the
+ <instruction/> and the grounding in the project:
+
+ <expand name="approach-select"
+ arg1="<approach-kind/>"
+ arg2="◉ task: **<ase-task-id/>**"></expand>
+
+ If <chosen-approach/> is empty, only output the following <template/> and
+ then immediately *STOP* processing the entire current skill:
+
+ <template>
+ ⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **plan generation cancelled**
+ </template>
+ </if>
+ <else>
+ Set <chosen-approach></chosen-approach> (empty). Do not output anything.
+ </else>
+
Create a new plan from scratch and store the result as
<task-content/> by closely following the defined plan format
<format/> and injecting into it all the information from
- the <instruction/>, all decisions you derived from the
- <instruction/>, and the grounding in the project.
+ the <instruction/>, the <chosen-approach/> (if not empty), all
+ decisions you derived from the <instruction/> and the <chosen-approach/>, and
+ the grounding in the project. Set the `Kind:` frontmatter key to
+ <task-kind/>.
- <if condition="<getopt-option-dry/> is equal `true`">
+ <if condition="<task-kind/> is equal `RESOLVING`">
+ The plan *MUST* carry code references, a precise description of the
+ problem, the resolution approach, a preview of the *unified
+ diff* of the necessary code changes, and -- unless
+ <getopt-option-unverified/> is equal `true` -- a possible way to verify the
+ success of the resolution.
+ </if>
+
+ <if condition="<getopt-option-unverified/> is equal `true`">
You *MUST* completely omit the `## VERIFICATION (WHEN)` section
(including its heading and all of its bullet points) from
<task-content/>.
</if>
Call the `ase_timestamp(format: "yyyy-LL-dd HH:mm")` tool of the
`ase` MCP server and use the `text` field of its response
for fresh <timestamp-created/> and <timestamp-modified/>
information. Then insert the current <ase-task-id/>,
<timestamp-created/>, and <timestamp-modified/> information.
Set <task-content-dirty>true</task-content-dirty>.
</define>
<define name="handoff-args">
Set <args></args> (set args to empty).
<if condition="the plan was saved via `ase_task_save` in step 3.2">
Set <args>--int-reuse-task</args>.
</if>
<if condition="<getopt-option-next/> is not equal `none`">
Set <args><args/> --next <getopt-option-next/></args>
</if>
</define>
1. **Determine Task and Instruction:**
1. Set <instruction><getopt-arguments/></instruction> initially.
+ Set <issue-id></issue-id> (empty),
+ <task-allocated>false</task-allocated>, and
+ <task-origin>task inherited</task-origin>.
Inherit the always existing <ase-task-id/> from the current context.
Inherit the always existing <ase-session-id/> from the current context.
Do not output anything.
- 2. React on task and/or instruction:
+ 2. Resolve a potential analyzer issue:
+ <if condition="
+ <instruction/> has the format `[<id/>:] <candidate/>` where
+ the optional <id/> matches the regexp `^[a-zA-Z0-9#][a-zA-Z0-9#_-]*$` and
+ <candidate/> matches the regexp `^([a-zA-Z][a-zA-Z0-9_]*-)?[PT]\d+$`
+ ">
+ The <candidate/> may be a bare issue identifier (like `P1`,
+ `T1`, or `<prefix>-P1`) previously produced by
+ `ase-code-analyze` or `ase-arch-analyze`. Call the
+ `ase_kv_get(key: "ase-issue-<candidate/>")` tool of the `ase`
+ MCP server to retrieve the persisted problem description. If the
+ returned `text` is non-empty:
+
+ 1. Set <issue-id><candidate/></issue-id> and
+ <instruction><text/></instruction>.
+
+ 2. If <id/> is given, set <ase-task-id><id/></ase-task-id> and
+ <task-origin>task given</task-origin>, and call the
+ `ase_task_id(id: "<ase-task-id/>", session:
+ "<ase-session-id/>")` tool from the `ase` MCP server to
+ switch the task.
+
+ 3. Only output the following <template/>:
+
+ <template>
+ ⧉ **ASE**: ◉ task: **<ase-task-id/>**, ⇌ issue: **<issue-id/>**, ▶ status: **issue retrieved**
+ </template>
+
+ Otherwise, keep <instruction/> unchanged, so it is treated as a
+ task id resp. as an instruction below. Do not output anything.
+ </if>
+
+ 3. React on task and/or instruction:
+
1. <if condition="
+ <issue-id/> is empty and
<instruction/> matches the regexp `^[a-zA-Z0-9#][a-zA-Z0-9#_-]*$`
">
Set <ase-task-id><instruction/></ase-task-id> (set task
id to instruction) and <instruction></instruction> (set
instruction empty), call the `ase_task_id(id: "<ase-task-id/>",
session: "<ase-session-id/>")` tool from the `ase` MCP
server to switch the task, and then only output the
following <template/>:
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **task given**
</template>
</if>
2. <elseif condition="
+ <issue-id/> is empty and
<instruction/> has the format `<id/>: <text/>` where
<id/> matches the regexp `^[a-zA-Z0-9#][a-zA-Z0-9#_-]*$` and
<text/> is *empty*
">
Set <instruction></instruction> (set instruction to empty)
and <ase-task-id><id/></ase-task-id> (set task id to
id) and call the `ase_task_id(id: "<ase-task-id/>", session:
"<ase-session-id/>")` tool from the `ase` MCP server to
switch the task, and then only output the following
<template/>:
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **task given**
</template>
</elseif>
3. <elseif condition="
+ <issue-id/> is empty and
<instruction/> has the format `<id/>: <text/>` where
<id/> matches the regexp `^[a-zA-Z0-9#][a-zA-Z0-9#_-]*$` and
<text/> is *not empty*
">
Set <instruction><text/></instruction> (set instruction to
text) and <ase-task-id><id/></ase-task-id> (set task id
to id) and call the `ase_task_id(id: "<ase-task-id/>", session:
"<ase-session-id/>")` tool from the `ase` MCP server to
switch the task, and then only output the following
<template/>:
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **task given**
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ⇌ instruction: **<instruction/>**, ▶ status: **instruction given**
</template>
</elseif>
4. <elseif condition="
<instruction/> is not empty
">
- Only output the following <template/>:
+ Only output the following <template/>, where <task-origin/>
+ is `task given` if step 1.2 switched the task:
<template>
- ⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **task inherited**
+ ⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **<task-origin/>**
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ⇌ instruction: **<instruction/>**, ▶ status: **instruction given**
</template>
</elseif>
5. <elseif condition="
<instruction/> is empty
">
Only output the following <template/>:
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **task inherited**
</template>
</elseif>
2. **Determine Plan:**
1. Determine any existing plan content:
<if condition="
<getopt-option-int-reuse-task/> is equal `true`
*and* an `ase_task_save(id: '<ase-task-id/>', ...)` tool call
exists earlier in the current session
*and* the `text` *output* field of the most recent such
`ase_task_save` tool call carries a `<task-plan-tag>`
delimiter line
*and* the `text` *argument* of that call carries no `Effort:`
frontmatter key without <hash/> (a bare size like `Effort: M`,
which the task store stamped or dropped on that save, see the
plan <format/>)
">
Set <text/> to the `text` *argument* of the most recent
`ase_task_save(id: '<ase-task-id/>', ...)` tool call -- this
is the *authoring form* of the plan and *MUST NOT* be
confused with the `text` *output* field of that call --
*without* calling `ase_task_load` again. Set
<task-render></task-render> (set the rendering-prepared plan
to empty, as it is re-derived in step 3.2 or 3.3). Set
<task-tag/> to the content enclosed in the `<task-plan-tag>`
delimiter line of the `text` *output* field of that
`ase_task_save` tool call (the *entity tag* of the plan as
saved by it). Set <status>plan reused</status>. Do not
output anything.
</if>
<else>
Call the `ase_task_load(id: "<ase-task-id/>", variant:
"both", tag: true)` tool of the `ase` MCP server to load any existing
plan content in *both* of its forms, with the payloads of all
attachments *elided* to `[elided: <n/> lines]` markers (the
default of its `attachments` argument). From the `text` output
field of this `ase_task_load` tool call, set <text/> to the
content enclosed in the `<task-plan-source>` delimiter lines
(the *authoring form*, the only form which is ever edited and
persisted), set <task-render/> to the content enclosed in
the `<task-plan-render>` delimiter lines (the
*rendering-prepared* form, used for *display only*), and set
<task-tag/> to the content enclosed in the `<task-plan-tag>`
delimiter line (the *entity tag* of the loaded plan, or empty
if absent, as no plan exists yet). The delimiter lines themselves are *never* part of
any form. Do not output anything related to this MCP tool call. Set
<status>plan loaded</status>.
</else>
Set <task-content-dirty>false</task-content-dirty>.
- If <text/> starts with `ERROR:` or `WARNING:`:
Silently ignore the MCP error.
Set <task-content/> to empty.
Set <task-render/> to empty.
Do not output anything.
- If <text/> starts NOT with `ERROR:` and NOT with `WARNING:`:
Set <task-content><text/></task-content> (set task content to text).
Only output the following <template/>:
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **<status/>**
</template>
2. <if condition="<task-content/> is empty AND <instruction/> is empty">
Ask the user interactively, without a special tool, for the
initial plan content with a single question:
`**No plan content yet. What is the task you want to plan?**`
Then set <instruction/> to the response of the user and only
output the following <template/>:
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ⇌ instruction: **<instruction/>**, ▶ status: **instruction given**
</template>
</if>
- 3. <if condition="<task-content/> is not empty AND
+ 3. <if condition="
+ <ase-task-id/> is equal `default` AND
+ <task-content/> is empty AND
+ <instruction/> is not empty
+ ">
+ Call the `ase_task_newid(title: "<title/>", proposal:
+ "<proposal/>")` tool from the `ase` MCP server, where <title/> is
+ a brief title summarizing <instruction/> and <proposal/> is a
+ task id derived from <instruction/>, which consists of two
+ lower-case words concatenated with a `-` character, and set
+ <ase-task-id/> to the `id` field of its response -- the tool
+ derives the id according to the task id scheme of the project,
+ so you *MUST* *NEVER* assemble it yourself. Then call the
+ `ase_task_id(id: "<ase-task-id/>", session: "<ase-session-id/>")`
+ tool from the `ase` MCP server to switch the task, set
+ <task-tag></task-tag> (empty, as no plan exists yet under the
+ new id) and <task-allocated>true</task-allocated>, and only
+ output the following <template/>:
+
+ <template>
+ ⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **task allocated**
+ </template>
+ </if>
+
+ 4. <if condition="<task-content/> is not empty AND
<instruction/> is not empty AND
<instruction/> is not equal <task-content/>">
*Determine previous-plan handling*:
- If <getopt-option-plan/> matches the regex `^(OVERWRITE|REFINE|PRESERVE)$`:
Honor the pre-selection of what to do with the previous plan.
Set <result><getopt-option-plan/></result>.
- If <getopt-option-plan/> is equal to `none`:
In the following, you *MUST* *NOT* use your built-in
<user-dialog-tool/> tool! Instead, you *MUST* just show a
custom dialog according to the expanded `custom-dialog`
definition. You *MUST* closely follow this definition:
<expand name="custom-dialog" arg1="--other">
Previous Plan: Should the previous plan content be overwritten, refined, or preserved?
OVERWRITE: Continue operation, overwrite previous plan.
REFINE: Continue operation, refine previous plan.
PRESERVE: Cancel operation, preserve previous plan.
</expand>
Check the tool <result/> and dispatch accordingly:
- If <result/> is `CANCEL` or `PRESERVE`:
Only output the following <template/> and then immediately
*STOP* processing this skill:
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **plan preserved**
</template>
- If <result/> is `OVERWRITE`:
<expand name="generate-plan"/>
Only output the following <template/> and continue processing:
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **plan overwritten**
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ⇌ instruction: **<instruction/>**, ▶ status: **instruction given**
</template>
- If <result/> is `REFINE`:
<expand name="apply-refinement"/>
Only output the following <template/> and continue processing:
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **plan refined**
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ⇌ instruction: **<instruction/>**, ▶ status: **instruction given**
</template>
- If <result/> matches `OTHER: <text/>`:
Set <instruction><instruction/> <text/></instruction> (append
the user's free-text hint to the existing instruction).
<expand name="apply-refinement"/>
Only output the following <template/> and continue processing:
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **plan refined**
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ⇌ instruction: **<instruction/>**, ▶ status: **instruction given**
</template>
</if>
- 4. <if condition="no line of <task-content/> matches the case-insensitive regex `^\s*#+\s*TASK\b` AND <instruction/> is empty">
+ 5. <if condition="no line of <task-content/> matches the case-insensitive regex `^\s*#+\s*TASK\b` AND <instruction/> is empty">
Set <instruction><task-content/></instruction> (set instruction to task content).
Set <task-content></task-content> (set task content to empty).
Set <task-content-dirty>true</task-content-dirty>.
Do not output anything.
</if>
- 5. <if condition="<task-content/> is empty AND <instruction/> is not empty">
+ 6. <if condition="<task-content/> is empty AND <instruction/> is not empty">
<expand name="generate-plan"/>
Only output the following <template/> and continue processing:
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ⇌ instruction: **<instruction/>**, ▶ status: **instruction given**
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **plan generated**
</template>
</if>
3. **Iterative Plan Refinement Loop:**
*REPEAT* the following steps from 3.1 up to and including 3.4 in
a *LOOP* until the user selects `DONE`, `GRILL`, `IMPLEMENT`, or
`DRAFT`, or declines/cancels in the dialog of step 3.4:
1. *Update timestamp*:
<if condition="<task-content-dirty/> is 'true'">
Update <timestamp-modified/> with the current time in
ISO-style format, which has to be determined by calling the
`ase_timestamp(format: "yyyy-LL-dd HH:mm")` tool of the `ase`
MCP server and using the `text` field of its response. If the
frontmatter of <task-content/> carries a `Modified:` key *and*
the refinement changed the "body" (not only frontmatter keys or
attachments), update it with the new <timestamp-modified/>
value, as the key tracks "body" changes only. Then set the
`Modified:` key of every attachment block *touched* by the
refinement (see `apply-refinement`) to the very same
<timestamp-modified/> value -- *creating* the key at its position
in the key order of the plan <format/> if the block does not
carry it yet -- and forget the touched marks again, so a changed
attachment never falls behind the frontmatter.
Do not output anything.
</if>
2. *Persist plan*:
<if condition="<task-content-dirty/> is 'true'">
Call the `ase_task_save(id: "<ase-task-id/>", text:
"<task-content/>", render: true, tag: true)` tool of the `ase` MCP server --
if <task-tag/> is not empty, additionally with the argument
`base: "<task-tag/>"`, so the save is refused if the plan was
changed meanwhile by anybody else (instead of silently
overwriting that change), and if <task-tag/> is empty (no plan
existed yet), additionally with the argument `create: true`, so
the save is refused if the plan was created meanwhile by anybody
else -- to
persist the current plan -- <task-content/> always is the
*authoring form* of the plan and hence is persisted *as is* --
and then set <task-content-dirty>false</task-content-dirty>
- again. This `ase_task_save` MCP tool call is the *only*
- permitted way to persist the plan -- *NEVER* write the plan
+ again. If this call fails because the task already exists *and*
+ <task-allocated/> is `true` (a concurrent session took the
+ allocated id), allocate and switch to a new <ase-task-id/>
+ exactly as in step 2.3, set the `Id:` frontmatter key of
+ <task-content/> to it, and save again. This `ase_task_save` MCP
+ tool call is the *only* permitted way to persist the plan -- *NEVER* write the plan
file via `Write`/`Edit` or by executing a shell command.
Finally, *always* set <task-tag/> to the content enclosed in the
`<task-plan-tag>` delimiter line of the `text` *output* field of
this `ase_task_save` tool call (the entity tag of the just-saved
plan, to be passed as `base` on the next save of every
subsequent loop round), and set <task-render/> to the remaining
`text` *output* field
of this `ase_task_save` tool call (without this delimiter line) -- the rendering-prepared form
of the just-persisted plan, which is for *display only* and
*MUST NOT* be confused with the `text` *argument* passed into
that call -- so the rendering in step 3.3 stays consistent across
all loop rounds. Then take over the `Effort:` key *as stored*
into the authoring form, as the task store stamps a key without
<hash/> or drops a stale one on save (see the plan <format/>):
set the `Effort:` frontmatter key of <task-content/> to the one
of the frontmatter of <task-render/> (rendered from the stored
plan) -- *replacing* it, *creating* it at its position in the key
order of the plan <format/>, or *removing* it if <task-render/>
carries none -- changing *nothing else* of <task-content/> and
leaving <task-content-dirty/> untouched. Do not output anything
related to this MCP tool call except the following <template/>:
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **plan saved**
</template>
+
+ Then set <task-allocated>false</task-allocated>, as the
+ allocated id is now taken by the saved plan. If <issue-id/> is
+ not empty, call the `ase_kv_delete(key: "ase-issue-<issue-id/>")`
+ tool of the `ase` MCP server to remove the now-planned analyzer
+ result from the key/value store and set <issue-id></issue-id>
+ (empty). Do not output anything related to these steps.
</if>
3. *Render plan*:
If <ase-headless/> is `true`, nobody reads the rendering, so
silently *skip* this entire step 3.3 (no MCP tool call and no
output at all) and continue with step 3.4.
<if condition="<task-render/> is empty">
Call the `ase_markdown_prepare(text: "<task-content/>")` tool of
the `ase` MCP server and set <task-render/> to the `text` output
field of this tool call. Do not output anything related to this
MCP tool call.
</if>
Treat <task-render/> as *verbatim* Markdown.
For the *rendering only*, drop the leading *frontmatter* block --
both `---` delimiters and all of their keys -- and instead place
the following column-aligned glyph lines *before* the
`# TASK: <title/>` heading, separated from it by an empty line,
omitting the line of every key absent from the frontmatter and
always omitting the `Type` key. The glyph lines *MUST* stay
*above* the heading, exactly where the frontmatter block sits in
the plan file, and *MUST NOT* be moved below it. This keeps the
`---` delimiters from rendering as a horizontal rule plus a
*setext heading*. This rewrite is *display-only* and *MUST NOT*
change <task-render/> or <task-content/> itself:
<format>
◉ **Id:** <task-id/>
⎈ **Created:** <timestamp-created/>
⚙ **Modified:** <timestamp-modified/>
⊞ **Group:** <task-group/>
◷ **Phase:** <task-phase/>
⇢ **After:** <task-after/>
◐ **Status:** <task-status/>
☯ **Kind:** <task-kind/>
⚖ **Effort:** <task-effort/>
⚑ **Tags:** <task-tags/>
⇤ **Source:** <task-source/>
⇢ **Changeset:** <task-changeset/>
⇥ **Target:** <task-target/>
</format>
Only output the following <template/>, so the user
can read the plan and react to it. Do *not* truncate,
summarize, or partially show the plan. Use the
following <template/>:
<template>
<ase-tpl-head title="TASK" subtitle="<task-id/>"/>
<task-render/>
<ase-tpl-foot title="TASK" subtitle="<task-id/>"/>
</template>
<if condition="the backmatter of <task-content/> contains an attachment
block with the `Type` key value `text/x-diff; charset=utf-8; kind="draft"`
which is *stale* according to the plan <format/> (its `Modified` key
is absent or older than the `Modified` key of the frontmatter)">
Directly *after* this <template/>, only output the following
<template/> and then give the corrective hint by expanding the
subsequent construct (which, depending on the configured
<ase-guidance-level/>, may expand into nothing and hence emit
no output at all):
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ WARNING: implementation draft attachment is **stale** (older than the plan)
</template>
<ase-tpl-hint level="minimal">
Run `/ase-task-implement --draft` again to re-create the implementation draft for the changed plan, as `/ase-task-integrate --draft` refuses a stale draft.
</ase-tpl-hint>
</if>
4. *Determine next step*:
- If <getopt-option-next/> is not equal to `none`:
Treat <getopt-option-next/> as a comma-separated chronological
list of pre-selected next-step tokens. *Split* it on `,`,
take the *first* token as <head/>, and store the remaining
tokens (joined back with `,`, or `none` if empty) into
<getopt-option-next/> so subsequent loop iterations or
downstream skills can consume the tail.
- If <head/> matches the regex `^(DONE|GRILL|IMPLEMENT|DRAFT)$`:
Honor the pre-selected token.
Set <result><head/></result>.
Set <instruction></instruction> (clear the instruction, as
any instruction carried in via the arguments was already
applied to the plan in step 2 before this loop), so that a
later `OTHER: <text/>` refinement correctly starts from a
*fresh* refinement instruction below.
- else:
Only output the following <template/> and then immediately
*STOP* processing the entire current skill:
<template>
⧉ **ASE**: ☻ skill: **ase-task-edit**, ▶ ERROR: invalid `--next` token: **<head/>**
</template>
- If <getopt-option-next/> is equal to `none`:
In the following, you *MUST* *NOT* use your built-in
<user-dialog-tool/> tool! Instead, you *MUST* just show a
custom dialog according to the expanded `custom-dialog`
definition. You *MUST* closely follow this definition:
<expand name="custom-dialog" arg1="--other">
Next Step: How would you like to proceed with the plan?
DONE: Mark plan finalized, exit planning loop.
GRILL: Hand off plan to grilling.
DRAFT: Hand off plan to implementation drafting.
IMPLEMENT: Hand off plan to implementation.
</expand>
Check the tool <result/> and dispatch accordingly:
- If <result/> is `DONE`:
*Break* out of the *loop*, only output the following <template/>
and then *STOP*. Do *not* implement the plan.
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **plan finalized -- done**
</template>
- If <result/> is `GRILL`:
*Break* out of the *loop*.
<expand name="handoff-args"/>
Only output the following <template/> and then call the
`Skill(skill: "ase:ase-task-grill", args: "<args/>")` tool
to *grill* the finalized plan.
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **plan finalized -- hand-off to grilling**
</template>
- If <result/> is `DRAFT`:
*Break* out of the *loop*.
<expand name="handoff-args"/>
Set <args><args/> --draft</args>. Only output the following
<template/> and then call the
`Skill(skill: "ase:ase-task-implement", args: "<args/>")` tool
to *draft* the implementation of the finalized plan.
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **plan finalized -- hand-off to implementation draft**
</template>
- If <result/> is `IMPLEMENT`:
*Break* out of the *loop*.
<expand name="handoff-args"/>
Only output the following <template/> and then call the
`Skill(skill: "ase:ase-task-implement", args: "<args/>")` tool
to *apply* the finalized plan.
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **plan finalized -- hand-off to implementation**
</template>
- If <result/> matches `OTHER: <text/>`:
Set <instruction><text/></instruction> (replace existing instruction).
<expand name="apply-refinement"/>
Finally, only output the following <template/> and then
*continue* the *loop* at step **3.1**!
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ⇌ instruction: **<instruction/>**, ▶ status: **plan refined**
</template>
- If <result/> is `CANCEL`:
*Break* out of the *loop*, only output the following <template/>
and then *STOP*. Do *not* implement the plan.
<template>
⧉ **ASE**: ◉ task: **<ase-task-id/>**, ▶ status: **plan refinement cancelled**
</template>