@rse/ase 0.9.49 → 0.9.51

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.
package/dst/ase-hook.js CHANGED
@@ -145,12 +145,9 @@ export default class HookCommand {
145
145
  pluginRootVars = ["PLUGIN_ROOT", "CLAUDE_PLUGIN_ROOT"];
146
146
  else
147
147
  pluginRootVars = ["CLAUDE_PLUGIN_ROOT"];
148
- let pluginRoot = "";
149
- for (const pluginRootVar of pluginRootVars)
150
- if ((process.env[pluginRootVar] ?? "") !== "") {
151
- pluginRoot = process.env[pluginRootVar];
152
- break;
153
- }
148
+ const pluginRoot = pluginRootVars
149
+ .map((varName) => process.env[varName] ?? "")
150
+ .find((value) => value !== "") ?? "";
154
151
  if (pluginRoot === "")
155
152
  throw new Error(`${pluginRootVars.join("/")} environment variable is not set`);
156
153
  return pluginRoot;
@@ -254,7 +251,7 @@ export default class HookCommand {
254
251
  const guidance = setting("agent.guidance", "ASE_GUIDANCE_LEVEL", "normal");
255
252
  const boxing = setting("project.boxing", "ASE_PROJECT_BOXING", "white");
256
253
  /* determine headless mode */
257
- const headless = (process.env.ASE_HEADLESS ?? "false") === "true" ? "true" : "false";
254
+ const headless = process.env.ASE_HEADLESS === "true" ? "true" : "false";
258
255
  /* provide ASE information to Anthropic Claude Code CLI shell commands
259
256
  (Anthropic Claude Code CLI only -- GitHub Copilot CLI has no equivalent mechanism) */
260
257
  const envFile = tool === "claude" ? (process.env.CLAUDE_ENV_FILE ?? "") : "";
@@ -300,15 +297,14 @@ export default class HookCommand {
300
297
  "systemMessage" field for this -- GitHub Copilot CLI has no equivalent);
301
298
  the trailing help hint is emitted only if the guidance level asks for it */
302
299
  const banner = "\n" +
303
- `\n⧉ ASE: ⎈ version: ${versionCurrentPlugin}${versionHint !== "" ? " " + versionHint.replaceAll(/\*/g, "") : ""}` +
300
+ `\n⧉ ASE: ⎈ version: ${versionCurrentPlugin}${versionHint !== "" ? " " + versionHint.replace(/\*/g, "") : ""}` +
304
301
  `\n⧉ ASE: ※ user: ${userId}, ⚑ project: ${projectId}` +
305
302
  `\n⧉ ASE: ◉ task: ${taskId}, ⏻ session: ${sessionId}` +
306
303
  `\n⧉ ASE: ☯ persona: ${persona}, ▶ guidance: ${guidance}, ▢ boxing: ${boxing}` +
307
304
  (guidance === "normal" || guidance === "verbose" ?
308
305
  "\n" +
309
306
  "\n⧉ ASE: ▷ hint: use \"/ase-help-intent <intent-description>\" for skill command proposal" +
310
- "\n⧉ ASE: ▷ hint: use \"/ase-help-skill [<skill-name>]\" for skill catalog or skill manpage" : "") +
311
- "\n";
307
+ "\n⧉ ASE: ▷ hint: use \"/ase-help-skill [<skill-name>]\" for skill catalog or skill manpage" : "");
312
308
  /* inject markdown into session context.
313
309
  Anthropic Claude Code CLI and OpenAI Codex CLI expect the context nested in
314
310
  "hookSpecificOutput"; GitHub Copilot CLI expects a flat top-level
@@ -434,10 +430,10 @@ export default class HookCommand {
434
430
  tools, but the decision logic is shared by the "pre-tool-use" and
435
431
  "permission-request" handlers. */
436
432
  decideApproval(tool, spec, input) {
437
- const toolName = typeof input[spec.toolNameField] === "string" ?
438
- input[spec.toolNameField] : "";
439
- let toolInput = {};
433
+ const rawName = input[spec.toolNameField];
440
434
  const rawInput = input[spec.toolInputField];
435
+ const toolName = typeof rawName === "string" ? rawName : "";
436
+ let toolInput = {};
441
437
  if (spec.toolInputIsString && typeof rawInput === "string")
442
438
  toolInput = this.parseJSON(rawInput, toolInputSchema);
443
439
  else if (!spec.toolInputIsString && typeof rawInput === "object" && rawInput !== null) {
@@ -159,6 +159,23 @@ const probeMemory = () => {
159
159
  return { used: 0, total: 0 };
160
160
  }
161
161
  };
162
+ /* set of reasoning effort levels GitHub Copilot CLI offers in its effort picker */
163
+ const EFFORTS = new Set([
164
+ "low", "medium", "high", "xhigh", "max"
165
+ ]);
166
+ /* split a GitHub Copilot CLI "model.display_name" into its plain model name and its
167
+ reasoning effort: Copilot CLI renders the display name as the model label, followed
168
+ by the optional request multiplier, the optional reasoning effort and the optional
169
+ context tier, all separated by " · " (e.g. "gpt-5.4 (2x) · high · 1M context"), so
170
+ only a segment matching a known effort level is taken as the effort */
171
+ const splitCopilotModel = (display) => {
172
+ const parts = display.split(" · ");
173
+ const effort = parts.filter((part) => EFFORTS.has(part.toLowerCase()));
174
+ const name = parts.filter((part) => !EFFORTS.has(part.toLowerCase()));
175
+ if (effort.length === 0)
176
+ return { name: display, effort: "" };
177
+ return { name: name.join(" · "), effort: effort[0].toLowerCase() };
178
+ };
162
179
  /* memoize a zero-argument function, computing its value at most once on first use */
163
180
  const memoize = (fn) => {
164
181
  let cache = null;
@@ -286,6 +303,15 @@ export default class StatuslineCommand {
286
303
  }
287
304
  return { taskId, persona, guidance };
288
305
  });
306
+ const getModel = memoize(() => {
307
+ const display = data.model?.display_name ?? "";
308
+ /* under GitHub Copilot CLI the reasoning effort is only available as
309
+ a segment of the display name, so split it off again and let the
310
+ regular "effort" field of Anthropic Claude Code CLI still win */
311
+ const split = tool === "copilot" && display !== "" ?
312
+ splitCopilotModel(display) : { name: display, effort: "" };
313
+ return { name: split.name, effort: data.effort?.level ?? split.effort };
314
+ });
289
315
  const getGit = memoize(() => probeGit(data.workspace?.current_dir ?? ""));
290
316
  const getMem = memoize(() => probeMemory());
291
317
  /* identifier to renderer map: each callback fetches its own information
@@ -308,12 +334,12 @@ export default class StatuslineCommand {
308
334
  s: () => emit(`${prefix("⏻", "session")}${c.bold(getSession())}`),
309
335
  /* ==== MODEL ==== */
310
336
  m: () => {
311
- const model = data.model?.display_name ?? "";
312
- emit(`${prefix("⚙", "model")}${c.bold(model)}`);
337
+ const { name } = getModel();
338
+ emit(`${prefix("⚙", "model")}${c.bold(name)}`);
313
339
  },
314
340
  e: () => {
315
- const effort = data.effort?.level ?? "unknown";
316
- emit(`${prefix("⚒", "effort")}${c.bold(effort)}`);
341
+ const { effort } = getModel();
342
+ emit(`${prefix("⚒", "effort")}${c.bold(effort !== "" ? effort : "unknown")}`);
317
343
  },
318
344
  t: () => {
319
345
  const thinking = data.thinking?.enabled === true ? "yes" : "no";
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.49",
9
+ "version": "0.9.51",
10
10
  "license": "Apache-2.0",
11
11
  "author": {
12
12
  "name": "Dr. Ralf S. Engelschall",
@@ -42,7 +42,7 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "commander": "15.0.0",
45
- "@dotenvx/dotenvx": "2.17.2",
45
+ "@dotenvx/dotenvx": "2.18.0",
46
46
  "yaml": "2.9.0",
47
47
  "valibot": "1.4.2",
48
48
  "execa": "10.0.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.49",
3
+ "version": "0.9.51",
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.49",
3
+ "version": "0.9.51",
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.49",
3
+ "version": "0.9.51",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -13,6 +13,10 @@ Workflow
13
13
  --------
14
14
 
15
15
  1. Set the requested context: <context>$ARGUMENTS</context>.
16
+ The *first* whitespace-separated token of <context/> is the
17
+ comma-separated *aspect set* <aspects/> (a non-empty subset of the
18
+ aspect ids `A01`...`A20`). The *remaining* tokens are the source
19
+ code files to check.
16
20
 
17
21
  2. Use the `Read` tool to read all source code files referenced by
18
22
  <context/>, plus all *related* source code files needed to really
@@ -25,7 +29,9 @@ Workflow
25
29
  4. Set <problems/> to empty.
26
30
  Then check the read source code for the following aspects (each
27
31
  aspect is uniquely identified by its `aspect` id `A01 - XXX`...`A20
28
- - XXX`):
32
+ - XXX`), but *strictly limited* to those aspects whose id is
33
+ contained in the aspect set <aspects/> -- all other aspects are
34
+ *not* checked and their problems are *never* reported:
29
35
 
30
36
  - **A01 - FORMATTING**:
31
37
  Check for inconsistently formatted code and badly vertically
@@ -95,6 +101,20 @@ Workflow
95
101
  site as close as possible. For R4, prefer *parameterization*
96
102
  (table-driven, strategy map) over inheritance.
97
103
 
104
+ **PAYOFF GATE**: *Before* reporting any redundancy, draft the
105
+ solution diff and count its lines. The removed lines *MUST* be at
106
+ least *twice* the added lines (ratio >= 2:1, i.e. a net reduction
107
+ of at least 50%), where the added lines include the *entire*
108
+ extracted construct (signature, body, closing lines, comments,
109
+ type annotations) plus all replacing call sites. A break-even
110
+ proposal (e.g. 8 removed, 8 added) or any proposal below the 2:1
111
+ ratio *MUST* be *silently dropped* and *MUST* *NOT* be reported --
112
+ it merely relocates code instead of reducing it. Do *not* game
113
+ the ratio by compressing the extracted construct into unnatural
114
+ formatting or by omitting comments the code base style requires.
115
+ Two duplicated occurrences of a short block rarely pass this gate;
116
+ three or more occurrences usually do.
117
+
98
118
  - **A07 - PATTERNS**:
99
119
  Check for broken design patterns, broken conventions, or broken
100
120
  best practices.
@@ -0,0 +1,133 @@
1
+ ---
2
+ name: ase-meta-proximity
3
+ description: "Determine the Conceptual Proximity of a Topic"
4
+ effort: high
5
+ tools:
6
+ - "Agent"
7
+ ---
8
+
9
+ @../meta/ase-control.md
10
+
11
+ <define name="gather-facts">
12
+ <if condition="<ground/> is equal `true`">
13
+ Use the `ase-meta-search` skill in a sub-agent to gather facts with
14
+ the following tool call and store the returned facts in the placeholder
15
+ named `<arg2/>`:
16
+
17
+ `Agent(
18
+ description: "Query Web Search Service",
19
+ subagent_type: "ase:ase-meta-search",
20
+ prompt: "Search the Internet/Web and gather facts about <arg1/>",
21
+ run_in_background: false
22
+ )`
23
+
24
+ <if condition="the placeholder named `<arg2/>` contains no usable facts">
25
+ Set the placeholder named `<arg2/>` to empty, so the determination below
26
+ silently falls back to model knowledge. You *MUST* *NOT* output any
27
+ warning, because the caller expects the labeled list of step 4 as the
28
+ *only* output.
29
+ </if>
30
+ </if>
31
+ <else>
32
+ Use the model's world knowledge and determine facts about <arg1/> and
33
+ store those facts in the placeholder named `<arg2/>`.
34
+ </else>
35
+ </define>
36
+
37
+ 1. Set <args>$ARGUMENTS</args>, the single whitespace-separated string.
38
+
39
+ <if condition="the *first* token of <args/> is equal `GROUND`">
40
+ Set <ground>true</ground> (grounding requested) and set <topic/>
41
+ to the *second and all following* tokens of <args/>.
42
+ </if>
43
+ <else>
44
+ Set <ground>false</ground> (no grounding requested) and set
45
+ <topic/> to *all* tokens of <args/>.
46
+ </else>
47
+
48
+ You *MUST* *NOT* output anything related to this step.
49
+
50
+ 2. *Determine Topic*:
51
+
52
+ Determine the canonical name of the central *topic* which is stored
53
+ in <topic/>.
54
+
55
+ <expand name="gather-facts"
56
+ arg1="the following topic: <topic/>"
57
+ arg2="facts-topic"></expand>
58
+
59
+ Ground the determination of the canonical name of the topic <topic/>
60
+ in the facts of <facts-topic/> and do not contradict them. Update
61
+ <topic/> accordingly.
62
+
63
+ You *MUST* *NOT* output anything related to this step.
64
+
65
+ 3. *Determine Proximity*:
66
+
67
+ Determine the *conceptual proximity* of the current <topic/> along
68
+ three *dimensions* in parallel:
69
+
70
+ - **PARENT**:
71
+
72
+ The single most relevant *parent* topic (the broader topic that
73
+ <topic/> is a specialization of), which will be stored in
74
+ <parent/>.
75
+
76
+ <expand name="gather-facts"
77
+ arg1="the PARENT topic (the broader topic that the given topic is a specialization of) of the following topic: <topic/>"
78
+ arg2="facts-parent"></expand>
79
+
80
+ Ground the determination of the canonical name of the parent
81
+ topic <parent/> in the facts of <facts-parent/> and do not
82
+ contradict them.
83
+
84
+ - **SIBLINGS**:
85
+
86
+ The *four* most relevant *sibling* topics (topics on the same
87
+ level that share the same parent), which will be stored in
88
+ <sibling-1/> to <sibling-4/>.
89
+
90
+ <expand name="gather-facts"
91
+ arg1="the SIBLING topics (topics on the same level that share the same parent) of the following topic: <topic/>"
92
+ arg2="facts-siblings"></expand>
93
+
94
+ Ground the determination of the canonical names of the most
95
+ relevant sibling topics <sibling-1/> to <sibling-4/> in the facts
96
+ of <facts-siblings/> and do not contradict them.
97
+
98
+ - **CHILDREN**:
99
+
100
+ The *four* most relevant *child* topics (narrower topics that
101
+ are specializations of <topic/>), stored in <child-1/> to
102
+ <child-4/>.
103
+
104
+ <expand name="gather-facts"
105
+ arg1="the CHILDREN topics (narrower topics that are specializations) of the following topic: <topic/>"
106
+ arg2="facts-children"></expand>
107
+
108
+ Ground the determination of the canonical names of the most
109
+ relevant child topics <child-1/> to <child-4/> in the facts of
110
+ <facts-children/> and do not contradict them.
111
+
112
+ You *MUST* determine *exactly* one parent, *exactly* four siblings,
113
+ and *exactly* four children. All nine proximity topics *MUST* be
114
+ *distinct* from each other and *MUST* *NOT* be <topic/> itself or a
115
+ mere synonym or spelling variant of it. You *MUST* *NOT* output
116
+ anything related to this step.
117
+
118
+ 4. Return *exclusively* the following <template/> (no prose, no
119
+ preamble, no summary, and no Markdown formatting):
120
+
121
+ <template>
122
+ TOPIC: <topic/>
123
+ PARENT: <parent/>
124
+ SIBLING: <sibling-1/>
125
+ SIBLING: <sibling-2/>
126
+ SIBLING: <sibling-3/>
127
+ SIBLING: <sibling-4/>
128
+ CHILD: <child-1/>
129
+ CHILD: <child-2/>
130
+ CHILD: <child-3/>
131
+ CHILD: <child-4/>
132
+ </template>
133
+
@@ -1,48 +1,21 @@
1
1
 
2
- ASE Constitution
3
- ================
2
+ # ASE Constitution
4
3
 
5
4
  You are an expert-level AI coding assistant.
6
5
  You have the **Agentic Software Engineering (ASE)** companion toolkit enabled,
7
6
  which boosts you to an expert-level Software Engineering AI agent.
8
7
 
9
- If ((<ase-agent-tool/> is equal to `copilot`) *AND* (<ase-headless/> is empty
10
- or not set) *AND* (<ase-guidance-level/> is not equal to `none`)) you *MUST* output
11
- the following <template/> *exactly once* as the very *first* thing in
12
- your *first* response of this session -- *before* any other text,
13
- *before* any tool call, and *before* entering any skill flow:
14
-
15
- <template>
16
- ⧉ **ASE**: ⎈ version: **<ase-version/>** <ase-version-hint/>
17
- ⧉ **ASE**: ※ user: **<ase-user-id/>**, ⚑ project: **<ase-project-id/>**
18
- ⧉ **ASE**: ◉ task: **<ase-task-id/>**, ⏻ session: **<ase-session-id/>**
19
- ⧉ **ASE**: ☯ persona: **<ase-persona-style/>**, ▶ guidance: **<ase-guidance-level/>**, ▢ boxing: **<ase-project-boxing/>**
20
- </template>
21
-
22
- If ((<ase-agent-tool/> is equal to `copilot`) *AND* (<ase-headless/> is
23
- empty or not set) *AND* (<ase-guidance-level/> is equal to `normal` or
24
- `verbose`)) you *MUST* output the following <template/> *exactly once*
25
- as the very *second* thing in your *first* response of this session,
26
- too:
27
-
28
- <template>
29
- ⧉ **ASE**: ▷ hint: use "/ase-help-intent *intent-description*" for skill command proposal
30
- ⧉ **ASE**: ▷ hint: use "/ase-help-skill [*skill-name*]" for skill catalog or skill manpage
31
- </template>
32
-
33
- Prohibitions
34
- ------------
8
+ ## Prohibitions
35
9
 
36
10
  - Do *not* factor out code blocks into their own functions without good reason.
37
11
  - Do *not* factor out deeply nested code constructs into individual functions.
38
12
  - Do *not* split continuous chunks of code fewer than 100 lines into individual functions.
39
13
  - Do *not* use braces around single-statement blocks in "if" and "while" constructs unless the language requires them.
40
- - Do *not* insist on early "return" in "if" blocks if an "else" block exists.
14
+ - Do *not* insist on early "return" in "if" blocks, if an "else" block exists.
41
15
  - Do *not* remove any whitespace in the code formatting -- keep whitespace aligned with code base.
42
16
  - Do *not* produce any trailing white-spaces on any lines.
43
17
 
44
- Commandments
45
- ------------
18
+ ## Commandments
46
19
 
47
20
  - Be *honest* and *transparent* in all your responses.
48
21
  - *Ground* factual and technical claims in verifiable evidence (code base, local files, or web)
@@ -51,7 +24,8 @@ Commandments
51
24
  - Use *concise* and *type-safe code* only.
52
25
  - Use *precise* and *surgical code changes* only.
53
26
  - Be very *pedantic* on code style.
54
- - Place a *blank line before a comment line*, but not when it is the first line of a block or an end-of-line comment.
27
+ - Place a *blank line before any comment line*,
28
+ but not when it is the first line of a block or an end-of-line comment.
55
29
  - Keep code and comment *formatting exactly as in the existing code*.
56
30
  - Use *regular comments* `/* [...] */` instead of end-of-line comments `// [...]`.
57
31
  - Use *two leading/trailing spaces within comments* as in `/* [...] */`.
@@ -1,6 +1,5 @@
1
1
 
2
- Persona Communication Style
3
- ---------------------------
2
+ ## Persona Communication Style
4
3
 
5
4
  *IMPORTANT*: The communication style in your outputs *MUST* follow the
6
5
  following conditional rules. Re-evaluate and internalize them for each
@@ -60,7 +59,7 @@ requested communication style at any time during a session.
60
59
  - `<subject/> <action/> <object/>.`
61
60
  - `<subject/> <action/>.`
62
61
  - <keywords/> is only one to four keywords summarizing the <details/>
63
- - <details/> is one to four prose sentences explaining the aspect
62
+ - <details/> is one to four concise prose sentences explaining the aspect
64
63
 
65
64
  - If <ase-persona-style/> is `telegrapher`, or `caveman`:
66
65
  - You *MUST* *use only* bullet point lists without blank lines between bullet points.
@@ -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.49",
9
+ "version": "0.9.51",
10
10
  "license": "Apache-2.0",
11
11
  "author": {
12
12
  "name": "Dr. Ralf S. Engelschall",
@@ -17,7 +17,7 @@
17
17
  "@rse/stx": "1.1.6",
18
18
  "markdownlint": "0.41.1",
19
19
  "markdownlint-cli2": "0.23.1",
20
- "eslint": "10.7.0",
20
+ "eslint": "10.8.0",
21
21
  "@eslint/markdown": "8.0.3",
22
22
  "eslint-markdown": "0.12.1"
23
23
  },
@@ -137,9 +137,17 @@ problems in *performance* and *efficiency*, or problems in *security*.
137
137
  persisted). With the default floor `LOW`, all problems are kept.
138
138
  `ACCEPTED` problems are *never* dropped.
139
139
 
140
+ Then sort the surviving problems in <problems/> by their `severity`
141
+ field from highest to lowest in the fixed order `HIGH`, `MEDIUM`,
142
+ `LOW`, `ACCEPTED`, so the reporting starts with the most severe
143
+ problem. Within the same severity, keep the `file`/`line` order
144
+ established in STEP 2.
145
+
140
146
  Then renumber the surviving problems contiguously as `P<n/>` with
141
- <n/> = 1, 2, ... in the original ordering. If *all* problems are
142
- dropped, skip the per-problem report but still purge any stale
147
+ <n/> = 1, 2, ... in that sorted ordering, so `P1` is the most severe
148
+ problem and the persisted `ase-issue-P<n/>` keys follow the reported
149
+ sequence. If *all* problems are dropped, skip the per-problem report
150
+ but still purge any stale
143
151
  persisted problems with a *single* `ase_kv_batch` call to the `ase`
144
152
  MCP server with `transactional` set to `true` and a `commands`
145
153
  parameter array holding exactly one `{ command: "clear", prefix:
@@ -33,8 +33,10 @@ The `--severity`|`-S`=(`LOW`|`MEDIUM`|`HIGH`) option sets a *severity
33
33
  floor* (default `LOW`): problems below the chosen threshold are silently
34
34
  suppressed (neither reported nor persisted), ordered `LOW` < `MEDIUM` <
35
35
  `HIGH`. The default `LOW` keeps all problems; `ACCEPTED` problems are
36
- never suppressed. Surviving problems are renumbered contiguously as
37
- `P<n>`.
36
+ never suppressed. Surviving problems are reported in *descending
37
+ severity* order `HIGH`, `MEDIUM`, `LOW`, `ACCEPTED` - keeping the
38
+ `file`/`line` order within the same severity - and are renumbered
39
+ contiguously as `P<n>`, so `P1` is the most severe problem.
38
40
 
39
41
  The skill investigates the code base silently, reports each detected
40
42
  problem as a `PROBLEM` entry with severity (`LOW`, `MEDIUM`, `HIGH`) and
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: ase-code-lint
3
- argument-hint: "[--help|-h] [--auto|-a] [--severity|-S=(LOW|MEDIUM|HIGH)] <source-reference>"
3
+ argument-hint: "[--help|-h] [--auto|-a] [--severity|-S=(LOW|MEDIUM|HIGH)] [--include|-i=<aspect>[,...]] [--exclude|-e=<aspect>[,...]] <source-reference>"
4
4
  description: >
5
5
  Lint source code for potential code quality problems.
6
6
  Use when the user wants to "lint" or "check" source code.
@@ -20,7 +20,7 @@ Lint Source Code
20
20
 
21
21
  <expand name="getopt"
22
22
  arg1="ase-code-lint"
23
- arg2="--auto|-a --severity|-S=(LOW|MEDIUM|HIGH)">
23
+ arg2="--auto|-a --severity|-S=(LOW|MEDIUM|HIGH) --include|-i=(none|A01|A02|A03|A04|A05|A06|A07|A08|A09|A10|A11|A12|A13|A14|A15|A16|A17|A18|A19|A20)... --exclude|-e=(none|A01|A02|A03|A04|A05|A06|A07|A08|A09|A10|A11|A12|A13|A14|A15|A16|A17|A18|A19|A20)...">
24
24
  $ARGUMENTS
25
25
  </expand>
26
26
 
@@ -48,7 +48,31 @@ related to a set of code quality aspects.
48
48
 
49
49
  </if>
50
50
 
51
- First, use the following <template/> to give a hint on this step:
51
+ First, determine the *effective aspect set* <aspects/>, i.e., the
52
+ code quality aspects which are checked at all. For this, parse
53
+ <getopt-option-include/> and <getopt-option-exclude/> as
54
+ comma-separated token lists, silently dropping the `none` sentinel
55
+ and any empty token. If a token <token/> is *not* one of the aspect
56
+ ids `A01`...`A20`, only output the following <template/> and then
57
+ *STOP* the entire flow (do not perform any further steps):
58
+
59
+ <template>
60
+ ⧉ **ASE**: ✪ skill: **ase-code-lint**, ▶ ERROR: invalid aspect id: **<token/>**
61
+ </template>
62
+
63
+ Otherwise set <aspects/> to *all* twenty aspect ids `A01`...`A20`
64
+ if both lists are empty, to the *include* list if only it is
65
+ non-empty, to all twenty *minus* the *exclude* list if only it is
66
+ non-empty, and to the *include* list *minus* the *exclude* list if
67
+ both are non-empty. If the resulting <aspects/> is *empty*, only
68
+ output the following <template/> and then *STOP* the entire flow
69
+ (do not perform any further steps):
70
+
71
+ <template>
72
+ ⧉ **ASE**: ✪ skill: **ase-code-lint**, ▶ ERROR: options `--include` and `--exclude` cancel out to an empty aspect set
73
+ </template>
74
+
75
+ Then, use the following <template/> to give a hint on this step:
52
76
 
53
77
  <template>
54
78
  <ase-tpl-bullet-secondary/> **LINT INVESTIGATION**
@@ -72,16 +96,17 @@ related to a set of code quality aspects.
72
96
  Agent(
73
97
  description: "Lint Investigation (<batch-index/>/<batch-count/>)",
74
98
  subagent_type: "ase:ase-code-lint",
75
- prompt: <batch/>,
99
+ prompt: "<aspects/> <batch/>",
76
100
  run_in_background: false
77
101
  )
78
102
  ```
79
103
 
80
- Here <batch/> is the space-separated list of the source code file
81
- paths of the corresponding batch, <batch-index/> is the 1-based
82
- index of that batch, and <batch-count/> is the total number of
83
- batches, so that each parallel invocation is distinguishable in
84
- the progress display.
104
+ Here <aspects/> is the comma-separated list of the effective aspect
105
+ ids (without any spaces), <batch/> is the space-separated list of
106
+ the source code file paths of the corresponding batch,
107
+ <batch-index/> is the 1-based index of that batch, and
108
+ <batch-count/> is the total number of batches, so that each
109
+ parallel invocation is distinguishable in the progress display.
85
110
 
86
111
  Parse the result message of each `Agent` tool invocation as a JSON
87
112
  array and concatenate all those arrays. Then *deduplicate* the
@@ -104,6 +129,12 @@ related to a set of code quality aspects.
104
129
  *silently drop* all other problems. With the default floor `LOW`, all
105
130
  problems are kept. `ACCEPTED` problems are *never* dropped.
106
131
 
132
+ Finally, sort the surviving problems in <problems/> by their
133
+ `severity` field from highest to lowest in the fixed order `HIGH`,
134
+ `MEDIUM`, `LOW`, `ACCEPTED`, so the subsequent reporting starts with
135
+ the most severe problem. Within the same severity, keep the
136
+ `file`/`line` order established above.
137
+
107
138
  You *MUST* *NOT* output anything else in this STEP 1.
108
139
 
109
140
  </step>
@@ -443,7 +474,7 @@ related to a set of code quality aspects.
443
474
 
444
475
  <if condition="<getopt-option-auto/> is not equal `true`">
445
476
  <ase-tpl-hint level="verbose">
446
- Use `/ase-code-lint --auto` to apply all corrections unattended, and `--severity` to raise the reporting floor.
477
+ Use `/ase-code-lint --auto` to apply all corrections unattended, `--severity` to raise the reporting floor, and `--include`/`--exclude` to narrow the checked aspects.
447
478
  </ase-tpl-hint>
448
479
  </if>
449
480
 
@@ -9,6 +9,8 @@
9
9
  [`--help`|`-h`]
10
10
  [`--auto`|`-a`]
11
11
  [`--severity`|`-S`=(`LOW`|`MEDIUM`|`HIGH`)]
12
+ [`--include`|`-i`=*aspect*[`,`...]]
13
+ [`--exclude`|`-e`=*aspect*[`,`...]]
12
14
  *source-reference*
13
15
 
14
16
  ## DESCRIPTION
@@ -25,6 +27,22 @@ correction interactively (or refine it via a free-text hint, which
25
27
  re-proposes the correction without limit) or - with `--auto` - applies
26
28
  all corrections automatically.
27
29
 
30
+ By default all twenty code quality aspects are checked. The `--include`
31
+ and `--exclude` options narrow this to an *effective aspect set*: with
32
+ `--include` only, exactly the listed aspects are checked; with
33
+ `--exclude` only, all aspects except the listed ones; with both, the
34
+ included ones minus the excluded ones. An unknown aspect id, or a
35
+ combination which cancels out to an empty set, aborts the skill with an
36
+ error. The twenty aspect ids are:
37
+
38
+ ```text
39
+ A01 FORMATTING A06 REDUNDANCY A11 TYPING A16 SECURITY
40
+ A02 COMPREHENSION A07 PATTERNS A12 ERROR-HANDLING A17 ARCHITECTURE
41
+ A03 CLEANLINESS A08 COMPLICATEDNESS A13 MEMORY-LEAK A18 LOGIC
42
+ A04 SPELLING A09 CONCISENESS A14 CONCURRENCY A19 FLOW
43
+ A05 COMPLEXITY A10 SMELLS A15 PERFORMANCE A20 DEAD-CODE
44
+ ```
45
+
28
46
  ## OPTIONS
29
47
 
30
48
  `--auto`|`-a`:
@@ -35,7 +53,19 @@ all corrections automatically.
35
53
  Set the *severity floor* (default `LOW`): findings below the chosen
36
54
  threshold are silently suppressed, ordered `LOW` < `MEDIUM` <
37
55
  `HIGH`. The default `LOW` keeps all findings; `ACCEPTED` findings are
38
- never suppressed.
56
+ never suppressed. Surviving findings are reported in *descending
57
+ severity* order `HIGH`, `MEDIUM`, `LOW`, `ACCEPTED`, keeping the
58
+ `file`/`line` order within the same severity.
59
+
60
+ `--include`|`-i`=*aspect*[`,`...]:
61
+ Restrict the checked code quality aspects to the given
62
+ comma-separated list of aspect ids (e.g. `A01,A04`). Without this
63
+ option, all twenty aspects are checked.
64
+
65
+ `--exclude`|`-e`=*aspect*[`,`...]:
66
+ Remove the given comma-separated list of aspect ids from the checked
67
+ code quality aspects. Applied *after* `--include`, so `-i A01,A02 -e
68
+ A02` checks `A01` only.
39
69
 
40
70
  ## ARGUMENTS
41
71
 
@@ -62,6 +92,18 @@ Lint a directory, reporting only `MEDIUM` and `HIGH` findings:
62
92
  ❯ /ase-code-lint -S MEDIUM src/handlers/
63
93
  ```
64
94
 
95
+ Lint a source file for the formatting and spelling aspects only:
96
+
97
+ ```text
98
+ ❯ /ase-code-lint -i A01,A04 src/server.ts
99
+ ```
100
+
101
+ Lint a directory for all aspects except dead code:
102
+
103
+ ```text
104
+ ❯ /ase-code-lint --exclude A20 src/handlers/
105
+ ```
106
+
65
107
  ## SEE ALSO
66
108
 
67
109
  [`ase-code-analyze`](../ase-code-analyze/help.md), [`ase-code-resolve`](../ase-code-resolve/help.md), [`ase-code-refactor`](../ase-code-refactor/help.md),
@@ -6,6 +6,7 @@
6
6
  ⎈ **RESEARCH**
7
7
  ○ `ase-meta-search`: Search the Internet/Web
8
8
  ○ `ase-meta-proximity`: Determine the Conceptual Proximity of a Topic
9
+ ○ `ase-meta-quotes`: Find Quotes on a Topic
9
10
  ○ `ase-meta-brainstorm`: Collaboratively Brainstorm a Topic
10
11
  ○ `ase-meta-chat`: Query Foreign LLM for Chat
11
12
  ○ `ase-meta-quorum`: Query Multiple AIs for Quorum Answer
@@ -58,4 +58,4 @@ Explain a recent topic grounded in Internet/Web facts:
58
58
 
59
59
  ## SEE ALSO
60
60
 
61
- [`ase-code-explain`](../ase-code-explain/help.md), [`ase-meta-search`](../ase-meta-search/help.md), [`ase-docs-distill`](../ase-docs-distill/help.md).
61
+ [`ase-code-explain`](../ase-code-explain/help.md), [`ase-meta-search`](../ase-meta-search/help.md), [`ase-meta-quotes`](../ase-meta-quotes/help.md), [`ase-docs-distill`](../ase-docs-distill/help.md).
@@ -37,37 +37,6 @@ relevant *child* topics:
37
37
  <topic><getopt-arguments/></topic>
38
38
  </objective>
39
39
 
40
- <define name="gather-facts">
41
- <if condition="<getopt-option-ground/> is equal `true`">
42
- Set <prompt>Search the Internet/Web and gather facts about
43
- <arg1/></prompt>.
44
-
45
- Then use the `ase-meta-search` skill in a sub-agent to gather facts with
46
- the following tool call and store the returned facts in the placeholder
47
- named `<arg2/>`:
48
-
49
- `Agent(
50
- description: "Query Web Search Service",
51
- subagent_type: "ase:ase-meta-search",
52
- prompt: "<prompt/>",
53
- run_in_background: false
54
- )`
55
-
56
- <if condition="the placeholder named `<arg2/>` contains no usable facts">
57
- Set the placeholder named `<arg2/>` to empty, so the determination below
58
- falls back to model knowledge, and output the following <template/>:
59
-
60
- <template>
61
- <ase-tpl-bullet-secondary/> **WARNING**: grounding found no usable facts -- falling back to model knowledge.
62
- </template>
63
- </if>
64
- </if>
65
- <else>
66
- Use the model's world knowledge and determine facts about <arg1/> and
67
- store those facts in the placeholder named `<arg2/>`.
68
- </else>
69
- </define>
70
-
71
40
  <flow>
72
41
 
73
42
  1. <step id="STEP 1: Check Topic">
@@ -88,69 +57,59 @@ store those facts in the placeholder named `<arg2/>`.
88
57
  *REPEAT* the following sub-steps in a *LOOP* until either
89
58
  <getopt-option-loop/> is *not* equal `true` (then the loop runs
90
59
  exactly *once* and stops after rendering), or the user declines/cancels
91
- the dialog in sub-step 5:
92
-
93
- 1. *Determine Topic*:
94
-
95
- Determine the canonical name of the central *topic* which is stored
96
- in <topic/>.
97
-
98
- <expand name="gather-facts"
99
- arg1="the following topic: <topic/>"
100
- arg2="facts-topic"></expand>
101
-
102
- Ground the determination of the canonical name of the topic
103
- <topic/> in the facts of <facts-topic/> and do not contradict
104
- them. Update <topic/> accordingly.
105
-
106
- 2. *Determine Proximity*:
107
-
108
- Determine the *conceptual proximity* of the current <topic/>
109
- along three *dimensions*:
110
-
111
- - **PARENT**:
112
-
113
- The single most relevant *parent* topic (the broader topic
114
- that <topic/> is a specialization of), which will be stored
115
- in <parent/>.
60
+ the dialog in sub-step 4:
116
61
 
117
- <expand name="gather-facts"
118
- arg1="the PARENT topic (the broader topic that the given topic is a specialization of) of the following topic: <topic/>"
119
- arg2="facts-parent"></expand>
62
+ 1. *Determine Proximity*:
120
63
 
121
- Ground the determination of the canonical name of the parent
122
- topic <parent/> in the facts of <facts-parent/> and do not
123
- contradict them.
64
+ Set <parent/>, <sibling-1/> to <sibling-4/>, and <child-1/> to
65
+ <child-4/> to empty, so that a stale proximity of a previously
66
+ navigated topic can never leak into the rendering below.
124
67
 
125
- - **SIBLINGS**:
68
+ Set <prompt><topic/></prompt>.
126
69
 
127
- The *four* most relevant *sibling* topics (topics on the
128
- same level that share the same parent), which will be stored
129
- in <sibling-1/> to <sibling-4/>.
130
-
131
- <expand name="gather-facts"
132
- arg1="the SIBLING topics (topics on the same level that share the same parent) of the following topic: <topic/>"
133
- arg2="facts-siblings"></expand>
134
-
135
- Ground the determination of the canonical names of the most
136
- relevant sibling topics <sibling-1/> to <sibling-4/> in the
137
- facts of <facts-siblings/> and do not contradict them.
138
-
139
- - **CHILDREN**:
140
-
141
- The *four* most relevant *children* topics (narrower topics
142
- that are specializations of <topic/>), stored in <child-1/>
143
- to <child-4/>.
70
+ <if condition="<getopt-option-ground/> is equal `true`">
71
+ Set <prompt>GROUND <topic/></prompt>, so the agent grounds its
72
+ determination in Internet/Web facts instead of using model
73
+ knowledge only.
74
+ </if>
144
75
 
145
- <expand name="gather-facts"
146
- arg1="the CHILDREN topics (narrower topics that are specializations) of the following topic: <topic/>"
147
- arg2="facts-children"></expand>
76
+ Determine the canonical name of the central *topic* and its
77
+ *conceptual proximity* along the three *dimensions* **PARENT**
78
+ (the single broader topic that <topic/> is a specialization of),
79
+ **SIBLINGS** (the four most relevant topics on the same level
80
+ that share the same parent), and **CHILDREN** (the four most
81
+ relevant narrower topics that are specializations of <topic/>) by
82
+ using the `ase-meta-proximity` agent in a sub-agent with the
83
+ following tool call:
84
+
85
+ `Agent(
86
+ description: "Determine Conceptual Proximity",
87
+ subagent_type: "ase:ase-meta-proximity",
88
+ prompt: "<prompt/>",
89
+ run_in_background: false
90
+ )`
91
+
92
+ Parse the returned labeled list and set <topic/> to the value of
93
+ its `TOPIC:` line, <parent/> to the value of its `PARENT:` line,
94
+ <sibling-1/> to <sibling-4/> to the values of its four `SIBLING:`
95
+ lines, and <child-1/> to <child-4/> to the values of its four
96
+ `CHILD:` lines.
97
+
98
+ <if condition="
99
+ the sub-agent returned no usable proximity OR
100
+ it did not yield a canonical topic, exactly one parent,
101
+ exactly four siblings, and exactly four children
102
+ ">
103
+ Determine the canonical topic name, the parent, the siblings, and
104
+ the children from model knowledge instead, and output the
105
+ following <template/>:
148
106
 
149
- Ground the determination of the canonical names of the most
150
- relevant children topics <child-1/> to <child-4/> in the
151
- facts of <facts-children/> and do not contradict them.
107
+ <template>
108
+ <ase-tpl-bullet-secondary/> **WARNING**: proximity agent returned no usable result -- falling back to model knowledge.
109
+ </template>
110
+ </if>
152
111
 
153
- 3. *Render Proximity*:
112
+ 2. *Render Proximity*:
154
113
 
155
114
  Output the result with the following <template/>, listing each
156
115
  proximity topic under its bullet-prefixed section header.
@@ -179,12 +138,12 @@ store those facts in the placeholder named `<arg2/>`.
179
138
  <ase-tpl-foot title="PROXIMITY TOPICS"/>
180
139
  </template>
181
140
 
182
- 4. <if condition="<getopt-option-loop/> is not equal `true`">
141
+ 3. <if condition="<getopt-option-loop/> is not equal `true`">
183
142
  The loop runs only once in non-interactive mode: *break* out of
184
143
  the *loop* and stop processing without any further output.
185
144
  </if>
186
145
 
187
- 5. *Navigate Proximity*:
146
+ 4. *Navigate Proximity*:
188
147
 
189
148
  In the following, you *MUST* *NOT* use your built-in
190
149
  <user-dialog-tool/> tool! Instead, you *MUST* just show a custom
@@ -207,7 +166,7 @@ store those facts in the placeholder named `<arg2/>`.
207
166
  CHILD-4: ↓ <child-4/>
208
167
  </expand>
209
168
 
210
- Check the tool <result/> and dispatch accordingly:
169
+ Check the <result/> and dispatch accordingly:
211
170
 
212
171
  - If <result/> is `CANCEL`:
213
172
  *Break* out of the *loop* and stop processing without any
@@ -20,11 +20,12 @@ topic that *topic* specializes), *SIBLINGS* (the four most relevant
20
20
  topics on the same level, sharing the same parent), and *CHILDREN* (the
21
21
  four most relevant narrower topics that specialize *topic*).
22
22
 
23
- By default the proximity is derived from model knowledge only. With the
24
- `--ground`/`-g` option, the skill first searches the Internet/Web for
25
- facts about the topic via the `ase-meta-search` skill (dispatched in a
26
- sub-agent, querying all available search backends) and grounds the
27
- determination in the found facts.
23
+ The determination itself is delegated to the `ase-meta-proximity` agent,
24
+ which is shared with the `ase-meta-quotes` skill. By default the
25
+ proximity is derived from model knowledge only. With the `--ground`/`-g`
26
+ option, the agent first searches the Internet/Web for facts about the
27
+ topic, about its broader topic, and about its narrower topics, and
28
+ grounds the determination in the found facts.
28
29
 
29
30
  Without the `--loop`/`-l` option, the skill determines and prints the
30
31
  proximity of the given topic once and then stops. With the `--loop`/`-l`
@@ -33,14 +34,14 @@ interactive dialog; selecting one of them makes it the new *current
33
34
  topic* and restarts the determination from the beginning, so the user
34
35
  can *navigate* the topic taxonomy up (parent), sideways (siblings), and
35
36
  down (children). Cancelling the dialog exits the loop. When `--loop` is
36
- combined with `--ground`, each newly selected topic is re-grounded via
37
- the `ase-meta-search` sub-agent before its proximity is re-determined.
37
+ combined with `--ground`, each newly selected topic is re-grounded by
38
+ the `ase-meta-proximity` sub-agent before its proximity is re-determined.
38
39
 
39
40
  ## OPTIONS
40
41
 
41
42
  `--ground`|`-g`:
42
- Ground the determination in Internet/Web facts gathered via the
43
- `ase-meta-search` skill before determining the proximity. Without
43
+ Ground the determination in Internet/Web facts gathered by the
44
+ `ase-meta-proximity` agent before determining the proximity. Without
44
45
  this option, the determination is derived from model knowledge only.
45
46
  When combined with `--loop`, every newly navigated-to topic is
46
47
  re-grounded.
@@ -75,4 +76,4 @@ Internet/Web facts:
75
76
 
76
77
  ## SEE ALSO
77
78
 
78
- [`ase-meta-eli5`](../ase-meta-eli5/help.md), [`ase-meta-search`](../ase-meta-search/help.md), [`ase-code-explain`](../ase-code-explain/help.md).
79
+ [`ase-meta-quotes`](../ase-meta-quotes/help.md), [`ase-meta-eli5`](../ase-meta-eli5/help.md), [`ase-meta-search`](../ase-meta-search/help.md), [`ase-code-explain`](../ase-code-explain/help.md).
@@ -0,0 +1,214 @@
1
+ ---
2
+ name: ase-meta-quotes
3
+ argument-hint: "[--help|-h] [--ground|-g] [--proximity|-p] [--count|-c <count>] <topic-keywords>"
4
+ description: >
5
+ Find quotes for a set of topic keywords and place them into a
6
+ 2x2 matrix, spanned by the presence of an author/origin and by
7
+ the literal containment of a keyword, optionally grounded in
8
+ Internet/Web facts and optionally widened to the conceptual
9
+ neighborhood of the topic. Use when the user wants "quotes",
10
+ "sayings", "aphorisms", or "citations" on a topic.
11
+ user-invocable: true
12
+ disable-model-invocation: false
13
+ effort: high
14
+ allowed-tools:
15
+ - "Agent"
16
+ ---
17
+
18
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-control.md
19
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-skill.md
20
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-getopt.md
21
+
22
+ <skill name="ase-meta-quotes">
23
+ Find Quotes on a Topic
24
+ </skill>
25
+
26
+ <expand name="getopt"
27
+ arg1="ase-meta-quotes"
28
+ arg2="--ground|-g --proximity|-p --count|-c=8">
29
+ $ARGUMENTS
30
+ </expand>
31
+
32
+ <objective>
33
+ *Find* quotes for the following topic keywords:
34
+ <keywords><getopt-arguments/></keywords>
35
+ </objective>
36
+
37
+ <flow>
38
+
39
+ 1. <step id="STEP 1: Sanity Check Usage">
40
+
41
+ 1. <if condition="<keywords/> is empty">
42
+ Only output the following <template/> and then immediately *STOP*
43
+ processing the entire current skill:
44
+
45
+ <template>
46
+ ⧉ **ASE**: ✪ skill: **ase-meta-quotes**, ▶ ERROR: expected a `<topic-keywords>` argument
47
+ </template>
48
+ </if>
49
+
50
+ 2. Set <quotes></quotes> (set to empty).
51
+
52
+ 3. Determine the maximum total number of *quotes* to surface: set
53
+ <count/> to <getopt-option-count/>; if <getopt-option-count/> is
54
+ *non-numeric* or *less than or equal to 0*, use the default *8*
55
+ instead.
56
+
57
+ </step>
58
+
59
+ 2. <step id="STEP 2: Harvest Quotes">
60
+
61
+ 1. Determine *quotes* -- sayings, aphorisms, maxims, proverbs, and
62
+ citations -- which are about the topic <keywords/>, and store them in
63
+ <quotes/>. Per quote, record its *text*, its *author* (a named person
64
+ or organization, if any is known), its *origin* (a named work,
65
+ standard, or document, if any is known), and <keywords/> as its
66
+ *source topic*.
67
+
68
+ 2. <if condition="<getopt-option-ground/> is equal `true`">
69
+
70
+ *Additionally* -- and never *instead* -- gather quotes from the
71
+ Internet/Web by using the `ase-meta-search` skill in a sub-agent
72
+ with the following tool call:
73
+
74
+ `Agent(
75
+ description: "Query Web Search Service",
76
+ subagent_type: "ase:ase-meta-search",
77
+ prompt: "Search the Internet/Web and gather quotes about the following topic: <keywords/>",
78
+ run_in_background: false
79
+ )`
80
+
81
+ Merge the returned quotes into <quotes/>, deduplicating quotes which
82
+ differ only in punctuation, capitalization, or attribution wording,
83
+ and remember for every quote whether the search *confirmed* its exact
84
+ wording and attribution.
85
+
86
+ <if condition="the sub-agent returned no usable quotes">
87
+ Output the following <template/> and continue with the model
88
+ knowledge only:
89
+
90
+ <template>
91
+ <ase-tpl-bullet-secondary/> **WARNING**: grounding found no usable quotes -- falling back to model knowledge.
92
+ </template>
93
+ </if>
94
+
95
+ </if>
96
+
97
+ </step>
98
+
99
+ 3. <step id="STEP 3: Widen Topic via Proximity" condition="<getopt-option-proximity/> is equal `true`">
100
+
101
+ 1. Set <prompt><keywords/></prompt>.
102
+
103
+ 2. <if condition="<getopt-option-ground/> is equal `true`">
104
+ Set <prompt>GROUND <keywords/></prompt>, so the agent grounds
105
+ its determination in Internet/Web facts instead of using model
106
+ knowledge only.
107
+ </if>
108
+
109
+ 3. Determine the *conceptual neighborhood* of <keywords/> by using the
110
+ `ase-meta-proximity` agent in a sub-agent with the following
111
+ tool call:
112
+
113
+ `Agent(
114
+ description: "Determine Conceptual Proximity",
115
+ subagent_type: "ase:ase-meta-proximity",
116
+ prompt: "<prompt/>",
117
+ run_in_background: false
118
+ )`
119
+
120
+ 4. <if condition="the sub-agent returned no usable neighborhood">
121
+ Output the following <template/>, *SKIP* the remaining sub-steps
122
+ of this step, and continue with the quotes harvested in STEP 2
123
+ only:
124
+
125
+ <template>
126
+ <ase-tpl-bullet-secondary/> **WARNING**: proximity agent returned no usable result -- keeping the narrow topic only.
127
+ </template>
128
+ </if>
129
+
130
+ 5. Parse the returned labeled list and set <neighborhood/> to the values
131
+ of its `PARENT:` line (the *broader* topic), of its four
132
+ `SIBLING:` lines (the *same-level* topics), and of its four
133
+ `CHILD:` lines (the *narrower* topics).
134
+
135
+ 6. Harvest quotes for *each* topic of <neighborhood/> exactly as in
136
+ STEP 2 (Harvest Quotes), record the contributing neighborhood
137
+ topic as the *source topic* of each of those quotes, and merge
138
+ the results into <quotes/>.
139
+
140
+ </step>
141
+
142
+ 4. <step id="STEP 4: Classify and Render Quotes">
143
+
144
+ 1. *Classify Quotes*:
145
+
146
+ Classify every quote of <quotes/> along two *orthogonal* axes:
147
+
148
+ - **ATTRIBUTION**:
149
+ A quote is `ATTRIBUTED` if a named *author* and/or a named
150
+ *origin* is known for it, and `ANONYMOUS` otherwise.
151
+
152
+ - **LITERALNESS**:
153
+ A quote is `LITERAL` if its text contains at least one of
154
+ the topic keywords of <keywords/> as a *whole word* --
155
+ matched *case-insensitively* and tolerating *inflections*
156
+ (e.g. `architect` and `architectural` match the keyword
157
+ `architecture`), but *never* as a mere *substring* (e.g.
158
+ `art` does *not* match `architecture`). A quote is
159
+ `THEMATIC` otherwise.
160
+
161
+ Both axes span the four *quadrants*:
162
+
163
+ - `Q1` (`ATTRIBUTED` and `LITERAL`)
164
+ - `Q2` (`ATTRIBUTED` and `THEMATIC`)
165
+ - `Q3` (`ANONYMOUS` and `LITERAL`)
166
+ - `Q4` (`ANONYMOUS` and `THEMATIC`)
167
+
168
+ 2. Finally, reduce <quotes/> to at most <count/> quotes in *total*,
169
+ distributed as evenly as possible across the four quadrants
170
+ and preferring the most relevant and most well-known quote per
171
+ quadrant.
172
+
173
+ 3. *Render Quotes*:
174
+
175
+ Render every quote on its own `○`-prefixed line, with the
176
+ following *suffixes* appended in this order:
177
+
178
+ - ` — *<author/>*, <origin/>` in the two `ATTRIBUTED` quadrants,
179
+ omitting whichever of <author/> and <origin/> is unknown.
180
+
181
+ - ` [from proximity: `<source-topic/>`]` if the quote was
182
+ harvested for a *neighborhood* topic in STEP 3 rather than for
183
+ <keywords/> itself.
184
+
185
+ - ` *(unverified)*` if the exact wording or the attribution of
186
+ the quote could not be established with confidence -- but
187
+ omit this marker for a quote whose wording and attribution
188
+ the Internet/Web search of STEP 2.2 confirmed -- including
189
+ its re-application for a neighborhood topic in STEP 3.
190
+
191
+ Render the single line `○ (none)` for a quadrant without any
192
+ quote. Output the result with the following <template/>:
193
+
194
+ <template>
195
+ <ase-tpl-head title="QUOTES"/>
196
+
197
+ ● **Q1 - ATTRIBUTED / LITERAL**:
198
+ ○ [...]
199
+
200
+ ● **Q2 - ATTRIBUTED / THEMATIC**:
201
+ ○ [...]
202
+
203
+ ● **Q3 - ANONYMOUS / LITERAL**:
204
+ ○ [...]
205
+
206
+ ● **Q4 - ANONYMOUS / THEMATIC**:
207
+ ○ [...]
208
+
209
+ <ase-tpl-foot title="QUOTES"/>
210
+ </template>
211
+
212
+ </step>
213
+
214
+ </flow>
@@ -0,0 +1,109 @@
1
+
2
+ ## NAME
3
+
4
+ `ase-meta-quotes` - Find Quotes on a Topic
5
+
6
+ ## SYNOPSIS
7
+
8
+ `ase-meta-quotes`
9
+ [`--help`|`-h`]
10
+ [`--ground`|`-g`]
11
+ [`--proximity`|`-p`]
12
+ [`--count`|`-c` *count*]
13
+ *topic-keywords*
14
+
15
+ ## DESCRIPTION
16
+
17
+ The `ase-meta-quotes` skill finds *quotes* -- sayings, aphorisms,
18
+ maxims, proverbs, and citations -- for the supplied *topic-keywords* and
19
+ places them into a *2x2 matrix*, reported as four labeled *quadrant*
20
+ sections.
21
+
22
+ Per quote, the skill records its *text*, its *author* (a named person or
23
+ organization, if known), its *origin* (a named work, standard, or
24
+ document, if known), and the topic it was harvested for (its *source
25
+ topic*).
26
+
27
+ The first dimension of the matrix is the *attribution* of a quote: a
28
+ quote is `ATTRIBUTED` when a named author and/or a named origin is known
29
+ for it, and `ANONYMOUS` otherwise. The second dimension is the
30
+ *literalness* of a quote: a quote is `LITERAL` when its text contains at
31
+ least one of the *topic-keywords* as a whole word -- matched
32
+ case-insensitively and tolerating inflections (e.g. `architect` and
33
+ `architectural` match the keyword `architecture`), but never as a mere
34
+ substring (e.g. `art` does not match `architecture`) -- and `THEMATIC`
35
+ otherwise. The two dimensions span the quadrants `Q1`
36
+ (`ATTRIBUTED`/`LITERAL`), `Q2` (`ATTRIBUTED`/`THEMATIC`), `Q3`
37
+ (`ANONYMOUS`/`LITERAL`), and `Q4` (`ANONYMOUS`/`THEMATIC`). A quadrant
38
+ without any quote is rendered as `(none)`.
39
+
40
+ Every quote is rendered on its own line and carries, where applicable,
41
+ the suffixes `— <author>, <origin>` (in the two `ATTRIBUTED`
42
+ quadrants, omitting whichever part is unknown), `[from proximity:
43
+ <source-topic>]` (when the quote was contributed by a neighborhood topic
44
+ under `--proximity` instead of by *topic-keywords* itself), and
45
+ `(unverified)` (when the exact wording or the attribution could not be
46
+ established with confidence). The `(unverified)` marker is dropped as
47
+ soon as the Internet/Web search under `--ground` confirms the wording and
48
+ the attribution of the quote.
49
+
50
+ ## OPTIONS
51
+
52
+ `--ground`|`-g`:
53
+ Gather quotes from the Internet/Web via the `ase-meta-search` skill
54
+ (dispatched in a sub-agent, querying all available search backends)
55
+ *in addition to* -- and never *instead* of -- the model knowledge,
56
+ merge them into the harvest while deduplicating quotes which differ
57
+ only in punctuation, capitalization, or attribution wording, and use
58
+ the search results to confirm the wording and the attribution of the
59
+ found quotes. When combined with `--proximity`, the determination of
60
+ the conceptual neighborhood is grounded in Internet/Web facts as
61
+ well. Should the search return no usable quotes, a warning is emitted
62
+ and the skill falls back to the model knowledge only. Without this
63
+ option, the quotes are derived from model knowledge only.
64
+
65
+ `--proximity`|`-p`:
66
+ Widen the harvest beyond the given topic to its *conceptual
67
+ neighborhood* -- the parent (more general) topic, the four sibling
68
+ (same-level) topics, and the four child (more specialized) topics --
69
+ as determined by the `ase-meta-proximity` agent, which is shared with
70
+ the `ase-meta-proximity` skill. Each of these nine neighborhood
71
+ topics is harvested exactly like the given topic itself. Quotes
72
+ contributed by a neighborhood topic carry that topic in brackets and
73
+ mostly land in the `THEMATIC` quadrants, which is exactly where the
74
+ widening pays off. Should the agent return no usable neighborhood, a
75
+ warning is emitted and the skill continues with the narrow topic
76
+ only. Without this option, only the given topic is harvested.
77
+
78
+ `--count`|`-c` *count*:
79
+ Maximum total number of quotes across all four quadrants (default:
80
+ `8`, i.e. about two quotes per quadrant). The quotes are distributed
81
+ as evenly as possible across the quadrants, preferring the most
82
+ relevant and most well-known quote per quadrant. A non-numeric value
83
+ or a value less than or equal to `0` falls back to the default.
84
+
85
+ ## ARGUMENTS
86
+
87
+ *topic-keywords*:
88
+ The topic keywords the quotes are searched for. They act both as the
89
+ search query and as the keyword set of the *literalness* dimension of
90
+ the matrix.
91
+
92
+ ## EXAMPLES
93
+
94
+ Find quotes from model knowledge:
95
+
96
+ ```text
97
+ ❯ /ase-meta-quotes software architecture
98
+ ```
99
+
100
+ Find a wider set of quotes, grounded in Internet/Web facts and widened
101
+ to the conceptual neighborhood of the topic:
102
+
103
+ ```text
104
+ ❯ /ase-meta-quotes --ground --proximity --count 12 technical debt
105
+ ```
106
+
107
+ ## SEE ALSO
108
+
109
+ [`ase-meta-proximity`](../ase-meta-proximity/help.md), [`ase-meta-search`](../ase-meta-search/help.md), [`ase-meta-eli5`](../ase-meta-eli5/help.md).
@@ -59,9 +59,10 @@ before it is committed.
59
59
  Set the *severity floor* (default `LOW`): findings below the chosen
60
60
  threshold are silently suppressed, ordered `LOW` < `MEDIUM` <
61
61
  `HIGH`. The default `LOW` keeps all findings; `ACCEPTED` findings are
62
- never suppressed. The floor only affects the rendered findings table,
63
- not the overall *verdict*, which is always derived from all findings
64
- before the floor is applied.
62
+ never suppressed. Surviving findings are rendered in *descending
63
+ severity* order `HIGH`, `MEDIUM`, `LOW`, `ACCEPTED`. The floor only
64
+ affects the rendered findings table, not the overall *verdict*, which
65
+ is always derived from all findings before the floor is applied.
65
66
 
66
67
  ## ARGUMENTS
67
68