@rse/ase 0.9.48 → 0.9.49

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 (35) hide show
  1. package/dst/ase-config.js +45 -1
  2. package/dst/ase-guidance.js +89 -0
  3. package/dst/ase-hook.js +17 -6
  4. package/dst/ase-service.js +0 -2
  5. package/dst/ase-setup.js +7 -5
  6. package/dst/ase-statusline.js +28 -4
  7. package/package.json +1 -1
  8. package/plugin/.claude-plugin/plugin.json +1 -1
  9. package/plugin/.codex-plugin/plugin.json +1 -1
  10. package/plugin/.github/plugin/plugin.json +1 -1
  11. package/plugin/meta/ase-common-task.md +9 -0
  12. package/plugin/meta/ase-constitution.md +17 -6
  13. package/plugin/meta/ase-getopt.md +11 -1
  14. package/plugin/meta/ase-skill.md +92 -4
  15. package/plugin/package.json +1 -1
  16. package/plugin/skills/ase-arch-analyze/SKILL.md +8 -6
  17. package/plugin/skills/ase-arch-discover/SKILL.md +12 -0
  18. package/plugin/skills/ase-code-analyze/SKILL.md +6 -4
  19. package/plugin/skills/ase-code-lint/SKILL.md +16 -0
  20. package/plugin/skills/ase-docs-proofread/SKILL.md +10 -0
  21. package/plugin/skills/ase-help-skill/SKILL.md +10 -2
  22. package/plugin/skills/ase-help-skill/catalog.md +1 -1
  23. package/plugin/skills/ase-meta-brainstorm/SKILL.md +8 -0
  24. package/plugin/skills/ase-meta-commit/SKILL.md +13 -0
  25. package/plugin/skills/ase-meta-config/SKILL.md +165 -0
  26. package/plugin/skills/ase-meta-config/help.md +136 -0
  27. package/plugin/skills/ase-meta-diaboli/help.md +1 -1
  28. package/plugin/skills/ase-meta-diff/SKILL.md +22 -0
  29. package/plugin/skills/ase-meta-review/SKILL.md +13 -1
  30. package/plugin/skills/ase-sync-export/SKILL.md +14 -0
  31. package/plugin/skills/ase-sync-import/SKILL.md +10 -0
  32. package/plugin/skills/ase-task-list/SKILL.md +21 -0
  33. package/plugin/skills/ase-task-view/SKILL.md +21 -0
  34. package/plugin/skills/ase-meta-persona/SKILL.md +0 -84
  35. package/plugin/skills/ase-meta-persona/help.md +0 -60
package/dst/ase-config.js CHANGED
@@ -22,7 +22,8 @@ export const projectClassification = {
22
22
  };
23
23
  /* agent classification taxonomy */
24
24
  export const agentClassification = {
25
- persona: ["writer", "engineer", "journalist", "telegrapher", "caveman"]
25
+ persona: ["writer", "engineer", "journalist", "telegrapher", "caveman"],
26
+ guidance: ["none", "minimal", "normal", "verbose"]
26
27
  };
27
28
  /* classification presets */
