@quill507/dsh-orchestrator-preset 0.1.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/.gitattributes +20 -0
- package/.gitignore +140 -0
- package/LICENSE +21 -0
- package/README.md +533 -0
- package/README.zh.md +222 -0
- package/THIRD_PARTY_NOTICES.md +67 -0
- package/cordis.patch.yml +399 -0
- package/extensions/dsh/aegis-prefix.js +197 -0
- package/extensions/dsh/index.js +41 -0
- package/install.sh +193 -0
- package/lane-composition.mjs +288 -0
- package/package.json +69 -0
- package/personas/analyst.md +74 -0
- package/personas/archivist.md +75 -0
- package/personas/auditor.md +79 -0
- package/personas/forge.md +101 -0
- package/personas/orchestrator.md +176 -0
- package/personas/planner.md +114 -0
- package/personas/reader.md +56 -0
- package/personas/scout.md +60 -0
- package/personas/seer.md +69 -0
- package/personas/wright.md +58 -0
- package/plan-aware-persona.mjs +102 -0
- package/routing-sections.mjs +120 -0
- package/skills/orch-delegation-brief/SKILL.md +55 -0
- package/skills/orch-discussion-protocol/SKILL.md +61 -0
- package/skills/orch-evidence-protocol/SKILL.md +88 -0
- package/skills/orch-real-path-testing/SKILL.md +66 -0
- package/tools/audit-personas.mjs +215 -0
- package/tools/gen-cordis-patch.mjs +424 -0
- package/tools/preset-declaration.mjs +468 -0
- package/tools/verify-install.sh +643 -0
package/README.md
ADDED
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
# dsh-orchestrator-preset
|
|
2
|
+
|
|
3
|
+
A thin-shell agent preset for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness):
|
|
4
|
+
the **aegis methodology pack** (upstream, consumed at runtime, unmodified) plus a
|
|
5
|
+
**self-authored orchestration layer** — nine named lanes with mechanically declared tool
|
|
6
|
+
boundaries, resident routing sections, a plan-aware persona, and an evidence-based
|
|
7
|
+
completion gate.
|
|
8
|
+
|
|
9
|
+
The repository root **is** the bundle. There is no `bundle/` subdirectory: the files here
|
|
10
|
+
are exactly the files that get installed.
|
|
11
|
+
|
|
12
|
+
[English](README.md) · [中文](README.zh.md)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Design
|
|
17
|
+
|
|
18
|
+
> **This section is the current and complete authority for what this preset is and how it
|
|
19
|
+
> works.** There is no separate design specification in this repository: the full design
|
|
20
|
+
> draft this grew out of — about 280K of design history, decision trail and rejected
|
|
21
|
+
> alternatives — is **not distributed here**. It is held back, and this section is the
|
|
22
|
+
> design description in its place. If you want the deeper reasoning, ask; it is not linked
|
|
23
|
+
> because a link to a file this repository does not contain would look authoritative and
|
|
24
|
+
> fail on click.
|
|
25
|
+
|
|
26
|
+
### What it is
|
|
27
|
+
|
|
28
|
+
DSH has no notion of an agent that delegates. A preset declares a set of tools and a
|
|
29
|
+
persona; nothing in that vocabulary says "this work belongs to someone else". This preset
|
|
30
|
+
supplies that missing layer. The orchestrator does not write code, search a codebase, or
|
|
31
|
+
review its own output — it routes each piece to a lane that is *declared* to be allowed to
|
|
32
|
+
do it, and then judges the result against evidence on disk.
|
|
33
|
+
|
|
34
|
+
### Lanes and their tool boundaries
|
|
35
|
+
|
|
36
|
+
Nine lanes are rows of the preset itself: `planner`, `scout`, `archivist`, `seer`,
|
|
37
|
+
`reader`, `analyst`, `auditor`, `wright`, `forge`. Each carries its own persona file and
|
|
38
|
+
its own `toolFilter`, so a lane's capability boundary is **declarative, not advisory** — a
|
|
39
|
+
read-only lane's `deny` list removes `write`, `edit`, `todo_write`, every other lane's
|
|
40
|
+
dispatch tool, and the lead-side child-addressing tools from its seat. The deny lists are
|
|
41
|
+
what keep a lane from re-entering the coordinator role.
|
|
42
|
+
|
|
43
|
+
`lane-composition.mjs` closes a gap the host leaves open. A Team assembly gives the lead
|
|
44
|
+
`send_message` / `list_agents` / `interrupt_agent`, which address teammates **by name** and
|
|
45
|
+
cannot reach a `subagent_*` child at all — so a lead delegating through `subagent_*` lanes
|
|
46
|
+
would have no way to list, continue, or interrupt them. This bundle registers exactly those
|
|
47
|
+
three actions under distinct names (`subagent_children`, `subagent_send`,
|
|
48
|
+
`subagent_interrupt`), addressed by **durable agent id**. Two id namespaces, never mixed.
|
|
49
|
+
The three names are registered *globally* on purpose: `tools.restrict()` resolves against
|
|
50
|
+
the global registry, so a scoped registration would make every lane's deny entry illegal and
|
|
51
|
+
take the whole lane family down.
|
|
52
|
+
|
|
53
|
+
### Routing sections
|
|
54
|
+
|
|
55
|
+
`routing-sections.mjs` registers four **static** text sections that are reassembled every
|
|
56
|
+
turn by the host's `systemPrompt` registry: the domain-owner table, the trigger-arbitration
|
|
57
|
+
table, a short index of standing judgements, and the MCP discipline. They are static
|
|
58
|
+
constants on purpose — a dynamic system prefix invalidates the session cache wholesale.
|
|
59
|
+
|
|
60
|
+
The single-owner rule is the point. The MCP discipline lives in exactly one section, the
|
|
61
|
+
orchestrator persona carries one pointer to it, and a delegation brief may *reference* it
|
|
62
|
+
but must never restate it. The same discipline governs the orchestration layer's own
|
|
63
|
+
content: the orchestrator persona explicitly disclaims the lane roster and the MCP rules,
|
|
64
|
+
because a second copy is a second owner.
|
|
65
|
+
|
|
66
|
+
**The four `orch-*` skill names are load-bearing, and renaming one is a two-file edit.**
|
|
67
|
+
`routing-sections.mjs` and `personas/orchestrator.md` both name `orch-evidence-protocol` and
|
|
68
|
+
`orch-delegation-brief` explicitly, and the routing table's rows resolve by that exact
|
|
69
|
+
string. Rename a skill directory and its frontmatter but not those references, and the row
|
|
70
|
+
keeps pointing at a name nothing provides — which is a silent failure, because a routing
|
|
71
|
+
entry that matches no skill simply never fires. `node tools/gen-cordis-patch.mjs` and
|
|
72
|
+
`node tools/audit-personas.mjs` catch a half-finished rename; neither is run automatically,
|
|
73
|
+
so run one after touching a skill name.
|
|
74
|
+
|
|
75
|
+
The `orch-` prefix itself is not decoration: these skills land in a registry that also holds
|
|
76
|
+
whatever else a given machine has installed, so an unprefixed `evidence-protocol` would be a
|
|
77
|
+
name waiting to collide.
|
|
78
|
+
|
|
79
|
+
### Evidence and state
|
|
80
|
+
|
|
81
|
+
Completion is a file, not a sentence. A task counts as done only when
|
|
82
|
+
`.dsh/evidence/<task-id>-<slug>.md` exists, is non-empty, and carries exactly one anchored
|
|
83
|
+
verdict line as its last line. Every path touched in a turn is classified at completion as
|
|
84
|
+
`in_scope`, `out_of_scope`, `undeclared` or `illegal`, and anything but `in_scope` blocks
|
|
85
|
+
the completion claim. State that must outlive a session — the lane ledger
|
|
86
|
+
(`.dsh/state/lanes.md`), direction-level ownership claims (`.dsh/state/claims.md`) and
|
|
87
|
+
goal frames (`.dsh/goals/<slug>.md`) — lives in files, so that a claim can be checked
|
|
88
|
+
against what other writers also see.
|
|
89
|
+
|
|
90
|
+
### How this differs from the upstream aegis pack
|
|
91
|
+
|
|
92
|
+
aegis supplies **method**: how to write a plan, run strict TDD, debug systematically, run a
|
|
93
|
+
review, verify before claiming done. It is a library of skills, and it assumes a single
|
|
94
|
+
coordinator doing the work.
|
|
95
|
+
|
|
96
|
+
This preset supplies **topology**: who does what, under which tool restrictions, with which
|
|
97
|
+
evidence. The two are orthogonal and complementary — aegis skills are routed *to* lanes
|
|
98
|
+
rather than executed in place. What the preset adds that aegis structurally cannot is
|
|
99
|
+
everything that presupposes more than one agent: the lane ledger and its three states, the
|
|
100
|
+
direction-level atomic claim with a staleness criterion for cross-session ownership, and
|
|
101
|
+
the independent-review rule. Those are not extensions to aegis; they are a different axis,
|
|
102
|
+
and no aegis skill is modified to accommodate them.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Sourcing: what is upstream, what was measured here
|
|
107
|
+
|
|
108
|
+
Being precise about this matters more than it usually does, because a preset is a pile of
|
|
109
|
+
claims about someone else's runtime.
|
|
110
|
+
|
|
111
|
+
| Claim | Status |
|
|
112
|
+
|---|---|
|
|
113
|
+
| A bundle declares a patch via the `dsh.bundle.patch` field in its `package.json`, e.g. `"patch": "./cordis.patch.yml"`. | **Upstream contract.** Verbatim in the published `@deepseek-ai/dsh-base` manifest, which also exports the patch as a subpath. |
|
|
114
|
+
| Later patch layers win, and a patch **replaces the whole row** rather than deep-merging it — so a row overriding `config` must restate every key it needs. | **Corroborated twice, independently.** |
|
|
115
|
+
| Exact layer order: bundle patches in `dsh.profile.bundles` order, then the profile's own `cordis.patch.yml`, then `$DSH_HOME/cordis.patch.yml`, then each `--patch` overlay. | **Verified on host version 0.2.0-rc.1.** Not confirmed against upstream documentation. |
|
|
116
|
+
| A profile lives at `~/.dsh/profiles/<name>/` containing `cordis.yml`, `cordis.patch.yml` and `package.json`. | **Verified on host version 0.2.0-rc.1.** Not confirmed against upstream documentation. |
|
|
117
|
+
| `config.selectedDefault` is in the preset schema and is the effective value; the schema also carries `config.default`, and `defaultId` resolves `selectedDefault ?? default`. | **Verified on host version 0.2.0-rc.1**, against `@deepseek-ai/dsh-agent-preset-registry`. |
|
|
118
|
+
|
|
119
|
+
DeepSeek Harness is MIT-licensed: [`github.com/deepseek-ai/deepseek-harness`](https://github.com/deepseek-ai/deepseek-harness).
|
|
120
|
+
Unrelated projects sharing a similar name are not a source for anything in this repository.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Repository layout
|
|
125
|
+
|
|
126
|
+
| Path | What it is |
|
|
127
|
+
|---|---|
|
|
128
|
+
| `cordis.patch.yml` | **Generated.** The preset's rows. Do not edit by hand — see below. |
|
|
129
|
+
| `tools/preset-declaration.mjs` | **The single source of truth** for the preset's rows. |
|
|
130
|
+
| `tools/gen-cordis-patch.mjs` | Generates `cordis.patch.yml` from the declaration. |
|
|
131
|
+
| `tools/audit-personas.mjs` | Static audit of the persona files (originality thresholds against an excluded upstream corpus). |
|
|
132
|
+
| `plan-aware-persona.mjs` | Swaps the persona between Orchestrator and Planner per assembly. |
|
|
133
|
+
| `routing-sections.mjs` | The four resident routing sections. |
|
|
134
|
+
| `lane-composition.mjs` | The three durable-agent-id child-addressing tools. |
|
|
135
|
+
| `personas/` | Ten persona files: orchestrator, planner, and one per lane. |
|
|
136
|
+
| `skills/` | The four self-authored `orch-*` skills. This directory is the authoritative list of them. |
|
|
137
|
+
| `extensions/dsh/` | The bundle's two plugins: the skills provider, and the aegis prefix bridge. |
|
|
138
|
+
| `docs/` | **Not distributed.** The design history is held back; the Design section above is the specification. |
|
|
139
|
+
| `install.sh` | Installs everything below into a DSH home. |
|
|
140
|
+
| `tools/verify-install.sh` | Twenty read-only checks that the preset is installed and selected. |
|
|
141
|
+
| `README.zh.md` | The Chinese README. Same content, same obligations. |
|
|
142
|
+
| `LICENSE` | MIT, plus third-party attribution. |
|
|
143
|
+
|
|
144
|
+
**Editing the preset.** `cordis.patch.yml` carries a "DO NOT EDIT BY HAND" header and is
|
|
145
|
+
regenerated. Change `tools/preset-declaration.mjs` and run:
|
|
146
|
+
|
|
147
|
+
```sh
|
|
148
|
+
node tools/gen-cordis-patch.mjs
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The generator needs a skeleton patch to merge against; it looks for `--skeleton <path>`,
|
|
152
|
+
then `$DSH_SKELETON`, then the host's own `standard.patch.yml`, and it refuses to invent one
|
|
153
|
+
if none is found. The `cordis.patch.yml` in this repository is byte-for-byte what that
|
|
154
|
+
command produces from the committed declaration.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Installation
|
|
159
|
+
|
|
160
|
+
The install method is a **`link:`** dependency, not an npm publish. `package.json` carries
|
|
161
|
+
`"private": true` **precisely so the `@local/`-scoped name can never be published by
|
|
162
|
+
accident** — that guard is what makes the current name safe, and it is the flag to remove at
|
|
163
|
+
the moment of any real publication (see [Publishing to npm](#publishing-to-npm-future-work-not-yet-done)).
|
|
164
|
+
The package declares **no** `dependencies` — the host supplies everything at runtime. It does
|
|
165
|
+
declare `peerDependencies`, all four marked `optional`, so that what it was tested against is
|
|
166
|
+
written down without any install being able to fail over it:
|
|
167
|
+
|
|
168
|
+
| Package | Range | Why |
|
|
169
|
+
|---|---|---|
|
|
170
|
+
| `@deepseek-ai/dsh-skill-filesystem` | `>=0.2.0-rc.2 <2` | the provider this bundle mounts |
|
|
171
|
+
| `@deepseek-ai/dsh-tools` | `>=0.2.0-rc.2 <2` | `defineTool`, used by `lane-composition.mjs` |
|
|
172
|
+
| `@deepseek-ai/cordis` | `>=4.0.1 <5` | the plugin contract; a real major boundary |
|
|
173
|
+
| `@deepseek-ai/schemastery` | `>=3.18.0 <4` | the `Config` schema the settings card is built from |
|
|
174
|
+
|
|
175
|
+
The lower bounds name **the version this was actually run against**, not an earlier one the
|
|
176
|
+
design happened to reference. The upper bounds follow the convention the published
|
|
177
|
+
`@quill507/dsh-auto-approval-llm` uses on the same host packages. `optional: true` is what
|
|
178
|
+
keeps the declaration honest: the coupling here is deep — `ctx.skills.registerProvider` is a
|
|
179
|
+
host API — so a major change could break this silently, and saying so is worth more than
|
|
180
|
+
pretending the range is enforced. It is not.
|
|
181
|
+
|
|
182
|
+
### 0. Host version gate
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
dsh --version # install.sh refuses below 0.1.7-rc.1
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
This is a hard check inside `install.sh`, and it is deliberately **looser** than the
|
|
189
|
+
`peerDependencies` above: 0.1.7-rc.1 is the version the design was written against, while
|
|
190
|
+
0.2.0-rc.2 is the version it has been run on. Between those two the honest answer is
|
|
191
|
+
**untested**, and the two numbers are kept separate for that reason rather than quietly
|
|
192
|
+
merged into one. `install.sh --check` runs this gate and writes nothing.
|
|
193
|
+
|
|
194
|
+
### 1–4. Install
|
|
195
|
+
|
|
196
|
+
```sh
|
|
197
|
+
./install.sh # into $DSH_HOME, or ~/.dsh
|
|
198
|
+
DSH_HOME=/some/other/home ./install.sh
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
From a clone, that stages the bundle into `<DSH_HOME>/plugins/dsh-orchestrator-preset-bundle/`
|
|
202
|
+
and verifies the per-profile symlink. Nothing is copied into `~/.dsh/skills/`, and there is no
|
|
203
|
+
companion plugin: the four skills are served by the bundle's own provider, and the aegis prefix
|
|
204
|
+
bridge is mounted by a row the generator emits. Doing it by hand:
|
|
205
|
+
|
|
206
|
+
```sh
|
|
207
|
+
# 1. copy the bundle
|
|
208
|
+
cp -r . ~/.dsh/plugins/dsh-orchestrator-preset-bundle/
|
|
209
|
+
|
|
210
|
+
# 2. link it into a profile (see step 5 for the package.json line that makes this work)
|
|
211
|
+
# and run `pnpm install` there — pnpm creates the symlink from the `link:` dependency.
|
|
212
|
+
# Verify with test -L, never test -e: Git Bash can silently degrade a link into a
|
|
213
|
+
# copy, and a copy passes test -e while freezing every later edit to the bundle.
|
|
214
|
+
test -L ~/.dsh/profiles/web/node_modules/@quill507/dsh-orchestrator-preset && echo "real symlink"
|
|
215
|
+
|
|
216
|
+
# 3. the four self-authored skills need NO install step — they ship inside the
|
|
217
|
+
# bundle and are served by extensions/dsh/index.js, a filesystem skill provider
|
|
218
|
+
# mounted by the generated patch with includeDefaultRoots:false. Nothing is
|
|
219
|
+
# written to ~/.dsh/skills/.
|
|
220
|
+
|
|
221
|
+
# 4. nothing to install. The aegis prefix bridge ships inside the bundle as
|
|
222
|
+
# extensions/dsh/aegis-prefix.js, mounted by a generated patch row with two
|
|
223
|
+
# settings: prefixAegisSkills (default on) and describeAegisSkillsInZh
|
|
224
|
+
# (default off, turned on in your own layer — see below).
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Nothing is copied into `~/.dsh/skills/`.** The four `orch-*` skills travel with the bundle
|
|
228
|
+
and a provider scoped to it serves them, so installing this preset adds nothing to your
|
|
229
|
+
global skills directory and removing it takes nothing away. That directory is where other
|
|
230
|
+
people's tools live; a preset that scatters copies into it inherits the mess without the
|
|
231
|
+
context. What this bundle ships is exactly what is in `skills/`, and `.gitignore` admits
|
|
232
|
+
those four paths one by one — a fifth cannot be added without saying so.
|
|
233
|
+
|
|
234
|
+
`describeAegisSkillsInZh` defaults to off because translating a catalogue is a reader
|
|
235
|
+
preference rather than a routing requirement.
|
|
236
|
+
|
|
237
|
+
**Set it in a patch layer. There is no settings-page control for it yet.** The home layer
|
|
238
|
+
`$DSH_HOME/cordis.patch.yml` applies after this bundle's, so a row there wins:
|
|
239
|
+
|
|
240
|
+
```yaml
|
|
241
|
+
- id: orch-aegis-prefix
|
|
242
|
+
config:
|
|
243
|
+
prefixAegisSkills: true
|
|
244
|
+
describeAegisSkillsInZh: true
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Restate **both** keys. A patch replaces a row's config rather than deep-merging it, so naming
|
|
248
|
+
only the one you are changing drops the other back to its default. A restart is needed either
|
|
249
|
+
way: the config is read when the plugin is applied.
|
|
250
|
+
|
|
251
|
+
### Why there is no control yet, and what it would take
|
|
252
|
+
|
|
253
|
+
The host does build settings forms from plugin schemas, and this plugin's `Config` is written
|
|
254
|
+
the way that requires — `@deepseek-ai/schemastery` rather than `zod`, with both fields marked
|
|
255
|
+
`.volatile()`. That is not sufficient, which was measured rather than assumed:
|
|
256
|
+
`dsh-settings.describe()` only considers entries that `dsh-config-editor.entries()` returns,
|
|
257
|
+
and that filters to rows whose `parent.tree.ctx.fiber.entry?.id === "include"`. A row inserted
|
|
258
|
+
by a bundle patch is not one of those, so nothing here reaches the settings UI.
|
|
259
|
+
|
|
260
|
+
The one third-party plugin on the development machine that does have a settings card
|
|
261
|
+
(`@quill507/dsh-auto-approval-llm`) does not use that path either — it ships a browser client
|
|
262
|
+
plugin plus its own GET route, and its own source calls the route the degradation source "for a
|
|
263
|
+
card that has no host form (entry not ACTIVE)". So a control here means writing a client
|
|
264
|
+
plugin: a `dsh.client` declaration, a separate browser entry, a read route, and a form bound to
|
|
265
|
+
this entry's id. That is a small project, not a field on this schema, and it is **not done**.
|
|
266
|
+
|
|
267
|
+
**Client-page support is planned and tracked here as unfinished.** Until it lands the switches
|
|
268
|
+
are config-only, and this section is the place to look when wondering why.
|
|
269
|
+
|
|
270
|
+
### 5. Wire it into a profile
|
|
271
|
+
|
|
272
|
+
In `~/.dsh/profiles/<profile>/package.json`, add the dependency and the same string to
|
|
273
|
+
`dsh.profile.bundles`, keeping its position:
|
|
274
|
+
|
|
275
|
+
```json
|
|
276
|
+
"@quill507/dsh-orchestrator-preset": "link:<DSH_HOME>/plugins/dsh-orchestrator-preset-bundle"
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
then run `pnpm install` in that profile directory. In
|
|
280
|
+
`~/.dsh/profiles/<profile>/cordis.patch.yml`, select the preset:
|
|
281
|
+
|
|
282
|
+
```yaml
|
|
283
|
+
- id: preset-dsh-orchestrator-preset
|
|
284
|
+
name: '@deepseek-ai/dsh-agent-preset'
|
|
285
|
+
config:
|
|
286
|
+
selectedDefault: dsh-orchestrator-preset
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
A patch replaces the whole row rather than deep-merging it, so that snippet is the whole
|
|
290
|
+
row, not an addition to a larger one. Both profiles must pin the **same released tag** of
|
|
291
|
+
aegis; desktop must not float.
|
|
292
|
+
|
|
293
|
+
`install.sh` deliberately stops before this step: those are the live installation's own
|
|
294
|
+
files, and `cordis.patch.yml` is watched by `dsh-hmr`, so writing it triggers an immediate
|
|
295
|
+
full re-assembly of the running host. The script prints the edits instead of making them.
|
|
296
|
+
|
|
297
|
+
### 6. Install the aegis methodology pack
|
|
298
|
+
|
|
299
|
+
`aegis` is an upstream dependency, not something this repository ships. Install it through
|
|
300
|
+
the host, and pin the same released tag in both profiles.
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Troubleshooting
|
|
305
|
+
|
|
306
|
+
**A preset chosen in the GUI does not come back on its own.** The preset chooser persists
|
|
307
|
+
through the config editor, which rewrites the profile's own `cordis.patch.yml` in place. A
|
|
308
|
+
preset picked there overwrites `selectedDefault`, and nothing restores it. The bundle's own
|
|
309
|
+
patch is not touched — only the profile's. Re-apply the step 5 row to come back; there is
|
|
310
|
+
no state to reset.
|
|
311
|
+
|
|
312
|
+
**`cordis.yml` is empty, and that is correct.** The host defines the empty list as a literal
|
|
313
|
+
and rewrites it on every boot so that it stays empty; composed rows are written back into
|
|
314
|
+
it by the loader, which would otherwise duplicate every bundle insert on the next boot.
|
|
315
|
+
**Grepping `cordis.yml` can never tell you which preset is selected** — inspect
|
|
316
|
+
`cordis.patch.yml` instead.
|
|
317
|
+
|
|
318
|
+
**The bundle loads but its files are not found.** Check the symlink with `test -L`. A
|
|
319
|
+
directory that exists but is not a symlink is a copy, and a copy will not track later edits.
|
|
320
|
+
|
|
321
|
+
**A lane behaves as if it lost a shell tool.** The preset declares *both* shells —
|
|
322
|
+
`tool-bash` and `tool-pwsh` — each gated on `process.platform`, so on Windows the preset
|
|
323
|
+
asks for `pwsh` and off Windows for `bash`. A layer applied **after** the profile layer can
|
|
324
|
+
override that: the `~/.dsh/cordis.patch.yml` home layer is one such place, and a host set
|
|
325
|
+
up for bash-only on Windows will force `tool-bash: disabled: false` and
|
|
326
|
+
`tool-pwsh: disabled: true` there. That is a **deployment fact, not a defect** — the
|
|
327
|
+
preset does not require `pwsh`, and a disabled tool is still a known tool, so the lanes
|
|
328
|
+
dispatch and work normally on bash alone. If a lane looks like it has lost its shell,
|
|
329
|
+
check your own home or profile layer before suspecting the preset: the home layer wins,
|
|
330
|
+
and it wins silently. Note that the generator derives the shell name that goes into the
|
|
331
|
+
lanes' `toolFilter` deny lists from the *effective* values of both the host layer and the
|
|
332
|
+
preset's own rows, so changing that override means re-running
|
|
333
|
+
`node tools/gen-cordis-patch.mjs`. This preset changes no tool row, filter or persona to
|
|
334
|
+
accommodate any particular shell arrangement.
|
|
335
|
+
|
|
336
|
+
**The persona prefix is empty.** `plan-aware-persona` fails loud on a missing or empty
|
|
337
|
+
persona file rather than silently stripping the agent's identity. Read the error: it names
|
|
338
|
+
the file.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Verifying the install
|
|
343
|
+
|
|
344
|
+
```sh
|
|
345
|
+
./tools/verify-install.sh # checks the "desktop" profile
|
|
346
|
+
./tools/verify-install.sh web
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
Is the preset really installed, and is it really the one selected? Twenty checks across
|
|
350
|
+
eight groups, plain `PASS`/`FAIL` lines and a summary, exit non-zero if anything fails. It
|
|
351
|
+
is **read-only**: it composes the profile tree in memory and never writes to a DSH home —
|
|
352
|
+
check 5 asserts that rather than assuming it.
|
|
353
|
+
|
|
354
|
+
| # | What it checks |
|
|
355
|
+
|---|---|
|
|
356
|
+
| 1 | the profile patch selects this preset, exactly once |
|
|
357
|
+
| 2 | the bundle link is a **real symlink** — `test -L`, never `test -e`, because a link silently degraded into a copy still passes `test -e` |
|
|
358
|
+
| 3 | the bundle is **resolvable by package name** through the link, i.e. present *and* usable |
|
|
359
|
+
| 4 | the patch generator is in sync, run with **`DSH_HOME` unset** |
|
|
360
|
+
| 5 | the **composed** tree really selects this preset, with no occurrence of the pre-rename name, and the preset row present |
|
|
361
|
+
| 6 | the four `orch-*` skills are installed, and the four retired unprefixed names are gone as directories |
|
|
362
|
+
| 7 | the two shell rows read as this host deliberately configured them |
|
|
363
|
+
| 8 | leak gate: no machine-local absolute path, no third-party skill name and no private-data token, in any **tracked** file |
|
|
364
|
+
|
|
365
|
+
**Check 4 runs with `DSH_HOME` unset on purpose.** The generator resolves its skeleton
|
|
366
|
+
from `$DSH_HOME` and falls back to `~/.dsh`, so a shell that happens to export the variable
|
|
367
|
+
resolves fine while a plain one did not — and that read as "the tool is broken". The tool
|
|
368
|
+
was since repaired to fall back, so this proves it rather than assuming it.
|
|
369
|
+
|
|
370
|
+
**Check 5 composes the tree instead of reading `cordis.yml`,** because `cordis.yml` cannot
|
|
371
|
+
answer the question: it is a four-line empty root the host rewrites on every launch, so it
|
|
372
|
+
structurally cannot contain those rows and anything dumped into it dies at the next boot.
|
|
373
|
+
`dsh --profile <name> --dump-config` is also unavailable — the launcher refuses it outright
|
|
374
|
+
for an Electron-managed profile such as `desktop`. So the script calls the host's own
|
|
375
|
+
read-only loader, skips the step that rewrites `cordis.yml`, and greps the composed output.
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## Dependencies
|
|
380
|
+
|
|
381
|
+
This bundle has no runtime npm dependencies. It imports `@deepseek-ai/dsh-tools` (for
|
|
382
|
+
`defineTool`, in `lane-composition.mjs`) and nothing else from the npm ecosystem; that
|
|
383
|
+
package is provided by the **host**, which is why it is neither a `dependency` nor a
|
|
384
|
+
`peerDependency` here.
|
|
385
|
+
|
|
386
|
+
The persona files are resolved by deep path at runtime
|
|
387
|
+
(`createRequire(baseUrl).resolve('@quill507/dsh-orchestrator-preset/personas/scout.md')`).
|
|
388
|
+
`baseUrl` is injected by the host, so resolution is independent of where the bundle is
|
|
389
|
+
installed. One fragility worth naming: `package.json` has **no `exports` field**, so those
|
|
390
|
+
deep `.md` paths currently resolve through Node's legacy no-exports behaviour. An explicit
|
|
391
|
+
`exports` map would be more robust and is listed under the npm work below.
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## Publishing to npm (future work, not yet done)
|
|
396
|
+
|
|
397
|
+
**None of this has been done, attempted or tested.** It is recorded so the path is not
|
|
398
|
+
rediscovered from scratch. The runtime specifier is still `@local/`, and that is a
|
|
399
|
+
deliberate deferral, not an oversight: renaming the runtime specifier means re-linking and
|
|
400
|
+
re-verifying a working desktop installation, which is not a cost worth paying for a
|
|
401
|
+
packaging change nobody has asked for yet.
|
|
402
|
+
|
|
403
|
+
If it is wanted later:
|
|
404
|
+
|
|
405
|
+
- **The package name** it would take is currently undecided; it must match the bundle
|
|
406
|
+
directory name's tail segment, and it must stop being `@local/`-scoped.
|
|
407
|
+
- **The one line that must change** is `tools/preset-declaration.mjs:45`,
|
|
408
|
+
`export const bundlePkg = '@quill507/dsh-orchestrator-preset'`. That single constant
|
|
409
|
+
owns all 12 specifier references in the generated `cordis.patch.yml`; the 12 resolve to 12
|
|
410
|
+
distinct files (3 `.mjs` and 9 persona `.md`). Change that one line, then run
|
|
411
|
+
`node tools/gen-cordis-patch.mjs` — no other edit is needed, and no persona file is
|
|
412
|
+
affected. (`personas/orchestrator.md` is inlined rather than file-resolved, so it is
|
|
413
|
+
correctly absent from that list.)
|
|
414
|
+
- **Two things beyond that are unsolved**: the four skills under `skills/` are plain Markdown
|
|
415
|
+
with no npm story and would need a postinstall step to copy them into a profile's skills
|
|
416
|
+
directory; and `package.json` carries `"private": true`, which npm refuses to publish.
|
|
417
|
+
The `exports` map and the second-package question are both settled — the map exists, and
|
|
418
|
+
the companion plugin was folded into `extensions/dsh/aegis-prefix.js` rather than shipped
|
|
419
|
+
as its own package.
|
|
420
|
+
- **`"private": true` must be removed** at the moment of publication. It is the guard that
|
|
421
|
+
currently makes the name safe to have.
|
|
422
|
+
- **The npm account does not exist yet** on the public registry, so publication is blocked
|
|
423
|
+
on account setup, not on the code.
|
|
424
|
+
|
|
425
|
+
### The skill-provider architecture — adopted, deliberately not built
|
|
426
|
+
|
|
427
|
+
**This is not implemented and not tested.** It is recorded because the owner adopted it as
|
|
428
|
+
the approach for a *later* round, and because it changes two of the items above.
|
|
429
|
+
|
|
430
|
+
The approach: **mount a plugin that calls `apply()` from `@deepseek-ai/dsh-skill-filesystem`**,
|
|
431
|
+
configured with `includeDefaultRoots: false` and `bundledSkillDir` pointing at the package's
|
|
432
|
+
own `skills/` tree. It is the same roughly 12-line shape aegis uses for its own bundled
|
|
433
|
+
skills. The package is already resolvable from this bundle with **zero new dependencies**,
|
|
434
|
+
and it exports `apply`, `FileSystemSkillProvider` and `Config` — so the entry point is
|
|
435
|
+
already there; what is missing is the call site and the registration.
|
|
436
|
+
|
|
437
|
+
**What it would delete:**
|
|
438
|
+
|
|
439
|
+
- **Install step 3 disappears.** Copying the four skills into the global `~/.dsh/skills/`
|
|
440
|
+
is no longer needed, because the provider serves them from inside the package. That also
|
|
441
|
+
removes the "copy one directory at a time, never the whole tree" hazard for users.
|
|
442
|
+
- **npm todo item 5 disappears with it** — the postinstall skill-copying step is the very
|
|
443
|
+
thing this architecture exists to avoid, so that item should be struck from the list
|
|
444
|
+
above rather than solved.
|
|
445
|
+
|
|
446
|
+
**What it would cost, and why that is why it is deferred:**
|
|
447
|
+
|
|
448
|
+
- **It changes the generated `cordis.patch.yml`.** A new plugin row has to be declared, so
|
|
449
|
+
the patch is regenerated and its current verified md5 — `ba04ddbeb2eaa82bcb9f6d2df00fc219`
|
|
450
|
+
— stops being the expected value. Anything that pins that digest has to be updated with it.
|
|
451
|
+
- The regeneration has to be done for real and re-verified against a host, not reasoned
|
|
452
|
+
about: the same generator that reproduces today's patch byte-for-byte is the thing that
|
|
453
|
+
would produce the new one, and a skill-provider row that fails to mount would remove the
|
|
454
|
+
four skills at runtime rather than at install time.
|
|
455
|
+
|
|
456
|
+
Doing it now would mean shipping a change to the running installation's skill surface for a
|
|
457
|
+
benefit nobody has asked for yet. Deferring costs nothing but a stale `cordis.patch.yml`
|
|
458
|
+
digest.
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## License
|
|
463
|
+
|
|
464
|
+
MIT — see [`LICENSE`](./LICENSE).
|
|
465
|
+
|
|
466
|
+
## Acknowledgements
|
|
467
|
+
|
|
468
|
+
This preset is mostly other people's work arranged in a particular way, and it is worth
|
|
469
|
+
saying whose.
|
|
470
|
+
|
|
471
|
+
**[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)** — the host this
|
|
472
|
+
runs inside, MIT-licensed. The configuration rows in `cordis.patch.yml` are derived from
|
|
473
|
+
it, the bundle/patch model this project is built on is its design, and its own first-party
|
|
474
|
+
bundles (`dsh-web-app`, `dsh-base`) are the reference implementations the architecture here
|
|
475
|
+
was read off. Several findings recorded in this README — that composing a profile rewrites
|
|
476
|
+
its `cordis.yml`, that a filesystem skill provider can be pointed at an arbitrary tree —
|
|
477
|
+
are the host's documented behaviour, measured rather than guessed.
|
|
478
|
+
|
|
479
|
+
**[aegis](https://github.com/GanyuanRan/Aegis)** — the methodology pack this preset routes
|
|
480
|
+
into, by Jesse Vincent and Ganyuan Ran. It owns the method: the routing discipline, the
|
|
481
|
+
skill-per-situation idea, the pressure-testing and verification habits. This project
|
|
482
|
+
supplies the orchestration layer around it and consumes aegis at runtime without vendoring
|
|
483
|
+
a line of its text. Its `extensions/dsh/index.js` was also the working reference for the
|
|
484
|
+
provider mounted here — twelve lines that made the skills-in-the-bundle design obviously
|
|
485
|
+
correct before it was tried.
|
|
486
|
+
|
|
487
|
+
**[itamzxm](https://github.com/itamzxm)** — author of **Auto-Pilot**, a set of seven skills
|
|
488
|
+
written to work across agent environments other than this one, rather than for any single
|
|
489
|
+
host. They are bare skill directories with no package manifest, which is why nothing here was
|
|
490
|
+
a candidate to install: Auto-Pilot was read as a source of mechanisms, not adopted as a
|
|
491
|
+
component. Six groups of its mechanisms are borrowed here by mechanism rather than by text —
|
|
492
|
+
its memory model, its convening gate and convergence states, its bare-run test and delegation
|
|
493
|
+
letter, its four scheduling rules, and its search and goal criteria. Auto-Pilot is not
|
|
494
|
+
published and carries no licence, and none of its text appears in this repository; where a
|
|
495
|
+
mechanism came from it, this repository's own design history names which one rather than
|
|
496
|
+
restating it.
|
|
497
|
+
|
|
498
|
+
**[Tacrine](https://github.com/Tacrine)** — who ported the oh-my-openagent agent set to
|
|
499
|
+
DeepSeek Harness and modified it, before this repository existed. The ten personas here
|
|
500
|
+
began as that port's output.
|
|
501
|
+
|
|
502
|
+
**oh-my-openagent** ([code-yeongyu/oh-my-openagent](https://github.com/code-yeongyu/oh-my-openagent))
|
|
503
|
+
— the upstream those personas ultimately descend from, and its author **code-yeongyu**. That
|
|
504
|
+
project is not open source, and no text from it is distributed here: every persona in this
|
|
505
|
+
repository has since been rewritten against an explicit threshold — under 2% n-gram overlap
|
|
506
|
+
with the upstream agent sources, and no run of six consecutive matching lines.
|
|
507
|
+
`tools/audit-personas.mjs` is that threshold, made runnable. Its term-probe half runs
|
|
508
|
+
anywhere; the overlap half needs the upstream corpus, which is deliberately not included, so
|
|
509
|
+
the rewrite is **partial evidence rather than a verified claim** — the tool reports it as
|
|
510
|
+
unverified, not as a pass, because those are different things.
|
|
511
|
+
|
|
512
|
+
**The authors of the packages this was tested against** — `@deepseek-ai/schemastery`, and the DSH packages that
|
|
513
|
+
supply `dsh-tools`, `dsh-skill-filesystem` and `dsh-home-paths`. Nothing here would load
|
|
514
|
+
without them, and none of them are dependencies of this package: the host supplies them at
|
|
515
|
+
runtime, which is precisely why this bundle declares no runtime dependencies of its own.
|
|
516
|
+
|
|
517
|
+
And a note on what is **not** acknowledged here: the tooling used to build this — a
|
|
518
|
+
language model working through a long session — is not a source of the design. The mistakes
|
|
519
|
+
in it are catalogued in this repository's own history rather than smoothed away, and the
|
|
520
|
+
distinction between what was measured and what was assumed is marked throughout.
|
|
521
|
+
|
|
522
|
+
## Third-party attribution
|
|
523
|
+
|
|
524
|
+
The formal record — what is in this repository from somewhere else, and what is deliberately
|
|
525
|
+
not in it — is [`THIRD_PARTY_NOTICES.md`](./THIRD_PARTY_NOTICES.md). It is kept in its own
|
|
526
|
+
file rather than appended to `LICENSE`, because an appended block makes GitHub's licence
|
|
527
|
+
detector report "Other" for a file that is plainly MIT, and because a fact with two homes has
|
|
528
|
+
no home.
|
|
529
|
+
|
|
530
|
+
Two points from it are worth stating here, since they affect what you may do with this code:
|
|
531
|
+
the `aegis` pack is consumed at runtime and **not vendored**, and the third-party skills on
|
|
532
|
+
any given machine are **not redistributed** — some carry no licence at all, which makes
|
|
533
|
+
redistributing them a violation rather than an oversight.
|