@menghuan1918/dsh-apollo 0.4.0 → 0.5.0

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@menghuan1918/dsh-apollo",
3
- "version": "0.4.0",
4
- "description": "DSH plugin: 流程技能、工程模式、Codex/Claude 可续接子代理与统一设置。纯 ESM,无构建步骤。",
3
+ "version": "0.5.0",
4
+ "description": "DSH plugin bundle: workflow skills, engineering presets, independent better-goal / better-subagent / better-compact integration, and a minimal job exit guard. Pure ESM, no build step.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "repository": {
7
7
  "type": "git",
@@ -21,11 +21,12 @@
21
21
  },
22
22
  "scripts": {
23
23
  "test": "node --test",
24
- "prompts": "node scripts/render-prompts.mjs"
24
+ "prompts": "node scripts/render-prompts.mjs",
25
+ "smoke": "node scripts/runtime-smoke.mjs"
25
26
  },
26
27
  "files": [
27
28
  "src",
28
- "docs",
29
+ "docs/DEVELOPMENT.md",
29
30
  "skills",
30
31
  "presets",
31
32
  "third-party",
@@ -53,7 +54,9 @@
53
54
  },
54
55
  "dependencies": {
55
56
  "@deepseek-ai/schemastery": "~3.18.4",
56
- "dsh-better-goal": "0.1.0"
57
+ "@menghuan1918/dsh-better-subagent": "0.1.0",
58
+ "dsh-better-compact": "0.1.0",
59
+ "dsh-better-goal": "0.2.0"
57
60
  },
