@rse/ase 0.9.51 → 0.9.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dst/ase-task.js +7 -2
  2. package/package.json +7 -7
  3. package/plugin/.claude-plugin/plugin.json +1 -1
  4. package/plugin/.codex-plugin/plugin.json +1 -1
  5. package/plugin/.github/plugin/plugin.json +1 -1
  6. package/plugin/agents/ase-code-analyze.md +4 -6
  7. package/plugin/agents/ase-code-lint.md +4 -6
  8. package/plugin/agents/ase-docs-proofread.md +4 -6
  9. package/plugin/agents/ase-meta-chat.md +3 -3
  10. package/plugin/agents/ase-meta-proximity.md +2 -2
  11. package/plugin/agents/ase-meta-review.md +4 -5
  12. package/plugin/agents/ase-meta-search.md +2 -2
  13. package/plugin/etc/stx.conf +2 -2
  14. package/plugin/meta/ase-common-dissect.md +110 -0
  15. package/plugin/meta/ase-common-task.md +5 -3
  16. package/plugin/meta/ase-control.md +53 -0
  17. package/plugin/meta/ase-format-task.md +6 -0
  18. package/plugin/meta/ase-skill.md +46 -23
  19. package/plugin/package.json +2 -2
  20. package/plugin/skills/ase-arch-analyze/SKILL.md +23 -12
  21. package/plugin/skills/ase-arch-analyze/help.md +16 -0
  22. package/plugin/skills/ase-arch-discover/SKILL.md +2 -2
  23. package/plugin/skills/ase-code-analyze/SKILL.md +27 -18
  24. package/plugin/skills/ase-code-analyze/help.md +15 -0
  25. package/plugin/skills/ase-code-craft/SKILL.md +2 -2
  26. package/plugin/skills/ase-code-dissect/SKILL.md +380 -0
  27. package/plugin/skills/ase-code-dissect/help.md +121 -0
  28. package/plugin/skills/ase-code-explain/SKILL.md +2 -2
  29. package/plugin/skills/ase-code-insight/SKILL.md +2 -2
  30. package/plugin/skills/ase-code-lint/SKILL.md +2 -2
  31. package/plugin/skills/ase-code-refactor/SKILL.md +2 -2
  32. package/plugin/skills/ase-code-resolve/SKILL.md +2 -2
  33. package/plugin/skills/ase-docs-distill/SKILL.md +2 -2
  34. package/plugin/skills/ase-docs-proofread/SKILL.md +2 -2
  35. package/plugin/skills/ase-help-intent/SKILL.md +2 -2
  36. package/plugin/skills/ase-help-skill/SKILL.md +2 -2
  37. package/plugin/skills/ase-help-skill/catalog.md +3 -0
  38. package/plugin/skills/ase-meta-brainstorm/SKILL.md +2 -2
  39. package/plugin/skills/ase-meta-changelog/SKILL.md +2 -2
  40. package/plugin/skills/ase-meta-chat/SKILL.md +2 -2
  41. package/plugin/skills/ase-meta-commit/SKILL.md +2 -2
  42. package/plugin/skills/ase-meta-config/SKILL.md +2 -2
  43. package/plugin/skills/ase-meta-diaboli/SKILL.md +2 -2
  44. package/plugin/skills/ase-meta-diff/SKILL.md +2 -2
  45. package/plugin/skills/ase-meta-eli5/SKILL.md +2 -2
  46. package/plugin/skills/ase-meta-evaluate/SKILL.md +2 -2
  47. package/plugin/skills/ase-meta-proximity/SKILL.md +2 -2
  48. package/plugin/skills/ase-meta-quorum/SKILL.md +2 -2
  49. package/plugin/skills/ase-meta-quotes/SKILL.md +2 -2
  50. package/plugin/skills/ase-meta-review/SKILL.md +2 -2
  51. package/plugin/skills/ase-meta-search/SKILL.md +2 -2
  52. package/plugin/skills/ase-meta-steelman/SKILL.md +2 -2
  53. package/plugin/skills/ase-meta-why/SKILL.md +2 -2
  54. package/plugin/skills/ase-meta-workflow/SKILL.md +378 -0
  55. package/plugin/skills/ase-meta-workflow/help.md +117 -0
  56. package/plugin/skills/ase-meta-workflow/sample.md +70 -0
  57. package/plugin/skills/ase-meta-workflow/workflow.txt +97 -0
  58. package/plugin/skills/ase-sync-export/SKILL.md +2 -2
  59. package/plugin/skills/ase-sync-import/SKILL.md +2 -2
  60. package/plugin/skills/ase-sync-reconcile/SKILL.md +2 -2
  61. package/plugin/skills/ase-task-condense/SKILL.md +26 -6
  62. package/plugin/skills/ase-task-delete/SKILL.md +2 -2
  63. package/plugin/skills/ase-task-dissect/SKILL.md +299 -0
  64. package/plugin/skills/ase-task-dissect/help.md +114 -0
  65. package/plugin/skills/ase-task-edit/SKILL.md +6 -4
  66. package/plugin/skills/ase-task-grill/SKILL.md +6 -4
  67. package/plugin/skills/ase-task-id/SKILL.md +2 -2
  68. package/plugin/skills/ase-task-implement/SKILL.md +2 -2
  69. package/plugin/skills/ase-task-list/SKILL.md +2 -2
  70. package/plugin/skills/ase-task-preflight/SKILL.md +2 -2
  71. package/plugin/skills/ase-task-reboot/SKILL.md +12 -6
  72. package/plugin/skills/ase-task-rename/SKILL.md +2 -2
  73. package/plugin/skills/ase-task-view/SKILL.md +2 -2