28
29
  export const projectClassificationPresets = {
@@ -41,6 +42,7 @@ export const projectClassificationPresets = {
41
42
  default: {
42
43
  "agent.task": "default",
43
44
  "agent.persona": "engineer",
45
+ "agent.guidance": "normal",
44
46
  "project.id": "example",
45
47
  "project.name": "Example Project",
46
48
  "project.boxing": "white",
@@ -190,6 +192,7 @@ export const configSchema = v.nullish(v.strictObject({
190
192
  })),
191
193
  agent: v.optional(v.strictObject({
192
194
  persona: v.optional(v.picklist(agentClassification.persona)),
195
+ guidance: v.optional(v.picklist(agentClassification.guidance)),
193
196
  task: v.optional(v.pipe(v.string(), v.minLength(1))),
194
197
  skill: v.optional(v.pipe(v.string(), v.minLength(1)))
195
198
  }))
@@ -768,5 +771,46 @@ export class ConfigMCP {
768
771
  return mcpToolError(err);
769
772
  }
770
773
  });
774
+ /* config list */
775
+ mcp.registerTool("ase_config_list", {
776
+ title: "ASE config list",
777
+ description: "List all effective configuration entries of the layered configuration, " +
778
+ "cascading through the default/user/project/task/session chain up to and " +
779
+ "including the requested `scope`. Returns an `entries` array (in lexicographic " +
780
+ "`key` order) where each item has the dotted `key`, its effective `value`, and " +
781
+ "the `scope` label (\"default\", \"user\", \"project\", \"task:<id>\", or " +
782
+ "\"session:<id>\") that supplied it. For overlapping keys only the value of the " +
783
+ "strongest scope is reported.",
784
+ inputSchema: {
785
+ scope: z.string()
786
+ .describe("scope chain (e.g. \"session:<id>\", \"task:<id>\", \"project\", \"user\")")
787
+ },
788
+ outputSchema: {
789
+ entries: z.array(z.object({
790
+ key: z.string().describe("dotted configuration key"),
791
+ value: z.string().describe("effective configuration value"),
792
+ scope: z.string().describe("scope label which supplied the value")
793
+ })).describe("all effective configuration entries in lexicographic key order")
794
+ }
795
+ }, async (args) => {
796
+ try {
797
+ const scope = parseScope(args.scope);
798
+ const cfg = new Config("config", configSchema, this.log, scope);
799
+ cfg.read();
800
+ const entries = cfg.entries().map((e) => ({
801
+ key: e.key,
802
+ value: String(isScalar(e.value) ? e.value.value : e.value),
803
+ scope: Config.scopeLabel(e.scope)
804
+ }));
805
+ const result = { entries };
806
+ return {
807
+ structuredContent: result,
808
+ content: [{ type: "text", text: JSON.stringify(result) }]
809
+ };
810
+ }
811
+ catch (err) {
812
+ return mcpToolError(err);
813
+ }
814
+ });
771
815
  }
772
816
  }
@@ -0,0 +1,89 @@
1
+ /*
2
+ ** Agentic Software Engineering (ASE)
3
+ ** Copyright (c) 2025-2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
+ ** Licensed under Apache 2.0 <https://spdx.org/licenses/Apache-2.0>
5
+ */
6
+ import { isScalar } from "yaml";
7
+ import { z } from "zod";
8
+ import { Config, configSchema, parseScope, agentClassification } from "./ase-config.js";
9
+ /* reusable functionality: ASE agent guidance level get/set */
10
+ export class Guidance {
11
+ /* allowed guidance level values */
12
+ static levels = agentClassification.guidance;
13
+ /* get the effective guidance level for an optional session;
14
+ returns the default "normal" if nothing is configured */
15
+ static get(log, session) {
16
+ const scope = parseScope(session !== undefined ? `session:${session}` : undefined);
17
+ const cfg = new Config("config", configSchema, log, scope);
18
+ cfg.read();
19
+ const val = cfg.get("agent.guidance");
20
+ if (val === undefined)
21
+ return "normal";
22
+ const level = String(isScalar(val) ? val.value : val);
23
+ return Guidance.levels.find((l) => l === level) ?? "normal";
24
+ }
25
+ /* set the guidance level on the strongest scope of an optional session */
26
+ static set(log, level, session) {
27
+ const scope = parseScope(session !== undefined ? `session:${session}` : undefined);
28
+ const cfg = new Config("config", configSchema, log, scope);
29
+ cfg.lock(() => {
30
+ cfg.read();
31
+ cfg.set("agent.guidance", level);
32
+ cfg.write();
33
+ });
34
+ }
35
+ }
36
+ /* MCP registration entry point for guidance tools */
37
+ export default class GuidanceMCP {
38
+ log;
39
+ constructor(log) {
40
+ this.log = log;
41
+ }
42
+ register(mcp) {
43
+ mcp.registerTool("ase_guidance", {
44
+ title: "ASE guidance level get/set",
45
+ description: "Get or set the active ASE agent guidance `level`. " +
46
+ "If `level` is provided, it sets the guidance level, " +
47
+ "otherwise it returns the current guidance `level`. " +
48
+ "If `session` is provided, the operation is scoped to that session, " +
49
+ "otherwise it operates on the strongest/closest scope (user/project cascade). " +
50
+ "The guidance level controls the amount of unsolicited help hints -- " +
51
+ "pointers to the available ASE skills, their options, and the recommended " +
52
+ "next operations -- the agent emits. " +
53
+ "Allowed levels: \"none\" (no help hints at all), " +
54
+ "\"minimal\" (the single most essential help hint only), " +
55
+ "\"normal\" (the essential help hints only), " +
56
+ "\"verbose\" (all available help hints).",
57
+ inputSchema: {
58
+ level: z.enum(Guidance.levels).optional()
59
+ .describe("guidance level to set; if omitted, the current guidance level is returned"),
60
+ session: z.string().regex(/^[A-Za-z0-9._-]+$/).optional()
61
+ .describe("session identifier (allowed characters: A-Z, a-z, 0-9, '.', '_', '-'); " +
62
+ "if omitted, the operation is not scoped to a specific session")
63
+ }
64
+ }, async (args) => {
65
+ try {
66
+ if (args.level !== undefined) {
67
+ Guidance.set(this.log, args.level, args.session);
68
+ const where = args.session !== undefined ?
69
+ ` for session "${args.session}"` : "";
70
+ const msg = `OK: set agent.guidance to "${args.level}"${where}`;
71
+ return {
72
+ content: [{ type: "text", text: msg }]
73
+ };
74
+ }
75
+ const text = Guidance.get(this.log, args.session);
76
+ return {
77
+ content: [{ type: "text", text }]
78
+ };
79
+ }
80
+ catch (err) {
81
+ const message = err instanceof Error ? err.message : String(err);
82
+ return {
83
+ isError: true,
84
+ content: [{ type: "text", text: `ERROR: ${message}` }]
85
+ };
86
+ }
87
+ });
88
+ }
89
+ }
package/dst/ase-hook.js CHANGED
@@ -249,8 +249,9 @@ export default class HookCommand {
249
249
  const val = cfg.get(key);
250
250
  return typeof val === "string" ? val : (process.env[envVar] ?? dflt);
251
251
  };