58
61
  "peerDependencies": {
59
62
  "react": "^18.2.0"
@@ -1,96 +1,84 @@
1
1
  /**
2
- * `eng-exit-guard` — 工程模式退出守卫(预设本地插件)。
2
+ * `eng-exit-guard` — 工程模式退出守卫(预设本地插件),只管后台任务。
3
3
  *
4
- * pi-atlas task guard 的 DSH 等价物:回合即将结束时(`agent/turn-stopping`,
5
- * serial 事件——监听器跑完后 agent-loop 会重查 inbox,`agent.steer()` 加入的
6
- * next-step 消息使回合不关闭),若本代理仍有运行中的直接子代理或后台任务,
7
- * 注入一条提醒强制回合继续,直到 wait_subagent / job_output 等待收取、
8
- * job_kill 停止,或用户中断(被中断的回合在 dispatch 前即 throwIfAborted,
4
+ * pi-atlas task guard 的 DSH 等价物中属于 Apollo 的那一半:回合即将结束时
5
+ * (`agent/turn-stopping`,serial 事件——监听器跑完后 agent-loop 会重查 inbox,
6
+ * `agent.steer()` 加入的 next-step 消息使回合不关闭),若本代理仍有运行中的
7
+ * DSH 后台 job,注入一条提醒强制回合继续,直到 `job_output` 收取、
8
+ * `job_kill` 停止,或用户中断(被中断的回合在 dispatch 前即 throwIfAborted,
9
9
  * 天然不触发本守卫——Esc 始终是逃生口)。
10
10
  *
11
- * 无豁免机制(曾有 exitGuardIgnore 子串清单,因会被用来静默绕过守卫而移除
12
- * ——实测有会话中 agent 被拦一次后自行写入豁免,后续回合全部静默放行):
11
+ * 运行中**直接子代理**的拦截不在这里:0.5.0 起由 dsh-better-subagent 的
12
+ * `childExitGuard` 拥有(`agent/turn-stopping` 上的独立监听器,独立开关)。
13
+ * 本插件只读 Apollo 的 `exitGuard`(job/通用),不导入、不复制子代理判断。
14
+ *
15
+ * 无豁免机制(曾有 exitGuardIgnore 子串清单,因会被用来静默绕过守卫而移除):
13
16
  * 任何存活的后台 job 都必须被收取或停止,回合才能收尾。需要跨回合常驻的
14
17
  * 服务(dev server、watcher)用 pm2/systemd/裸 nohup 等脱离 DSH job 注册表
15
- * 的方式管理——守卫只看本地 job 注册表与直接子代理。
18
+ * 的方式管理——守卫只看本地 job 注册表。
16
19
  *
17
20
  * 每次事件读取当前 profile 的 Apollo Config.exitGuard(默认关闭)。
18
21
  * 设置保存后即时生效;旧配置只由宿主执行一次性导入。
19
- * 查询失败(listChildren / jobs.list 抛错)按 fail-open 处理:告警并放行本次
20
- * 回合结束,避免查询故障把回合卡死。
22
+ * 查询失败(jobs.list 抛错)按 fail-open 处理:告警并放行本次回合结束。
21
23
  *
22
- * 零 bare import(同 wait-subagent 约束);消息构造参照 goal-round-driver /
23
- * repeat-tool-reminder 的 plain-object 模式。
24
+ * 零 bare import(预设本地插件约束);消息 source 使用生产者自有 kind
25
+ * `better-apollo-job-exit-guard`——session format v4 拒绝旧的
26
+ * `{kind:'plugin', plugin}` 形状。
24
27
  */
25
28
 
26
29
  import { currentConfig } from '../../../../src/config.js'
27
30
 
28
31
  export const name = 'eng-exit-guard'
29
32
 
30
- export const inject = ['subagents', 'agents']
31
-
32
33
  /** 后台任务终态(dsh-jobs-local isTerminal 同款)。 */
33
34
  const JOB_TERMINAL = new Set(['completed', 'killed', 'failed'])
34
35
 
36
+ /** Producer-owned source kind accepted by session format v4. */
37
+ export const NOTICE_SOURCE_KIND = 'better-apollo-job-exit-guard'
38
+
35
39
  /** 渲染一条运行项清单行。 */
36
- function lineOf(prefix, id, detail) {
37
- return ` - ${prefix} ${id}${detail === undefined || detail === '' ? '' : ` (${detail})`}`
40
+ function lineOf(job) {
41
+ const detail = job.label === undefined ? job.kind : `${job.label}, ${job.kind}`
42
+ return ` - background job ${job.id} (${detail})`
38
43
  }
39
44
 
40
45
  /**
41
46
  * 构造 steer 提醒消息(模型可见,进入会话日志)。
42
- * @param children - 运行中的直接子代理 listChildren 条目。
43
47
  * @param jobs - 运行中的后台任务快照。
44
48
  * @returns 一条 user 角色的 plugin notice 消息。
45
49
  */
46
- function buildMessage(children, jobs) {
47
- const lines = []
48
- for (const child of children) {
49
- // 0.1.1-rc.2 的条目是 meta:{mode,label},0.1.2 起 mode/label 升为顶级;
50
- // 兼容回退只影响展示措辞,绝不抛错。
51
- lines.push(lineOf('subagent', child.id, child.label ?? child.meta?.label))
52
- }
53
- for (const job of jobs) {
54
- lines.push(lineOf('background job', job.id, job.label === undefined ? job.kind : `${job.label}, ${job.kind}`))
55
- }
50
+ export function buildJobGuardMessage(jobs) {
56
51
  const text = [
57
52
  'This background work is still running, so the turn cannot end yet:',
58
- ...lines,
53
+ ...jobs.map(lineOf),
59
54
  '',
60
- 'Wait for running subagents with wait_subagent (use send_message to continue one), '
61
- + 'collect background command results with job_output, and stop work you no longer need with job_kill. Finish only after all of it is handled.',
55
+ 'Collect background command results with job_output, and stop work you no longer need with job_kill. '
56
+ + 'Finish only after all of it is handled.',
62
57
  ].join('\n')
63
58
  return {
64
59
  role: 'user',
65
60
  content: [{ type: 'text', text }],
66
61
  source: {
67
- kind: 'plugin',
68
- plugin: 'eng-exit-guard',
62
+ kind: NOTICE_SOURCE_KIND,
69
63
  form: 'notice',
70
- summary: `运行中的后台工作阻止回合结束(子代理 ${children.length},后台任务 ${jobs.length})`,
64
+ summary: `运行中的后台任务阻止回合结束(${jobs.length})`,
71
65
  },
72
66
  id: crypto.randomUUID(),
73
67
  }
74
68
  }
75
69
 
76
70
  /**
77
- * 收集本代理仍在运行的后台工作。
78
- * @param ctx - 预设插件上下文(subagents / agents 注入,jobs 可选)。
71
+ * 收集本代理仍在运行的后台任务。
72
+ * @param ctx - 预设插件上下文(jobs 可选,经 ctx.get 读取)。
79
73
  * @param agent - 回合即将结束的代理。
80
- * @returns `{ children, jobs }`;查询失败抛出由调用方按 fail-open 处理。
74
+ * @returns 运行中的 job 数组;查询失败抛出由调用方按 fail-open 处理。
81
75
  */
82
- async function collectRunning(ctx, agent) {
83
- const children = []
84
- for (const entry of await ctx.subagents.listChildren(agent.id)) {
85
- if (ctx.agents.get(entry.id)?.status === 'running') children.push(entry)
86
- }
76
+ export function collectRunningJobs(ctx, agent) {
87
77
  const jobs = ctx.get('jobs')
88
- const runningJobs = jobs === undefined
89
- ? []
90
- // 0.1.7 起 JobRegistry.list 的参数是 SessionId(0.1.6 及以前是 Agent 对象):
91
- // 传 Agent 对象不报错但恒不匹配,守卫会静默看不见任何 owned 后台任务。
92
- : jobs.list(agent.id).filter((job) => !JOB_TERMINAL.has(job.status))
93
- return { children, jobs: runningJobs }
78
+ if (jobs === undefined) return []
79
+ // 0.1.7 起 JobRegistry.list 的参数是 SessionId(0.1.6 及以前是 Agent 对象):
80
+ // 传 Agent 对象不报错但恒不匹配,守卫会静默看不见任何 owned 后台任务。
81
+ return jobs.list(agent.id).filter((job) => !JOB_TERMINAL.has(job.status))
94
82
  }
95
83
 
96
84
  export function apply(ctx) {
@@ -99,10 +87,10 @@ export function apply(ctx) {
99
87
  if (agent === undefined || payload?.signal?.aborted) return
100
88
  try {
101
89
  if (!currentConfig(ctx).exitGuard) return
102
- const { children, jobs } = await collectRunning(ctx, agent)
103
- if (children.length === 0 && jobs.length === 0) return
90
+ const jobs = collectRunningJobs(ctx, agent)
91
+ if (jobs.length === 0) return
104
92
  if (payload.signal?.aborted) return
105
- agent.steer(buildMessage(children, jobs))
93
+ agent.steer(buildJobGuardMessage(jobs))
106
94
  } catch (error) {
107
95
  // fail-open:查询或注入失败时放行本次回合结束,守卫不应卡死会话。
108
96
  ctx.logger?.warn?.(`eng-exit-guard: guard skipped: ${error instanceof Error ? error.message : String(error)}`)
@@ -2,34 +2,29 @@
2
2
  * `eng-mode-instructions` — preset-scoped prompt section for 工程模式
3
3
  * (`eng`) and 工程(PTC)模式 (`eng-ptc`).
4
4
  *
5
- * Carries what no other surface states: the general engineering discipline
6
- * (moved out of the user-global ~/.dsh/AGENTS.md, which keeps only
7
- * machine-local conventions), the delegation policy, the subagent model tiers
8
- * rendered from Apollo settings (`tiers.*`), and the exit guard contract while
9
- * that switch is on. Tool mechanics, background-job etiquette and run_code
10
- * syntax live in the harness prompt and tool descriptions and are NOT
11
- * repeated here.
5
+ * 0.5.0 boundary: this section carries ONLY what still belongs to Apollo — the
6
+ * general engineering discipline (moved out of the user-global ~/.dsh/AGENTS.md,
7
+ * which keeps only machine-local conventions) and the job-only exit-guard
8
+ * contract while that switch is on.
12
9
  *
13
- * The text is a function re-rendered per request from the live Apollo config,
14
- * so settings edits apply without remounting; an edit costs the prefix cache
15
- * once, which is acceptable for rarely changed settings. The row config
16
- * `ptc: true` (set by eng-ptc) adds a rule for fanning out subagents inside
17
- * one run_code program (workflow usage is left to the harness tool guidance); run_code mechanics themselves
18
- * come from the harness `tools:sdk` / `tools:ptc-only` sections.
10
+ * Subagent delegation, fast/quality model tiers, PTC fan-out, the CLI catalog
11
+ * and the running-child guard are owned by dsh-better-subagent's per-Agent
12
+ * prompt sections (registered on `agent/created`). Apollo keeps no second
13
+ * generator and no `ptc` switch: the new plugin detects `eng-ptc` itself.
14
+ * Tool mechanics, background-job etiquette and run_code syntax live in the
15
+ * harness prompt and tool descriptions and are not repeated here.
16
+ *
17
+ * The text is a function re-rendered per request from the live Apollo config, so
18
+ * settings edits apply without remounting; an edit costs the prefix cache once,
19
+ * which is acceptable for rarely changed settings.
19
20
  */
20
21
 
21
- import z from '@deepseek-ai/schemastery'
22
22
  import { currentConfig } from '../../../../src/config.js'
23
23
 
24
24
  export const name = 'eng-mode-instructions'
25
25
 
26
26
  export const inject = ['systemPrompt']
27
27
 
28
- export const Config = z.object({
29
- /** Render the PTC variant (eng-ptc). */
30
- ptc: z.boolean().default(false),
31
- })
32
-
33
28
  const PRINCIPLES = `# Engineering mode
34
29
 
35
30
  For coding and infrastructure work. These are defaults; explicit user instructions take precedence.
@@ -69,56 +64,25 @@ For coding and infrastructure work. These are defaults; explicit user instructio
69
64
  - Never sleep longer than 60s at once; for longer waits use stepped probes, sentinel files, or completion notices.
70
65
  - Run services that must outlive the turn (dev servers, watchers) under pm2/nohup outside the job registry, and say which ones are still running when you finish.`
71
66
 
72
- const DELEGATION_HEAD = `## Delegation
73
- - Subagents cannot see this conversation: state the goal, write scope, deliverable, and verification, and give real file paths for prior outputs.
74
- - Opening reconnaissance: when starting non-trivial work in an unfamiliar or large codebase, immediately dispatch fast-tier scouts in parallel (structure, relevant modules, conventions, test entry points), all in one message; the main agent reads only the instruction files that define the task. A scout prompt needs only goal, boundaries, and deliverable.
75
- - Delegate read-only, parallelizable, stateless investigation by default instead of trying it in the main thread first; when a new unknown appears mid-task and 1–2 rounds of digging do not converge, delegate it.
76
- - Implementation chunks with non-overlapping write scopes can run in parallel; keep linear work, tightly coupled changes, and debugging that needs live state in the main thread.`
77
-
78
- const FANOUT_PTC = '- For repeated same-shaped work, dispatch all subagents inside one run_code program, then collect them with wait_subagent.'
79
-
80
- const DELEGATION_TAIL = `- When you need a subagent's result, wait patiently with wait_subagent. Do not poll or prod it with send_message; send a message only to give it genuinely new information or a correction.
81
- - The main agent owns integration, review, and final verification. Subagent reports are leads, not evidence: check the actual changes yourself.
82
- - When a subagent ends in an error or empty result, read why, fix the cause, and re-dispatch once; take over in the main thread only if it fails again without an external blocker, and say why.`
83
-
84
- const EXIT_GUARD = `## Exit guard
85
- - If subagents or background commands are still running when the turn would end, the system injects a reminder and the turn continues. Collect them with wait_subagent / job_output, stop unneeded ones with job_kill, then finish.`
86
-
87
- /** One tier as model-facing argument text; an unset tier inherits the parent route. */
88
- export function renderTier(tier) {
89
- if (!tier?.provider || !tier?.model) return 'omit provider / model / reasoning_effort to inherit the parent route'
90
- const parts = [`provider: \`${tier.provider}\``, `model: \`${tier.model}\``]
91
- if (tier.reasoningEffort) parts.push(`reasoning_effort: \`${tier.reasoningEffort}\``)
92
- return parts.join(' · ')
93
- }
67
+ const JOB_EXIT_GUARD = `## Exit guard
68
+ - If background commands are still running when the turn would end, the system injects a reminder and the turn continues. Collect them with job_output, stop unneeded ones with job_kill, then finish.`
94
69
 
95
70
  /**
96
- * Render the full section text.
97
- * @param config - normalized Apollo config (`exitGuard`, `tiers`).
98
- * @param options - `{ ptc }` from this row's config.
71
+ * Render the section text.
72
+ * @param config - normalized Apollo config (`exitGuard`).
99
73
  * @returns the section markdown.
100
74
  */
101
- export function renderInstructions(config, options = {}) {
102
- const tiers = `## Subagent model tiers
103
- - Fast tier (exploration, reconnaissance, mechanical analysis, batch triage): ${renderTier(config.tiers?.fast)}
104
- - Quality tier (complex implementation, debugging, review, design): ${renderTier(config.tiers?.quality)}
105
- - Start exploration on the fast tier; when coverage falls short or key questions remain, re-dispatch the unresolved part on the quality tier. Escalating means re-dispatching, not modifying an existing subagent.
106
- - subagent_fork takes no model choice: it keeps the parent route to reuse the prefix cache.`
107
- const blocks = [
108
- PRINCIPLES,
109
- [DELEGATION_HEAD, ...(options.ptc ? [FANOUT_PTC] : []), DELEGATION_TAIL].join('\n'),
110
- tiers,
111
- ]
112
- if (config.exitGuard) blocks.push(EXIT_GUARD)
75
+ export function renderInstructions(config) {
76
+ const blocks = [PRINCIPLES]
77
+ if (config?.exitGuard) blocks.push(JOB_EXIT_GUARD)
113
78
  return blocks.join('\n\n')
114
79
  }
115
80
 
116
- export function apply(ctx, config) {
117
- const options = { ptc: config?.ptc === true }
81
+ export function apply(ctx) {
118
82
  ctx.effect(() => ctx.systemPrompt.section({
119
83
  name: 'eng:mode-instructions',
120
84
  order: 1,
121
85
  interpolate: false,
122
- text: () => renderInstructions(currentConfig(ctx), options),
86
+ text: () => renderInstructions(currentConfig(ctx)),
123
87
  }), 'eng-mode-instructions.section()')
124
88
  }
@@ -7,8 +7,9 @@
7
7
  # run_code TypeScript SDK (needs the host `ptc-runtime` row);
8
8
  # - `workflow-ptc` and `tool-workflow` disabled: PTC fans out by calling
9
9
  # subagent several times inside one run_code program instead;
10
- # plus `eng-mode-instructions { ptc: true }`, which adds the rule for fanning
11
- # out subagents inside one run_code program. Preset-local plugins reuse the eng modules.
10
+ # Preset-local plugins reuse the eng modules. Subagent fan-out wording is owned
11
+ # by dsh-better-subagent (it detects the `eng-ptc` preset itself), so this row
12
+ # carries no `ptc` switch.
12
13
  # tests/upstream-drift.test.mjs checks this file against both eng and the
13
14
  # upstream `ptc` preset; edit eng first, then redo these deltas.
14
15
  #
@@ -96,8 +97,8 @@
96
97
  compaction: true
97
98
  toolResultPruner: true
98
99
  config:
99
- - id: compaction-basic
100
- name: '@deepseek-ai/dsh-compaction-basic'
100
+ - id: dsh-better-compact-engine
101
+ name: dsh-better-compact/engine
101
102
 
102
103
  - id: command-compact
103
104
  name: '@deepseek-ai/dsh-command-compact'
@@ -174,13 +175,8 @@
174
175
  name: '@deepseek-ai/dsh-plugin-market/tools'
175
176
  disabled: true
176
177
 
177
- - id: tool-wait-subagent
178
- name: '@menghuan1918/dsh-apollo/presets/eng/plugins/wait-subagent/index.js'
179
-
180
178
  - id: eng-exit-guard
181
179
  name: '@menghuan1918/dsh-apollo/presets/eng/plugins/exit-guard/index.js'
182
180
 
183
181
  - id: eng-mode-instructions
184
182
  name: '@menghuan1918/dsh-apollo/presets/eng/plugins/mode-instructions/index.js'
185
- config:
186
- ptc: true
@@ -179,15 +179,20 @@
179
179
 
180
180
  # ── compaction ──────────────────────────────────────────────────────────────
181
181
 
182
- # `compaction-basic` reads `toolResultPrune` through `ctx.get`, so the pruner must
183
- # share this realm rather than sit outside it.
182
+ # The compaction service is preset-owned in the Web composition. The
183
+ # native `compaction-basic` row is replaced by the independent
184
+ # dsh-better-compact engine (same stable row id/name as its standalone
185
+ # bundle); it keeps the native token meter, safe-cut selection,
186
+ # retention, locking, durable checkpoint transaction and `/compact`,
187
+ # and adds the native/goal/handoff summary modes. The host-plane
188
+ # engine inserted by the top-level patch detects this preset-owned
189
+ # service and stays out of the way, so there is one engine per realm.
184
190
  #
185
- # `tokenMeter` is deliberately NOT in this realm: the meter stays on the HOST
186
- # plane, and the rows here resolve that one instance. It takes no configuration,
187
- # keys every fold by Session, and owns the context-meter projection units the
188
- # browser reads for every session — behind a realm those units would come and go
189
- # with whichever presets happen to be mounted. What a preset chooses is whether
190
- # its agent compacts at all, which is `compaction-basic` below.
191
+ # The engine reads `toolResultPrune` through `ctx.get`, so the pruner
192
+ # must share this realm rather than sit outside it.
193
+ #
194
+ # `tokenMeter` is deliberately NOT in this realm: the meter stays on the
195
+ # HOST plane, and the rows here resolve that one instance.
191
196
  - id: compaction
192
197
  name: cordis:group
193
198
  group: true
@@ -195,8 +200,8 @@
195
200
  compaction: true
196
201
  toolResultPruner: true
197
202
  config:
198
- - id: compaction-basic
199
- name: '@deepseek-ai/dsh-compaction-basic'
203
+ - id: dsh-better-compact-engine
204
+ name: dsh-better-compact/engine
200
205
 
201
206
  - id: command-compact
202
207
  name: '@deepseek-ai/dsh-command-compact'
@@ -301,38 +306,26 @@
301
306
  name: '@deepseek-ai/dsh-plugin-market/tools'
302
307
  disabled: true
303
308
 
304
- # ── subagent waiting ─────────────────────────────────────────────────────────
305
-
306
- # Preset-local plugin: explicit wait for one continuable child to settle, so
307
- # the agent can block on a specific subagent (pi-style await_task semantics)
308
- # without giving up send_message continuations. The module specifier is a
309
- # bare subpath of this package (@menghuan1918/dsh-apollo/presets/eng/plugins/...):
310
- # config.plugins names resolve from the profile directory's node_modules,
311
- # where this package is installed or linked; it has zero bare imports on
312
- # purpose.
313
- - id: tool-wait-subagent
314
- name: '@menghuan1918/dsh-apollo/presets/eng/plugins/wait-subagent/index.js'
315
-
316
309
  # ── exit guard ───────────────────────────────────────────────────────────────
317
310
  #
318
- # Preset-local plugin: pi-atlas 式退出守卫。回合结束(agent/turn-stopping)
319
- # 时若有运行中的直接子代理或后台任务,注入 next-step 提醒(agent.steer)
320
- # 强制回合继续,直到 wait_subagent / job_output / job_kill 处理完毕或用户
321
- # 中断(被中断回合不触发)。开关为正式 Config.exitGuard,默认关闭,
322
- # 每次事件读取当前值,设置保存后即时生效。监听器注册型
323
- # 插件,无服务发布,无需 realm。
311
+ # Preset-local plugin: pi-atlas 式退出守卫(仅后台任务)。回合结束
312
+ # (agent/turn-stopping)时若本会话仍有运行中的 DSH 后台 job,注入
313
+ # next-step 提醒(agent.steer)强制回合继续,直到 job_output / job_kill
314
+ # 处理完毕或用户中断(被中断回合不触发)。运行中子代理的拦截由
315
+ # dsh-better-subagent 的 childExitGuard 拥有,这里不再重复判断。开关为
316
+ # Apollo Config.exitGuard,默认关闭,每次事件读取当前值,设置保存后即时
317
+ # 生效。监听器注册型插件,无服务发布,无需 realm。
324
318
  - id: eng-exit-guard
325
319
  name: '@menghuan1918/dsh-apollo/presets/eng/plugins/exit-guard/index.js'
326
320
 
327
321
  # ── mode instructions ────────────────────────────────────────────────────────
328
322
 
329
- # Preset-local prompt section carrying the engineering discipline (moved out
330
- # of the user-global ~/.dsh/AGENTS.md), the delegation policy, the model
331
- # tiers rendered from Apollo settings (`tiers.*`), and the exit guard
332
- # contract when that switch is on. Registered as a system-prompt section
333
- # (order 1, right after the persona slot) so it is scoped to sessions
334
- # mounted on this preset; its text is re-rendered per request from the live
335
- # Apollo config. `ptc: true` (set by eng-ptc) adds the rule for fanning
336
- # out subagents inside one run_code program.
323
+ # Preset-local prompt section carrying only the general engineering
324
+ # discipline (moved out of the user-global ~/.dsh/AGENTS.md) and the
325
+ # job-only exit guard contract. Subagent delegation, model tiers, PTC
326
+ # fan-out and the child guard are rendered by dsh-better-subagent's own
327
+ # per-Agent sections — Apollo keeps no second generator. Registered as a
328
+ # system-prompt section (order 1, right after the persona slot) and
329
+ # re-rendered per request from the live Apollo config.
337
330
  - id: eng-mode-instructions
338
331
  name: '@menghuan1918/dsh-apollo/presets/eng/plugins/mode-instructions/index.js'