package/dst/ase-task.js CHANGED
@@ -451,7 +451,8 @@ export class TaskMCP {
451
451
  mcp.registerTool("ase_task_save", {
452
452
  title: "ASE task save",
453
453
  description: "Persist a task as `text` under `id`. " +
454
- "Overwrites any existing task for the same `id`.",
454
+ "Overwrites any existing task for the same `id`. " +
455
+ "Returns the persisted task as `text`, prepared for improved rendering.",
455
456
  inputSchema: {
456
457
  id: z.string()
457
458
  .describe("task identifier (allowed characters: A-Z, a-z, 0-9, '_', '-')"),
@@ -461,8 +462,12 @@ export class TaskMCP {
461
462
  }, async (args) => {
462
463
  try {
463
464
  Task.save(this.log, args.id, args.text);
465
+ /* return the prepared content, so a caller reusing the
466
+ just-saved plan instead of re-loading it still receives
467
+ the rendering-prepared variant */
468
+ const text = Markdown.prepare(args.text);
464
469
  return {
465
- content: [{ type: "text", text: `OK: saved task "${args.id}"` }]
470
+ content: [{ type: "text", text }]
466
471
  };
467
472
  }
468
473
  catch (err) {
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "homepage": "https://ase.tools",
7
7
  "repository": { "url": "git+https://github.com/rse/ase.git", "type": "git" },
8
8
  "bugs": { "url": "https://github.com/rse/ase/issues" },
9
- "version": "0.9.51",
9
+ "version": "0.9.53",
10
10
  "license": "Apache-2.0",
11
11
  "author": {
12
12
  "name": "Dr. Ralf S. Engelschall",
@@ -23,14 +23,14 @@
23
23
  "eslint-plugin-promise": "7.3.0",
24
24
  "eslint-plugin-import": "2.32.0",
25
25
  "neostandard": "0.13.0",
26
- "globals": "17.7.0",
26
+ "globals": "17.8.0",
27
27
  "typescript": "6.0.3",
28
28
 
29
29
  "@rse/stx": "1.1.6",
30
30
  "nodemon": "3.1.14",
31
31
  "shx": "0.4.0",
32
32
 
33
- "@types/node": "26.1.1",
33
+ "@types/node": "26.1.2",
34
34
  "@types/luxon": "3.7.2",
35
35
  "@types/which": "3.0.4",
36
36
  "@types/update-notifier": "6.0.8",
@@ -42,18 +42,18 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "commander": "15.0.0",
45
- "@dotenvx/dotenvx": "2.18.0",
45
+ "@dotenvx/dotenvx": "2.19.1",
46
46
  "yaml": "2.9.0",
47
47
  "valibot": "1.4.2",
48
- "execa": "10.0.0",
48
+ "execa": "10.0.1",
49
49
  "mkdirp": "3.0.1",
50
50
  "@hapi/hapi": "21.4.10",
51
51
  "beautiful-mermaid": "1.1.3",
52
52
  "cli-table3": "0.6.5",
53
- "chalk": "5.6.2",
53
+ "chalk": "6.0.0",
54
54
  "pretty-ms": "9.3.0",
55
55
  "luxon": "3.7.2",
56
- "@modelcontextprotocol/sdk": "1.29.0",
56
+ "@modelcontextprotocol/sdk": "1.30.0",
57
57
  "json-asty": "1.3.4",
58
58
  "zod": "4.4.3",
59
59
  "which": "7.0.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.51",
3
+ "version": "0.9.53",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.51",
3
+ "version": "0.9.53",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.51",
3
+ "version": "0.9.53",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -248,15 +248,13 @@ Workflow
248
248
  }
249
249
  </template>
250
250
 
251
- 5. Return *exclusively* a single fenced JSON block (no prose,
252
- no preamble, no summary) of the following shape:
251
+ 5. You *MUST* *NOT* propose, apply, or render any code
252
+ changes yourself. Instead, return *exclusively* as the last message
253
+ a single JSON block (no markdown, no prose, no preamble, no summary)
254
+ of the following shape:
253
255
 
254
256
  ```json
255
257
  [
256
258
  <problems/>
257
259
  ]
258
260
  ```
259
-
260
- 6. You *MUST* *NOT* propose, apply, or render any code
261
- changes yourself.
262
-
@@ -393,15 +393,13 @@ Workflow
393
393
  }
394
394
  </template>
395
395
 
396
- 5. Return *exclusively* a single fenced JSON block (no prose,
397
- no preamble, no summary) of the following shape:
396
+ 5. You *MUST* *NOT* propose, apply, or render any code
397
+ changes yourself. Instead, return *exclusively* as the last message
398
+ a single JSON block (no markdown, no prose, no preamble, no summary)
399
+ of the following shape:
398
400
 
399
401
  ```json
400
402
  [
401
403
  <problems/>
402
404
  ]
403
405
  ```
404
-
405
- 6. You *MUST* *NOT* propose, apply, or render any code
406
- changes yourself.
407
-
@@ -94,15 +94,13 @@ Workflow
94
94
  }
95
95
  </template>
96
96
 
97
- 3. Return *exclusively* a single fenced JSON block (no prose,
98
- no preamble, no summary) of the following shape:
97
+ 3. You *MUST* *NOT* propose, apply, or render any document
98
+ changes yourself. Instead, return *exclusively* as the last message
99
+ a single JSON block (no markdown, no prose, no preamble, no summary)
100
+ of the following shape:
99
101
 
100
102
  ```json
101
103
  [
102
104
  <problems/>
103
105
  ]
104
106
  ```
105
-
106
- 4. You *MUST* *NOT* propose, apply, or render any document
107
- changes yourself.
108
-
@@ -54,7 +54,7 @@ tools:
54
54
  </template>
55
55
 
56
56
  4. Now call the MCP tool `query(prompt: <query/>)` from the MCP server
57
- <server/> and then return its result `text` *verbatim* and
58
- *without any modifications*. Especially, do *NOT* add or remove
59
- any text to the MCP server response on your own and do not
57
+ <server/> and then return its result `text` *verbatim* and *without
58
+ any modifications* as the last message. Especially, do *NOT* add or
59
+ remove any text to the MCP server response on your own and do not
60
60
  interpret the result in any way.
@@ -115,8 +115,8 @@ store those facts in the placeholder named `<arg2/>`.
115
115
  mere synonym or spelling variant of it. You *MUST* *NOT* output
116
116
  anything related to this step.
117
117
 
118
- 4. Return *exclusively* the following <template/> (no prose, no
119
- preamble, no summary, and no Markdown formatting):
118
+ 4. Return *exclusively* as the last message the following <template/>
119
+ (no prose, no preamble, no summary, and no Markdown formatting):
120
120
 
121
121
  <template>
122
122
  TOPIC: <topic/>
@@ -172,8 +172,10 @@ Workflow
172
172
  }
173
173
  </template>
174
174
 
175
- 7. Return *exclusively* a single fenced JSON block (no prose, no
176
- preamble, no summary) of the following shape:
175
+ 7. You *MUST* *NOT* propose, apply, or render any document
176
+ changes yourself. Instead, return *exclusively* as the last message
177
+ a single JSON block (no markdown, no prose, no preamble, no summary)
178
+ of the following shape:
177
179
 
178
180
  ```json
179
181
  {
@@ -183,6 +185,3 @@ Workflow
183
185
  ]
184
186
  }
185
187
  ```
186
-
187
- 8. You *MUST* *NOT* propose, apply, or render any code or document
188
- changes yourself.
@@ -9,6 +9,6 @@ tools:
9
9
  - "WebSearch"
10
10
  ---
11
11
 
12
- Just perform the given *query* `$ARGUMENTS` and
13
- give back the *plain responses* without any modifications.
12
+ Just perform the given *query* `$ARGUMENTS` and as the last message give
13
+ back the *plain responses* without any modifications.
14
14
 
@@ -12,9 +12,9 @@ lint
12
12
  # [plugin] build project
13
13
  build : lint
14
14
  ( for name in $(cd skills; ls -1 | grep -v ase-help-intent | sort); do
15
- echo "<skill name=\"$name\">"
15
+ echo "<purpose name=\"$name\">"
16
16
  cat skills/$name/help.md | sed -e '/^## SEE ALSO/,$d'
17
- echo "</skill>"
17
+ echo "</purpose>"
18
18
  done
19
19
  ) >skills/ase-help-intent/data.md
20
20
 
@@ -0,0 +1,110 @@
1
+
2
+ Dissect Skill Common Steps
3
+ ==========================
4
+
5
+ <define name="dissect-derive">
6
+
7
+ *Dissect* <content/> into *cohesive parts* by strictly honoring the
8
+ following ruleset:
9
+
10
+ 1. *Separate domain-wise and logically*: every part *MUST* be a
11
+ *self-contained* unit of work with a *single*, coherent purpose (one
12
+ domain, one concern, one logical change), so it can be implemented,
13
+ reviewed, and committed entirely *on its own*. A *technical* split
14
+ -- one part per file, per directory, per file type, or per technical
15
+ layer -- is usually *not* the obvious and intended one: files are
16
+ merely *where* the change lands, while a part is defined by *what*
17
+ it achieves. Cut along the *semantics* first, and let a file-wise
18
+ boundary result only when it *coincides* with a domain boundary.
19
+
20
+ 2. *Bound the part count*: derive at least *2* and at most
21
+ *<getopt-option-max-parts/>* parts. Prefer *fewer* and *larger*
22
+ cohesive parts over *many* and *tiny* ones.
23
+
24
+ 3. *Assign totally and disjointly*: *every* input element of the epic
25
+ *MUST* be assigned to *exactly one* part -- no input element is
26
+ dropped, and no input element occurs in two parts. An input element
27
+ which itself spans *multiple* domains or concerns *MAY* be *split*
28
+ into two or more *sub-elements*, which are then assigned like
29
+ ordinary input elements, provided the sub-elements *together* cover
30
+ the original element *completely*, *never* overlap, and each one
31
+ stays *self-contained* in the input form the calling skill defines.
32
+ Split *only* when rule 1 forces it: an input element whose content
33
+ fits a *single* part stays *unsplit*.
34
+
35
+ 4. *Keep mutually dependent elements together*: input elements which
36
+ only make sense *together* -- they reference each other, one is the
37
+ precondition of the other, or splitting them would leave a part
38
+ broken -- *MUST* land in the *same* part.
39
+
40
+ 5. *Never invent*: parts are formed *exclusively* from the input
41
+ elements of the epic. Do *not* add scope, do *not* re-interpret the
42
+ input elements, and do *not* re-word them beyond what a part-local
43
+ summary requires.
44
+
45
+ 6. *Slug and identify every part*: per part derive a <feature-slug/>
46
+ from its scope, matching the regexp `^[a-z][a-z0-9-]{0,23}$` and
47
+ *unique* across all parts, and then set
48
+ <part-id><arg3/>-<feature-slug/></part-id>, where <arg3/> is the
49
+ *id prefix* the calling skill passed in.
50
+
51
+ 7. *Order for implementation*: order the parts so that a part *never*
52
+ depends on a later one, and number them consecutively as <part-no/>,
53
+ starting at `1`.
54
+
55
+ 8. *Honor the dissection hint*:
56
+ <if condition="<arg2/> is not empty">
57
+ Set <hint><arg2/></hint>. The user explicitly stated *how* the epic
58
+ should be split -- e.g. which input elements belong together, along
59
+ which axis to cut, or how many parts to aim at -- so you *MUST*
60
+ follow this <hint/> as closely as possible and let it *override* the
61
+ default grouping of rule 1. It *MUST NOT* override the rules 2-7,
62
+ though: the part count stays bounded, the assignment stays total and
63
+ disjoint, mutually dependent elements stay together, nothing is
64
+ invented, every part stays uniquely slugged, and the order stays
65
+ dependency-free. If the <hint/> conflicts with one of these rules,
66
+ honor the rule and follow the <hint/> only as far as the rule
67
+ permits.
68
+ </if>
69
+ <else>
70
+ No dissection hint was given, so the grouping follows the rules 1-7
71
+ alone. Do not output anything.
72
+ </else>
73
+
74
+ Per part, additionally derive an *ultra brief* <scope/> (*what* the part
75
+ covers) and an *ultra brief* <rationale/> (*why* exactly these input
76
+ elements form *one* cohesive part). Store the resulting parts in
77
+ <parts/> and their number in <n/>.
78
+
79
+ <if condition="fewer than 2 cohesive parts exist">
80
+ The epic is *not* dissectable, because it carries a *single* cohesive
81
+ purpose (or too few input elements) and splitting it would only produce
82
+ artificial fragments. Only output the following <template/> and then
83
+ immediately *STOP* processing the entire current skill:
84
+
85
+ <template>
86
+ ⧉ **ASE**: ✪ skill: **<arg1/>**, ▶ status: **epic not dissectable**
87
+ </template>
88
+ </if>
89
+
90
+ </define>
91
+
92
+ <define name="dissect-report">
93
+
94
+ Report the derived <parts/> with the following <template/>, emitting
95
+ *one* table row per part in <parts/>, in their derived order. Keep
96
+ <scope/> and <rationale/> each to *one* ultra brief sentence, align all
97
+ column edges of the table, and do *not* output any further explanation:
98
+
99
+ <template>
100
+ <ase-tpl-head title="DISSECTION" subtitle="<arg1/>"/>
101
+
102
+ | Part | Id | Scope | Rationale |
103
+ | --------------- | ------------ | -------- | ------------ |
104
+ | **P<part-no/>** | `<part-id/>` | <scope/> | <rationale/> |
105
+ | [...] | [...] | [...] | [...] |
106
+
107
+ <ase-tpl-foot title="DISSECTION" subtitle="<arg1/>"/>
108
+ </template>
109
+
110
+ </define>
@@ -65,9 +65,11 @@ Task Skill Common Steps
65
65
  *and* a `ase_task_save(id: '<ase-task-id/>', ...)` tool call
66
66
  exists earlier in the current session
67
67
  ">
68
- Set <text/> to the `text` argument of the most recent
69
- `ase_task_save(id: '<ase-task-id/>', ...)` tool call,
70
- *without* calling `ase_task_load` again. Set <status>plan
68
+ Set <text/> to the `text` *output* field of the most recent
69
+ `ase_task_save(id: '<ase-task-id/>', ...)` tool call -- this is
70
+ the rendering-prepared plan content and *MUST NOT* be confused
71
+ with the `text` *argument* passed into that call -- *without*
72
+ calling `ase_task_load` again. Set <status>plan
71
73
  reused</status>. Do not output anything.
72
74
  </if>
73
75
  <else>
@@ -95,3 +95,56 @@ Control Flow Constructs
95
95
  is finished and no further repetitions are performed. This construct
96
96
  is expanded into nothing. Do not output anything.
97
97
 
98
+ - *IMPORTANT*: You *MUST* honor the following control flow construct:
99
+ <agent <attr/>="<value/>" [...]><agent-body/></agent>:
100
+
101
+ This specifies the *invocation* of a *sub-agent* through the
102
+ `Agent` tool. Every XML attribute is passed *verbatim* as the
103
+ identically named parameter of the `Agent` tool (e.g. `description`,
104
+ `subagent_type`, `run_in_background`, `isolation`, `model`), and
105
+ <agent-body/> is passed as its `prompt` parameter.
106
+
107
+ The *sole exception* is the *reserved* attribute `result="<var/>"`,
108
+ which is *not* passed on but instead *binds* the result returned
109
+ by the sub-agent to the placeholder `<<var/>/>`. This construct is
110
+ expanded to the result returned by the sub-agent if `result` is
111
+ *absent*, or into nothing if `result` is *present*. Do not output
112
+ anything else.
113
+
114
+ - *IMPORTANT*: You *MUST* honor the following control flow construct:
115
+ <agent-consolidation [group=<agent-group/>]/>
116
+
117
+ This specifies the merging of all the Git WorkTrees created by the
118
+ <agent/> calls with either are identified with the unique group
119
+ <agent-group/> or all <agent/> calls in the last <parallel/> section
120
+ of the context. After merging a single Git WorkTree, remove the Git
121
+ WorkTree.
122
+
123
+ - *IMPORTANT*: You *MUST* honor the following control flow construct:
124
+ <skill name="<id/>" [args="<args/>"] [result="<var/>"]/>:
125
+
126
+ This specifies the *invocation* of another *skill* through the
127
+ `Skill` tool, with its `skill` parameter set to <id/> and its `args`
128
+ parameter set to <args/> (or to the empty string if the `args`
129
+ attribute is absent).
130
+
131
+ The *reserved* attribute `result="<var/>"` *binds* the result
132
+ returned by the skill to the placeholder `<<var/>/>`, exactly
133
+ as for <agent/>. This construct is *always* *self-closing*: a
134
+ *body-bearing* `<skill>` element is *never* an invocation. This
135
+ construct is expanded to the result returned by the skill if
136
+ `result` is *absent*, or into nothing if `result` is *present*. Do
137
+ not output anything else.
138
+
139
+ - *IMPORTANT*: You *MUST* honor the following control flow construct:
140
+ <parallel><parallel-body/></parallel>:
141
+
142
+ This specifies a <parallel-body/> whose <agent/> and <skill/>
143
+ invocations are *all* dispatched *concurrently*: you *MUST* emit
144
+ them *in one single message* instead of one per turn, and this
145
+ construct is finished only once *all* of them have returned. If two
146
+ or more of these invocations bind the *same* `result` name, the
147
+ corresponding placeholder carries an *array* of their results, in
148
+ the order of their occurrence in <parallel-body/>. This construct is
149
+ expanded to its <parallel-body/>. Do not output anything else.
150
+
@@ -70,3 +70,9 @@ You *MUST* honor the following hints on this *task* format:
70
70
  after about 100 characters per line for better subsequent
71
71
  manual editing.
72
72
 
73
+ - You *MUST* *NEVER* break a line *inside* an inline code span
74
+ <template>`<code/>`</template>, as a code span split across two
75
+ lines renders badly. Instead, break the line *before* its opening
76
+ backtick or *after* its closing backtick, even if this means
77
+ breaking the line noticeably earlier than after 100 characters.
78
+
@@ -209,18 +209,18 @@ MCP Tool Calls
209
209
  Skill Identification
210
210
  --------------------
211
211
 
212
- - *IMPORTANT*: Set <skill></skill> (set to empty)
212
+ - *IMPORTANT*: Set <purpose></purpose> (set to empty)
213
213
  and <skill-name></skill-name> (set name to empty).
214
214
 
215
- In case <skill/> later becomes *not* empty by defining it as <skill
216
- name="<name/>"><body/></skill>, set <skill-name><name/></skill-name>
217
- (set skill name to name), and then (but only if ((`$1` is *NOT* equal
218
- to `-h` or `--help`) *AND* (<ase-guidance-level/> is equal to `normal`
219
- or `verbose`))) you *MUST* once output the following output
220
- <template/>:
215
+ In case <purpose/> later becomes *not* empty by defining it as
216
+ <purpose name="<name/>"><body/></purpose>, set
217
+ <skill-name><name/></skill-name> (set skill name to name), and then
218
+ (but only if ((`$1` is *NOT* equal to `-h` or `--help`) *AND*
219
+ (<ase-guidance-level/> is equal to `normal` or `verbose`))) you *MUST*
220
+ once output the following output <template/>:
221
221
 
222
222
  <template>
223
- ⧉ **ASE**: ✪ skill: **<skill-name/>**, ✦ purpose: **<skill/>**, ▶ status: **skill started**
223
+ ⧉ **ASE**: ✪ skill: **<skill-name/>**, ✦ purpose: **<purpose/>**, ▶ status: **skill started**
224
224
  </template>
225
225
 
226
226
  Later (but only if ((`$1` is *NOT* equal to `-h` or `--help`) *AND*
@@ -374,17 +374,29 @@ Template Patterns
374
374
 
375
375
  </template>
376
376
 
377
- - When `<ase-tpl-head title="<title/>"/>` should be expanded, use
378
- (where <raw-title/> is the visible un-styled text `⧉ ASE: <title/>`,
379
- <raw-title-len/> is the number of characters in <raw-title/>, and
380
- <bar/> is the `─` character repeated exactly max(0, 67 - <raw-title-len/>)
381
- times -- clamped to zero so an over-long title never yields a negative
382
- count -- the very same bar-width rule as `<ase-tpl-foot/>` and
383
- `<ase-tpl-boxed/>`, so equal visible text yields equal total width):
377
+ - When `<ase-tpl-head title="<title/>"[ subtitle="<subtitle/>"]/>`
378
+ should be expanded use the following helper placeholders and then
379
+ the following <template/>:
380
+
381
+ - <if condition="<subtitle/> is not empty">
382
+ Set <raw-title>⧉ ASE: <title/>: <subtitle/></raw-title>.
383
+ Set <render-title>⧉ ASE: **`<title/>`**: `<subtitle/>`</render-title>.
384
+ </if>
385
+ <else>
386
+ Set <raw-title>⧉ ASE: <title/></raw-title>.
387
+ Set <render-title>⧉ ASE: **`<title/>`**</render-title>.
388
+ </else>
389
+ - Set <raw-title-len/> to the number of characters in the visible
390
+ un-styled text <raw-title/>.
391
+ - Set <bar/> to the `─` character repeated exactly max(0, 67 - <raw-title-len/>)
392
+ times -- clamped to zero so an over-long title never yields a
393
+ negative count -- the very same bar-width rule as `<ase-tpl-foot/>`
394
+ and `<ase-tpl-boxed/>`, so equal visible text yields equal total
395
+ width.
384
396
 
385
397
  <template>
386
398
 
387
- ╭────━━━━**(** ⧉ ASE: **`<title/>`** **)**━━━━────<bar/>┈┈┈┈┈┈┈┈┈┈
399
+ ╭────━━━━**(** <render-title/> **)**━━━━────<bar/>┈┈┈┈┈┈┈┈┈┈
388
400
 
389
401
  </template>
390
402
 
@@ -396,16 +408,27 @@ Template Patterns
396
408
 
397
409
  </template>
398
410
 
399
- - When `<ase-tpl-foot title="<title/>"/>` should be expanded, use
400
- (where <raw-title/> is the visible un-styled text `⧉ ASE: <title/>`,
401
- <raw-title-len/> is the number of characters in <raw-title/>,
402
- and <bar/> is the `─` character repeated exactly max(0, 67 -
403
- <raw-title-len/>) times -- clamped to zero so an over-long title
404
- never yields a negative count):
411
+ - When `<ase-tpl-foot title="<title/>"[ subtitle="<subtitle/>"]/>`
412
+ should be expanded use the following helper placeholders and then
413
+ the following <template/>:
414
+
415
+ - <if condition="<subtitle/> is not empty">
416
+ Set <raw-title>⧉ ASE: <title/>: <subtitle/></raw-title>.
417
+ Set <render-title>⧉ ASE: **`<title/>`**: `<subtitle/>`</render-title>.
418
+ </if>
419
+ <else>
420
+ Set <raw-title>⧉ ASE: <title/></raw-title>.
421
+ Set <render-title>⧉ ASE: **`<title/>`**</render-title>.
422
+ </else>
423
+ - Set <raw-title-len/> to the number of characters in the visible
424
+ un-styled text <raw-title/>.
425
+ - Set <bar/> to the `─` character repeated exactly max(0, 67 - <raw-title-len/>)
426
+ times -- clamped to zero so an over-long title never yields a
427
+ negative count.
405
428
 
406
429
  <template>
407
430
 
408
- ╰────━━━━**(** ⧉ ASE: **`<title/>`** **)**━━━━────<bar/>┈┈┈┈┈┈┈┈┈┈
431
+ ╰────━━━━**(** <render-title/> **)**━━━━────<bar/>┈┈┈┈┈┈┈┈┈┈
409
432
 
410
433
  </template>
411
434
 
@@ -6,7 +6,7 @@
6
6
  "homepage": "https://ase.tools",
7
7
  "repository": { "url": "git+https://github.com/rse/ase.git", "type": "git" },
8
8
  "bugs": { "url": "https://github.com/rse/ase/issues" },
9
- "version": "0.9.51",
9
+ "version": "0.9.53",
10
10
  "license": "Apache-2.0",
11
11
  "author": {
12
12
  "name": "Dr. Ralf S. Engelschall",
@@ -16,7 +16,7 @@
16
16
  "devDependencies": {
17
17
  "@rse/stx": "1.1.6",
18
18
  "markdownlint": "0.41.1",
19
- "markdownlint-cli2": "0.23.1",
19
+ "markdownlint-cli2": "0.23.2",
20
20
  "eslint": "10.8.0",
21
21
  "@eslint/markdown": "8.0.3",
22
22
  "eslint-markdown": "0.12.1"
@@ -102,11 +102,13 @@ allowed-tools:
102
102
  @${CLAUDE_SKILL_DIR}/../../meta/ase-skill.md
103
103
  @${CLAUDE_SKILL_DIR}/../../meta/ase-getopt.md
104
104
 
105
- <skill name="ase-arch-analyze">
105
+ <purpose name="ase-arch-analyze">
106
106
  Review Software Architecture
107
- </skill>
107
+ </purpose>
108
108
 
109
- <expand name="getopt" arg1="ase-arch-analyze">
109
+ <expand name="getopt"
110
+ arg1="ase-arch-analyze"
111
+ arg2="--prefix|-P=">
110
112
  $ARGUMENTS
111
113
  </expand>
112
114
 
@@ -343,6 +345,14 @@ interface quality, quality attributes, and architecture governance.
343
345
  </step>
344
346
 
345
347
  3. <step id="STEP 3: Reconcile and Show Results">
348
+ Before reporting, determine the *finding id prefix* <id-prefix/>:
349
+ set <id-prefix><getopt-option-prefix/>-</id-prefix> if
350
+ <getopt-option-prefix/> is *not* empty, and set <id-prefix></id-prefix>
351
+ (set to empty) otherwise. Every reported `PROBLEM` and `TRADEOFF` id
352
+ and every persisted key below carries this <id-prefix/>, so that
353
+ analyses run under *distinct* prefixes occupy *distinct* id
354
+ namespaces and hence do not overwrite each other.
355
+
346
356
  Before reporting, classify every finding into one of three
347
357
  categories:
348
358
 
@@ -378,7 +388,7 @@ interface quality, quality attributes, and architecture governance.
378
388
  Report each unpaired finding with the following <template/>:
379
389
 
380
390
  <template>
381
- <ase-tpl-bullet-signal/> **PROBLEM** P<n/> (Severity: <severity/>, Aspect: <aspect-id/>): **<title/>**
391
+ <ase-tpl-bullet-signal/> **PROBLEM** <id-prefix/>P<n/> (Severity: <severity/>, Aspect: <aspect-id/>): **<title/>**
382
392
 
383
393
  <description/>
384
394
  </template>
@@ -386,7 +396,7 @@ interface quality, quality attributes, and architecture governance.
386
396
  Report each paired or clustered finding with the following <template/>:
387
397
 
388
398
  <template>
389
- <ase-tpl-bullet-normal/> **TRADEOFF** T<n/> (Severity: <severity/>): **<title/>**
399
+ <ase-tpl-bullet-normal/> **TRADEOFF** <id-prefix/>T<n/> (Severity: <severity/>): **<title/>**
390
400
 
391
401
  - *Focal aspect*: <focal-aspect/> - <focal-state/>
392
402
  - *In tension with*: <partner-list/>
@@ -458,12 +468,13 @@ interface quality, quality attributes, and architecture governance.
458
468
  - *Additionally*, persist all reported findings in a *single*
459
469
  `ase_kv_batch` call to the `ase` MCP server with `transactional`
460
470
  set to `true`. The `commands` parameter array of this call
461
- starts with one `{ command: "clear", prefix: "ase-issue-" }`
462
- entry (which removes only the previously persisted `ase-issue-*`
463
- keys, leaving any unrelated keys in the shared store intact),
464
- followed by one `{ command: "set", key: "ase-issue-P<n/>", val:
465
- "<title/>: <description/>" }` entry per reported PROBLEM and one
466
- `{ command: "set", key: "ase-issue-T<n/>", val: "<title/>:
471
+ starts with one `{ command: "clear", prefix: "ase-issue-<id-prefix/>" }`
472
+ entry (which removes only the previously persisted
473
+ `ase-issue-<id-prefix/>*` keys, leaving any unrelated keys in the
474
+ shared store intact),
475
+ followed by one `{ command: "set", key: "ase-issue-<id-prefix/>P<n/>",
476
+ val: "<title/>: <description/>" }` entry per reported PROBLEM and one
477
+ `{ command: "set", key: "ase-issue-<id-prefix/>T<n/>", val: "<title/>:
467
478
  <description/>" }` entry per reported TRADEOFF.
468
479
 
469
480
  Finally, give a final hint by expanding the following (which,
@@ -471,7 +482,7 @@ interface quality, quality attributes, and architecture governance.
471
482
  nothing and hence emit no output at all):
472
483
 
473
484
  <ase-tpl-hint level="minimal">
474
- For deeper analysis, suggestions on solution approaches and then final source code changes, use `/ase-code-resolve P{n}` or `/ase-code-resolve T{n}` in the same or even a different session.
485
+ For deeper analysis, suggestions on solution approaches and then final source code changes, use `/ase-code-resolve <id-prefix/>P{n}` or `/ase-code-resolve <id-prefix/>T{n}` in the same or even a different session.
475
486
  </ase-tpl-hint>
476
487
 
477
488
  </step>