252
- /* determine agent persona style and project boxing transparency */
252
+ /* determine agent persona style, agent guidance level, and project boxing transparency */
253
253
  const persona = setting("agent.persona", "ASE_PERSONA_STYLE", "engineer");
254
+ const guidance = setting("agent.guidance", "ASE_GUIDANCE_LEVEL", "normal");
254
255
  const boxing = setting("project.boxing", "ASE_PROJECT_BOXING", "white");
255
256
  /* determine headless mode */
256
257
  const headless = (process.env.ASE_HEADLESS ?? "false") === "true" ? "true" : "false";
@@ -281,6 +282,7 @@ export default class HookCommand {
281
282
  `<ase-version-hint>${versionHint}</ase-version-hint>\n` +
282
283
  `<ase-plugin-root>${pluginRoot}</ase-plugin-root>\n` +
283
284
  `<ase-persona-style>${persona}</ase-persona-style>\n` +
285
+ `<ase-guidance-level>${guidance}</ase-guidance-level>\n` +
284
286
  `<ase-user-id>${userId}</ase-user-id>\n` +
285
287
  `<ase-project-id>${projectId}</ase-project-id>\n` +
286
288
  `<ase-project-boxing>${boxing}</ase-project-boxing>\n` +
@@ -295,11 +297,18 @@ export default class HookCommand {
295
297
  agent harness, independent of any model decision, so it is
296
298
  guaranteed to appear once in every non-headless session;
297
299
  Anthropic Claude Code CLI and OpenAI Codex CLI surface a top-level
298
- "systemMessage" field for this -- GitHub Copilot CLI has no equivalent) */
299
- const banner = `\n⧉ ASE: version: ${versionCurrentPlugin}${versionHint !== "" ? " " + versionHint.replaceAll(/\*/g, "") : ""}` +
300
+ "systemMessage" field for this -- GitHub Copilot CLI has no equivalent);
301
+ the trailing help hint is emitted only if the guidance level asks for it */
302
+ const banner = "\n" +
303
+ `\n⧉ ASE: ⎈ version: ${versionCurrentPlugin}${versionHint !== "" ? " " + versionHint.replaceAll(/\*/g, "") : ""}` +
300
304
  `\n⧉ ASE: ※ user: ${userId}, ⚑ project: ${projectId}` +
301
305
  `\n⧉ ASE: ◉ task: ${taskId}, ⏻ session: ${sessionId}` +
302
- `\n⧉ ASE: ☯ persona: ${persona}, ▢ boxing: ${boxing}`;
306
+ `\n⧉ ASE: ☯ persona: ${persona}, ▶ guidance: ${guidance}, ▢ boxing: ${boxing}` +
307
+ (guidance === "normal" || guidance === "verbose" ?
308
+ "\n" +
309
+ "\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";
303
312
  /* inject markdown into session context.
304
313
  Anthropic Claude Code CLI and OpenAI Codex CLI expect the context nested in
305
314
  "hookSpecificOutput"; GitHub Copilot CLI expects a flat top-level
@@ -314,8 +323,10 @@ export default class HookCommand {
314
323
  };
315
324
  /* attach the deterministic banner as a top-level "systemMessage"
316
325
  (only for the harnesses that support it and only when not
317
- running headless -- mirroring the constitution box condition) */
318
- if ((tool === "claude" || tool === "codex") && headless !== "true")
326
+ running headless -- complementing the constitution box condition,
327
+ which covers exactly the remaining harness GitHub Copilot CLI
328
+ by letting the model emit the banner itself) */
329
+ if ((tool === "claude" || tool === "codex") && headless !== "true" && guidance !== "none")
319
330
  payload.systemMessage = banner;
320
331
  await writeStdout(JSON.stringify(payload));
321
332
  return 0;
@@ -22,7 +22,6 @@ import { TaskMCP } from "./ase-task.js";
22
22
  import { MarkdownMCP } from "./ase-markdown.js";
23
23
  import { ArtifactMCP } from "./ase-artifact.js";
24
24
  import { KVMCP } from "./ase-kv.js";
25
- import PersonaMCP from "./ase-persona.js";
26
25
  import { TimestampMCP } from "./ase-timestamp.js";
27
26
  import { GetoptMCP } from "./ase-getopt.js";
28
27
  import { SkillsMCP } from "./ase-skills.js";
@@ -243,7 +242,6 @@ export default class ServiceCommand {
243
242
  new MarkdownMCP().register(mcp);
244
243
  new ArtifactMCP(this.log).register(mcp);
245
244
  new KVMCP().register(mcp);
246
- new PersonaMCP(this.log).register(mcp);
247
245
  new TimestampMCP().register(mcp);
248
246
  new GetoptMCP().register(mcp);
249
247
  new SkillsMCP().register(mcp);
package/dst/ase-setup.js CHANGED
@@ -575,7 +575,7 @@ export default class SetupCommand {
575
575
  statuslineFormatDflt = [
576
576
  "<blue>%u</blue> <red>%p</red> <black>%T</black> %s",
577
577
  "%m %e %t",
578
- "%P %c"
578
+ "%P %h %c"
579
579
  ];
580
580
  /* resolve the tool settings file for a given installation scope */
581
581
  statuslineSettingsFile(tool, scope) {
@@ -607,8 +607,9 @@ export default class SetupCommand {
607
607
  }
608
608
  /* build the "ase statusline ..." command string from the activate
609
609
  options and the effective format lines */
610
- statuslineCommand(opts, format) {
611
- const parts = ["ase", "statusline", "-w", String(opts.width), "-m", String(opts.margin)];
610
+ statuslineCommand(tool, opts, format) {
611
+ const parts = ["ase", "statusline", "--tool", tool, "-w", String(opts.width), "-m", String(opts.margin),
612
+ "-p", String(opts.padding)];
612
613
  if (!opts.icons)
613
614
  parts.push("--no-icons");
614
615
  if (!opts.labels)
@@ -699,7 +700,7 @@ export default class SetupCommand {
699
700
  this.requireStatuslineTool(tool);
700
701
  this.requireStatuslineScope(tool, scope);
701
702
  const file = this.statuslineSettingsFile(tool, scope);
702
- const command = this.statuslineCommand(opts, format);
703
+ const command = this.statuslineCommand(tool, opts, format);
703
704
  const root = await this.statuslineReadAst(file);
704
705
  const existing = this.statuslineFindMember(root);
705
706
  if (existing !== undefined) {
@@ -923,10 +924,11 @@ export default class SetupCommand {
923
924
  .option("-s, --scope <scope>", "target scope (\"user\", \"project\", or \"local\")", "user")
924
925
  .option("-w, --width <n>", "force terminal width to <n> characters (0 = auto-detect via /dev/tty)", parseNonNeg("width"), 0)
925
926
  .option("-m, --margin <n>", "reduce maximum used terminal width by <n> characters on each side", parseNonNeg("margin"), 2)
927
+ .option("-p, --padding <n>", "pad each rendered line with <n> spaces on each side", parseNonNeg("padding"), 0)
926
928
  .option("--no-icons", "disable icons in placeholder rendering")
927
929
  .option("--no-labels", "disable labels in front of bold values")
928
930
  .action(async (format, opts) => {
929
- process.exit(await this.doStatuslineActivate(this.parseTool(opts.tool), this.parseScope(opts.scope), { width: opts.width, margin: opts.margin, icons: opts.icons, labels: opts.labels }, format ?? []));
931
+ process.exit(await this.doStatuslineActivate(this.parseTool(opts.tool), this.parseScope(opts.scope), { width: opts.width, margin: opts.margin, padding: opts.padding, icons: opts.icons, labels: opts.labels }, format ?? []));
930
932
  });
931
933
  /* register CLI sub-command "ase setup statusline deactivate" */
932
934
  statuslineCmd
@@ -189,9 +189,10 @@ export default class StatuslineCommand {
189
189
  .option("-t, --tool <tool>", "target tool (\"claude\" or \"copilot\"; \"codex\" is unsupported)", toolDflt)
190
190
  .option("-w, --width <n>", "force terminal width to <n> characters (0 = auto-detect via /dev/tty)", parseInteger("--width"), 0)
191
191
  .option("-m, --margin <n>", "reduce maximum used terminal width by <n> characters on each side", parseInteger("--margin"), 2)
192
+ .option("-p, --padding <n>", "pad each rendered line with <n> spaces on each side", parseInteger("--padding"), 0)
192
193
  .option("--no-icons", "disable icons in placeholder rendering")
193
194
  .option("--no-labels", "disable labels in front of bold values")
194
- .argument("[lines...]", "one or more template lines with %u %p %T %s %m %e %t %O %P %c %C %a %r " +
195
+ .argument("[lines...]", "one or more template lines with %u %p %T %s %m %e %t %O %P %h %c %C %a %r " +
195
196
  "%S %D %W %Q %H %X %b %g %G %d %M %V placeholders and <color>...</color> markup " +
196
197
  "(color: black, red, green, yellow, blue, magenta, cyan, white, default) " +
197
198
  "(default: single line \"%m %e %t\")")
@@ -220,9 +221,11 @@ export default class StatuslineCommand {
220
221
  && typeof data.cwd === "string" && data.cwd !== "") {
221
222
  data.workspace = { ...(data.workspace ?? {}), current_dir: data.cwd };
222
223
  }
223
- /* determine effective terminal width and budget */
224
+ /* determine effective terminal width and budget
225
+ (the padding spaces occupy terminal columns, too,
226
+ so they have to be subtracted from the budget) */
224
227
  const width = opts.width > 0 ? opts.width : detectTermWidth();
225
- const budget = width > 0 ? width - 2 * opts.margin : 0;
228
+ const budget = width > 0 ? width - 2 * (opts.margin + opts.padding) : 0;
226
229
  /* shared output state and append helper with auto-wrap;
227
230
  the helper itself strips ANSI CSI escape sequences to
228
231
  measure the raw visible width of the chunk */
@@ -264,20 +267,24 @@ export default class StatuslineCommand {
264
267
  const getCfg = memoize(() => {
265
268
  let taskId = process.env.ASE_TASK_ID ?? "";
266
269
  let persona = process.env.ASE_PERSONA_STYLE ?? "";
270
+ let guidance = process.env.ASE_GUIDANCE_LEVEL ?? "";
267
271
  try {
268
272
  const cfg = new Config("config", configSchema, this.log, parseScope(`session:${getSession()}`));
269
273
  cfg.read("lenient");
270
274
  const t = String(cfg.get("agent.task") ?? "").trim();
271
275
  const p = String(cfg.get("agent.persona") ?? "").trim();
276
+ const g = String(cfg.get("agent.guidance") ?? "").trim();
272
277
  if (t !== "")
273
278
  taskId = t;
274
279
  if (p !== "")
275
280
  persona = p;
281
+ if (g !== "")
282
+ guidance = g;
276
283
  }
277
284
  catch (_e) {
278
285
  /* cascade unavailable; keep env-var fallbacks */
279
286
  }
280
- return { taskId, persona };
287
+ return { taskId, persona, guidance };
281
288
  });
282
289
  const getGit = memoize(() => probeGit(data.workspace?.current_dir ?? ""));
283
290
  const getMem = memoize(() => probeMemory());
@@ -323,6 +330,11 @@ export default class StatuslineCommand {
323
330
  if (persona !== "")
324
331
  emit(`${prefix("☯", "persona")}${c.bold(persona)}`);
325
332
  },
333
+ h: () => {
334
+ const { guidance } = getCfg();
335
+ if (guidance !== "")
336
+ emit(`${prefix("▶", "guidance")}${c.bold(guidance)}`);
337
+ },
326
338
  /* ==== CONTEXT ==== */
327
339
  c: () => {
328
340
  const pct = Math.min(100, Math.max(0, Math.floor(data.context_window?.used_percentage ?? 0)));
@@ -462,6 +474,18 @@ export default class StatuslineCommand {
462
474
  out += "\n";
463
475
  col = 0;
464
476
  }
477
+ /* optionally pad all non-empty lines with spaces on both sides
478
+ (the trailing empty chunk after the final line break and any
479
+ intentionally empty line are left untouched, so that no
480
+ whitespace-only line is produced) */
481
+ if (opts.padding > 0) {
482
+ const pad = " ".repeat(opts.padding);
483
+ out = out.split("\n").map((line) => line !== "" ? `${pad}${line}${pad}` : line).join("\n");
484
+ /* for Copilot, prefix with a zero-width non-breaking space
485
+ to prevent the first line to be unindented */
486
+ if (tool === "copilot")
487
+ out = "\u200B" + out;
488
+ }
465
489
  /* send output */
466
490
  await writeStdout(out);
467
491
  /* optionally publish task id to the calling tmux pane as a per-pane user
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.48",
9
+ "version": "0.9.49",
10
10
  "license": "Apache-2.0",
11
11
  "author": {
12
12
  "name": "Dr. Ralf S. Engelschall",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ase",
3
- "version": "0.9.48",
3
+ "version": "0.9.49",
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.48",
3
+ "version": "0.9.49",
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.48",
3
+ "version": "0.9.49",
4
4
  "description": "Agentic Software Engineering (ASE)",
5
5
  "keywords": [ "agentic", "software", "engineering" ],
6
6
  "homepage": "https://ase.tools",
@@ -45,6 +45,15 @@ Task Skill Common Steps
45
45
  <template>
46
46
  ⧉ **ASE**: ☻ skill: **<arg1/>**, ▶ ERROR: expected single `[<id>]` argument
47
47
  </template>
48
+
49
+ Directly *after* this error <template/>, and *before* stopping,
50
+ give the corrective hint by expanding the following (which,
51
+ depending on the configured <ase-guidance-level/>, may expand into
52
+ nothing and hence emit no output at all):
53
+
54
+ <ase-tpl-hint level="verbose">
55
+ Run `/<arg1/> --help` for the accepted arguments of this skill, or use `/ase-help-intent` to have a fitting command proposed for a free-text intent.
56
+ </ase-tpl-hint>
48
57
  </elseif>
49
58
 
50
59
  </define>
@@ -6,17 +6,28 @@ You are an expert-level AI coding assistant.
6
6
  You have the **Agentic Software Engineering (ASE)** companion toolkit enabled,
7
7
  which boosts you to an expert-level Software Engineering AI agent.
8
8
 
9
- If ((<ase-agent-tool/> is equal to `codex`) *AND* (<ase-headless/> is empty
10
- or not set)) you *MUST* output the following <template/> *exactly once*
11
- as the very *first* thing in your *first* response of this session --
12
- *before* any other text, *before* any tool call, and *before* entering
13
- any skill flow:
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
14
 
15
15
  <template>
16
16
  ⧉ **ASE**: ⎈ version: **<ase-version/>** <ase-version-hint/>
17
17
  ⧉ **ASE**: ※ user: **<ase-user-id/>**, ⚑ project: **<ase-project-id/>**
18
18
  ⧉ **ASE**: ◉ task: **<ase-task-id/>**, ⏻ session: **<ase-session-id/>**
19
- ⧉ **ASE**: ☯ persona: **<ase-persona-style/>**, ▢ boxing: **<ase-project-boxing/>**
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
20
31
  </template>
21
32
 
22
33
  Prohibitions
@@ -76,6 +76,15 @@ set placeholders into the context as a side-effect.
76
76
  ⧉ **ASE**: ✪ skill: **<getopt-skill/>**, ▶ ERROR: option parsing failed: **<text/>**
77
77
  </template>
78
78
 
79
+ Directly *after* this error <template/>, and *before* stopping, give
80
+ the corrective hint by expanding the following (which, depending on
81
+ the configured <ase-guidance-level/>, may expand into nothing and
82
+ hence emit no output at all):
83
+
84
+ <ase-tpl-hint level="verbose">
85
+ Run `/<getopt-skill/> --help` for the accepted options and arguments of this skill.
86
+ </ase-tpl-hint>
87
+
79
88
  5. **Parsing JSON Result**:
80
89
  The tool returned a single `text` content payload containing JSON.
81
90
  Parse this JSON in <text/> now into <getopt-result/> by recognizing
@@ -100,7 +109,8 @@ set placeholders into the context as a side-effect.
100
109
  whose long name starts with `int-`.
101
110
 
102
111
  7. **Display Results**:
103
- Just output the following <template/>:
112
+ If <ase-guidance-level/> is equal to `normal` or `verbose`,
113
+ output the following <template/>:
104
114
 
105
115
  <template>
106
116
  ⧉ **ASE**: ✪ skill: **<getopt-skill/>**, ▶ options: <getopt-info/>
@@ -214,15 +214,17 @@ Skill Identification
214
214
 
215
215
  In case <skill/> later becomes *not* empty by defining it as <skill
216
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`) you *MUST* once output the following output
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
219
220
  <template/>:
220
221
 
221
222
  <template>
222
223
  ⧉ **ASE**: ✪ skill: **<skill-name/>**, ✦ purpose: **<skill/>**, ▶ status: **skill started**
223
224
  </template>
224
225
 
225
- Later (but only if `$1` is *NOT* equal to `-h` or `--help`), once
226
+ Later (but only if ((`$1` is *NOT* equal to `-h` or `--help`) *AND*
227
+ (<ase-guidance-level/> is equal to `normal` or `verbose`))), once
226
228
  this skill finally will stop processing, you *MUST* once output the
227
229
  following output <template/>:
228
230
 
@@ -231,7 +233,8 @@ Skill Identification
231
233
  </template>
232
234
 
233
235
  - *IMPORTANT*: Set <objective></objective> (set to empty).
234
- Then, in case <objective/> later becomes *not* empty,
236
+ Then, in case <objective/> later becomes *not* empty
237
+ (but only if <ase-guidance-level/> is equal to `normal` or `verbose`),
235
238
  you *MUST* once output the following output <template/>:
236
239
 
237
240
  <template>
@@ -292,6 +295,65 @@ Artifact Boxing Transparency
292
295
  deterministically skip or suppress and *win* over the implicit decisions
293
296
  above. Where no such branches exist, the decisions above apply.
294
297
 
298
+ Guidance Hint Level
299
+ -------------------
300
+
301
+ - *IMPORTANT*: The *guidance* of the agent (indicated by
302
+ <ase-guidance-level/> configuration) classifies how many
303
+ *unsolicited hints* -- pointers to the available *ASE* skills, to
304
+ their options, and to the recommended next operations, which the
305
+ user did *not* explicitly ask for -- you *MUST* emit in addition to
306
+ the requested result.
307
+
308
+ - *IMPORTANT*: Guidance modulates only the *hints*, per the four
309
+ levels below. It *MUST* *NOT* alter the *communication style*
310
+ (governed exclusively by the persona), it *MUST* *NOT* alter the
311
+ *work depth* or the *output visibility* (governed exclusively by the
312
+ boxing), and it *MUST* *NOT* suppress, reduce, or expand any
313
+ *requested* output. In particular, guidance *MUST* *NOT* apply to:
314
+
315
+ - the *manual page* emitted for `-h`/`--help`, which is
316
+ explicitly requested,
317
+ - the *skill catalog*, *manual page*, and *command proposal*
318
+ results of the `ase-help-skill` and `ase-help-intent` skills,
319
+ which are explicitly requested,
320
+ - the *option affordance* lines of a user dialog (e.g. `Please
321
+ choose *one* option by typing ...`), which are functional parts
322
+ of the dialog and not hints,
323
+ - the *artifact state* lines of a skill (e.g. `plan loaded`, `plan
324
+ created`, `task given`) and every `ERROR:` line, which carry
325
+ state rather than pointers.
326
+
327
+ The *skill identification* chrome (the `skill started`, `skill
328
+ finished`, and `objective` lines) is the sole exception: it is
329
+ *decoration* rather than result, so it is gated on `normal` and
330
+ `verbose` directly in the `Skill Identification` section above.
331
+
332
+ - *IMPORTANT*: Every hint carries a *level* -- `minimal`, `normal`,
333
+ or `verbose` -- and is emitted only if the configured
334
+ <ase-guidance-level/> *includes* that level:
335
+
336
+ - If <ase-guidance-level/> is `none`:
337
+ - Hints emitted: *none*
338
+ - If <ase-guidance-level/> is `minimal`:
339
+ - Hints emitted: `minimal` -- the *essential* pointers only,
340
+ i.e. those without which the just-produced result cannot be
341
+ consumed at all (such as the follow-up command that turns
342
+ persisted findings into actual changes)
343
+ - If <ase-guidance-level/> is `normal`:
344
+ - Hints emitted: `minimal` *and* `normal` -- additionally the
345
+ *canonical next step* of the finished skill
346
+ - If <ase-guidance-level/> is `verbose`:
347
+ - Hints emitted: `minimal`, `normal`, *and* `verbose` --
348
+ additionally the *unused options* of the current skill, the
349
+ *related* skills, and the *configuration* skills
350
+ - If <ase-guidance-level/> is empty or not set:
351
+ - Treat it as `normal`
352
+
353
+ - *IMPORTANT*: A hint *MUST* be emitted *exclusively* through the
354
+ `<ase-tpl-hint/>` template pattern below, and *never* as free-text
355
+ prose, so that its suppression is uniform across all skills.
356
+
295
357
  Template Patterns
296
358
  -----------------
297
359
 
@@ -347,6 +409,32 @@ Template Patterns
347
409
 
348
410
  </template>
349
411
 
412
+ - When `<ase-tpl-hint level="<level/>"><content/></ase-tpl-hint>`
413
+ should be expanded, first determine whether the hint passes the
414
+ configured guidance level (see `Guidance Hint Level` above):
415
+
416
+ - Set <emit>false</emit>.
417
+ - If <ase-guidance-level/> is `minimal` and <level/> is `minimal`,
418
+ set <emit>true</emit>.
419
+ - If <ase-guidance-level/> is `normal` and <level/> is `minimal`
420
+ or `normal`, set <emit>true</emit>.
421
+ - If <ase-guidance-level/> is `verbose` and <level/> is `minimal`,
422
+ `normal`, or `verbose`, set <emit>true</emit>.
423
+ - If <ase-guidance-level/> is empty or not set, treat it as
424
+ `normal` and apply the corresponding decision above.
425
+
426
+ Then dispatch on <emit/>:
427
+
428
+ <if condition="<emit/> is `true`">
429
+ <template>
430
+ ⧉ **ASE**: ▷ hint [<level/>]: **<content/>**
431
+ </template>
432
+ </if>
433
+ <else>
434
+ This construct is expanded into *nothing*.
435
+ Do not output anything.
436
+ </else>
437
+
350
438
  - When `<ase-tpl-boxline><line/></ase-tpl-boxline>` should be expanded, use:
351
439
 
352
440
  <if condition="<line/> is not empty">
@@ -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.48",
9
+ "version": "0.9.49",
10
10
  "license": "Apache-2.0",
11
11
  "author": {
12
12
  "name": "Dr. Ralf S. Engelschall",
@@ -465,14 +465,16 @@ interface quality, quality attributes, and architecture governance.
465
465
  "<title/>: <description/>" }` entry per reported PROBLEM and one
466
466
  `{ command: "set", key: "ase-issue-T<n/>", val: "<title/>:
467
467
  <description/>" }` entry per reported TRADEOFF.
468
- </step>
469
468
 
470
- 4. <step id="STEP 4: Give Final Hint">
471
- Finally, output the following <template/> to give a final hint:
469
+ Finally, give a final hint by expanding the following (which,
470
+ depending on the configured <ase-guidance-level/>, may expand into
471
+ nothing and hence emit no output at all):
472
+
473
+ <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.
475
+ </ase-tpl-hint>
472
476
 
473
- <template>
474
- ⧉ **ASE**: ↪ hint: **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.**
475
- </template>
476
477
  </step>
478
+
477
479
  </flow>
478
480