500 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# DSH port — design and spike notes
Status: **spike 0.2.1, live guard/require-plan/bootstrap verified; `/role`
command works, the model-invocable `role` skill and the asynchronous SDD
protocol are verified live (three-task trial run); the pre-step
`harness-check`/`role-hint` injections are implemented and tested but not yet
verified live — they need the reinstalled bundle**. This directory is the
DeepSeek Harness adapter for `claude-harness`; the Claude Code installation and
the repository's source of truth are unchanged.
## 1. Verdict
This is a port, not a copy. Three layers map differently:
| Layer | Claude Code | DeepSeek Harness | Status |
|---|---|---|---|
| Instructions | `~/.claude/CLAUDE.md`, project `CLAUDE.md` | `$DSH_HOME/AGENTS.md`, project `CLAUDE.md`/`AGENTS.md`, nested | almost 1:1 |
| Skills | `~/.claude/skills`, `.claude/skills` | `~/.dsh/skills`, `.agents/skills`, `customSkillDirs` | 1:1 format |
| Roles | `roles/`, `/role` skill | same files + `/role` command + model-invocable `role` skill | close |
| Hard rules | `PreToolUse` shell hooks | `ctx.tools.guard` Cordis guard + approval gates A/B/C | logic reused, wrapper new |
| Session-start checks | `harness-check.sh`, `role-hint.sh` | `agent/pre-step` injections `harness-check`, `role-hint` | checks ported, texts new |
| Superpowers | plugin + `SessionStart` hook | pinned sync of tag `v7.0.1` (`DSH_SUPERPOWERS_REF`) into `~/.dsh/skills` + `agent/pre-step` bootstrap | content adapted by sync, bootstrap new |
| SDD | `Task` (synchronous) | `subagent` (asynchronous) / `workflow` | semantics differ |
| Gitea | CLI + skills | `bash` + skills | 1:1 |
| OpenSpec | CLI + `.claude/skills` + `/opsx:*` | CLI + проектные `.agents/skills` | close: нет слэш-команд |
| codegraph | MCP | MCP (`mcp__codegraph__*`) | 1:1 with names |
| auto-memory | Claude Code feature | none | dropped/replaced with files |
| install | `install.sh` + `settings.json` | bundle + profile manager | new |
The important discovery: **DSH loads `CLAUDE.md` as a project instruction file**,
so the project templates and nested instructions need no rewrite. The global
file has to be installed as `$DSH_HOME/AGENTS.md` because DSH does not read
`~/.claude/CLAUDE.md`.
## 2. What this spike implements
1. **`guard-main` and `require-plan`** through `ctx.tools.guard`. The adapter
synthesizes the Claude hook payload (`{cwd, tool_name, tool_input}`), runs
the existing `hooks/guard-main.sh` / `hooks/require-plan.sh`, turns `exit 2`
into a denial reason, and fails open on every other error. The Python core
(`hooks/harness_target.py`) and its tests remain the source of truth. A guard
is synchronous and monotonic: it runs after `tools/pre-execute`, and no later
listener can turn the denial back into permission.
2. **Superpowers bootstrap** through `agent/pre-step`. It reads the installed
`using-superpowers/SKILL.md`, strips frontmatter, appends
`bundle/dsh-tools.md`, wraps the result in `<EXTREMELY_IMPORTANT>`, and
injects it once per session. A content-hash marker handles dedupe; scanning
`session.surface.nodes` re-injects after compaction.
3. **Roles** — `/role` is a real command (`ctx.commands.register`); it reads
`~/.dsh/roles/<role>.md`, falls back to `~/.claude/roles/<role>.md`, then to
the repository's `roles/`, and reads the project `.claude/roles/<role>.md`.
It injects the role text as a user message and starts a turn for the
five-line summary. Because a model cannot call a slash command,
`skills/role/SKILL.md` is the model-invocable loader: it infers the role,
reads the file, and tells the model to follow it. Auto-memory is explicitly
dropped; the role's "Читать на старте" section is left to the model.
4. **Display metadata and an optional CodeGraph MCP overlay** so the bundle can
be installed through the Plugins page and codegraph stays available.
5. **OpenSpec** — воркфлоу идут проектными скиллами `.agents/skills/openspec-*`,
которые пишет `openspec init --tools agents`. DSH читает этот каталог нативно;
проверено сабагентом с cwd в проекте — все шесть имён в каталоге скиллов.
Глобальной копии в `~/.dsh/skills` нет: генератор обновляется вместе с CLI
проекта, а копия старела бы молча. Слэш-команд нет — только скиллы.
Установка в проект — `bash dsh/install.sh --openspec`; проверка — `--check`.
6. **`harness-check` and `role-hint`** through `agent/pre-step` (change
`dsh-prestep`, capability `session-prestep`). `harness-check` walks up to the
nearest `.git` and looks for `openspec/`, `.codegraph/`, and the
`## OpenSpec и superpowers` section in `CLAUDE.md`; a missing signal produces
one non-blocking `[dsh-harness]` message with the setup steps. `role-hint`
reads the first non-harness user message of the step and injects either
`Роль сессии: <r>` or one question with the four variants. Both are text-only
(`lib/prestep.js` uses fs reads, no spawn), skipped for subagents, gated by
`harnessCheck` / `roleHint` and by the same marker/visibility machinery as the
bootstrap. The Claude Code `SessionStart` scripts are not run under DSH.
## 3. What is deliberately deferred
- **CC `SessionStart` scripts**: `hooks/harness-check.sh` and
`hooks/role-hint.sh` stay for Claude Code sessions; DSH runs the ported checks
itself (§2 item 6), so the scripts and `settings.hooks.json` are not reused.
- **`briefing`**: needs an agent preset with read-only tools and a model route;
not part of the guard/bootstrap spike.
- **SDD parity**: the Claude `Task` is synchronous, while DSH `subagent` returns
a child id and reports later. The `sdd` skill implements the asynchronous
analogue (report files, notification as the wait, `send_message` for fix
rounds, ledger as memory); there is no parity and the skill says so.
- **Codegraph by default**: `dsh/mcp.codegraph.yml` is an opt-in overlay; the
bundle does not assume the binary is installed.
- **`harness-doctor`**: its scripts inspect `~/.claude`; a DSH variant is a
separate task.
- **Auto-memory, caveman**: no direct DSH equivalents; caveman is off by default
anyway.
- **Full installer**: `install.sh` prepares global instructions and skills; the
bundle itself is installed by `plugin_manager` because the Desktop profile is
Electron-managed.
- **Pinned sync of superpowers (change `dsh-port-v2`, D-2)**: "vendored
superpowers" is gone — no upstream skill text is copied as-is. The default
install source is the clone at `~/.dsh/superpowers` pinned to
`$DSH_SUPERPOWERS_REF` (default `v7.0.1`). `install.sh --skills` clones or
updates it, runs the vendored `dsh/sync/sync-from-upstream.mjs` (asserted
transforms, namespace strip, `dsh-tools.md` override) and
`dsh/sync/verify-skills.mjs`, and copies only the adapted tree; a broken or
empty synced tree is never installed. Explicit sources (`--superpowers-from`,
`$DSH_SUPERPOWERS_SOURCE`) are synced directly with no network. Upstream
moves independently, so each release is a deliberate pin bump (an issue per
release, D-7; the procedure is in `dsh/README.md`). Removing the legacy
`~/.claude` fallbacks is deferred until every machine has rerun
`--skills --roles`; until then both runtime and installer warn when they use
one.
## 4. Architecture
```
dsh/
bundle/
package.json # dsh.bundle.patch, exports, display resources
cordis.patch.yml # inserts the dsh-harness row
index.js # ctx.tools.guard + agent/pre-step + /role wiring
command-role.js # /role command glue (DSH imports live only here)
lib/guards.js # Claude-hook JSON adapter, fail-open
lib/bootstrap.js # skill resolution, marker, dedupe, compaction
lib/prestep.js # harness-check/role-hint detection and texts (pure)
lib/role.js # role parsing and text building (pure)
dsh-tools.md # superpowers tool mapping
hooks -> ../../hooks # local-install symlink to the tested bash/Python hooks
locale/{en,ru}.json
icon.svg
tests/ # Node tests, no DSH runtime needed
skills/role/SKILL.md # model-invocable role loader (installed to ~/.dsh)
install.sh # --check / --global / --skills / --roles / --all
mcp.codegraph.yml # optional CodeGraph MCP row
```
The bundle imports only Node builtins and files inside this package. It
deliberately does not import `@deepseek-ai/dsh-llm` or
`@deepseek-ai/schemastery`: a local-directory profile install resolves imports
from the profile, not from the DSH installation, so a DSH-internal import fails
at activation with `ERR_MODULE_NOT_FOUND`. `lib/message.js` is a local copy of
the tiny `createUserMessage` constructor, and `Config` was replaced by defaults
normalized in `apply()`. The pure modules are testable with plain Node; this is
why the port's 26 tests run without a DSH process.
### Guard flow
```
model calls write/edit/bash
-> tools/pre-execute (approval, extensible policy)
-> ctx.tools.guard (dsh-harness, synchronous, monotonic)
-> lib/guards.js maps tool + args
-> bash hooks/guard-main.sh (cwd, tool_name, tool_input)
-> python3 hooks/harness_target.py guard-main
-> exit 2 => deny reason (final)
-> exit 0 or any failure => allow
-> require-plan.sh for write/edit
-> execution
```
The guard returns a denial; the tool pipeline materializes it as the model-facing
error. Other listeners cannot turn it back into permission. A script failure,
missing Python, or malformed JSON fails open, matching the harness invariant.
### Bootstrap flow
```
agent/pre-step
-> next() (other injections happen first)
-> skip if reject/aborted, or if subagent and bootstrapSubagents=false
-> prepareBootstrap(): resolve skill, read mapping, hash content, build text
-> isInjectionVisible(agent, decision.messages, marker)?
yes -> no-op
no -> append createUserMessage({ source: {kind:"user"} })
```
The marker is an HTML comment at the top of the message. The visible-surface
scan uses `agent.session.surface.nodes` + `eventAt(seq)`, the same mechanism the
skill catalog uses, so a compacted message is re-injected on the next step.
### Pre-step injection flow (harness-check, role-hint)
```
agent/pre-step (after next(), same listener as the bootstrap)
-> harness-check: sessionCwd -> detectAdoption()
no .git up to the fs root -> silent
all signals present -> silent
otherwise -> [dsh-harness] Проект … не подключён …
-> role-hint: first user message of this step that is not a harness injection
no such message -> silent (autonomous round)
keyword match -> [dsh-harness] Роль сессии: <r> …
no match -> the four-variant question
-> skip both for subagents (origin=subagent, delegationDepth>0, subagentDepth>0)
-> dedupe by the PRESTEP marker, which is the hash of the injection text
```
The checks are gated by `typeof ctx.on === 'function'` rather than by the
`bootstrap` self-check (D-5), so `bootstrap: false` keeps them alive. The
`harness-check` texts contain no Claude Code paths or adopt script (D-9); the
pre-step prefix is `[dsh-harness]`, and the message filter also accepts the
legacy `[claude-harness]` (D-10).
## 5. Configuration
The bundle row can be configured from the profile patch. Defaults are suitable
for the repository layout:
```yaml
- id: dsh-harness
config:
enabled: true
guards: true
approvalGates: true # gates A/B/C; active only inside the guard chain
bootstrap: true
roleCommand: true
selfCheck: true # activation check of the DSH contract; not-ok is logged
checkCommand: true # register the dsh-harness-check command
bootstrapSubagents: false
harnessCheck: true # pre-step: unadopted project -> setup steps (non-blocking)
roleHint: true # pre-step: first user message -> role hint or question
hooksDir: '' # empty -> bundle/hooks -> ../../hooks
rolesDir: '' # empty -> ~/.dsh/roles, legacy ~/.claude/roles, repo roles/
projectRolesDir: '' # empty -> <cwd>/.claude/roles
roleNames: [dev, admin, analyst, qa]
bootstrapSkillPath: '' # empty -> ~/.dsh/skills, then legacy Claude Code paths
toolMappingPath: '' # empty -> bundle/dsh-tools.md
bootstrapMaxBytes: 65536
```
### Model routes and delegation depth
SDD needs two things the default profile does not give: a model choice for
`subagent` and a second level of delegation for a background controller.
`dsh/subagent-models.yml` is the opt-in overlay for both:
```bash
# 1. copy the two entries into the profile patch (desktop is Electron-managed)
open -e ~/.dsh/profiles/desktop/cordis.patch.yml # append dsh/subagent-models.yml
# 2. restart DSH, then check
bash dsh/install.sh --check # "ok: subagent maxDepth=2 (...)"
```
After the restart the `subagent` and `subagent_fork` schemas accept
`provider`, `model`, `reasoning_effort`, and a background controller subagent
can dispatch an implementer. Routes measured in 0.2.1-rc.3:
`deepseek-official/deepseek-flash` (transcription and mechanics) and
`deepseek-official/deepseek-v4-pro` (integration and every review). Without the
overlay the agent runs everything on the session model and at depth 1; the
`sdd` skill must say so in its report instead of pretending the routes exist.
The overlay stays out of `dsh/bundle/cordis.patch.yml` on purpose: the
`subagent-model-selection-settings` row exists in the web/desktop profile and is
absent in headless, and enabling it from the bundle would break headless boot
with "requires ... in the Host scope".
`bootstrapSkillPath` resolution order: explicit path, `DSH_SUPERPOWERS_SKILL`,
`~/.dsh/skills`, `~/.agents/skills`, the newest
`~/.claude/plugins/cache/claude-plugins-official/superpowers/*/`, then
`~/.claude/skills`. The DSH copy wins because `dsh/install.sh --skills` copies
real files there; the Claude Code locations are a legacy fallback and the
bundle logs one warning per process when it resolves one of them.
Install-time source resolution is separate and stricter (change
`dsh-install-source`, pin in change `dsh-port-v2`): `--superpowers-from` →
`$DSH_SUPERPOWERS_SOURCE` → the pinned clone `~/.dsh/superpowers` at
`$DSH_SUPERPOWERS_REF` (default `v7.0.1`, cloned or updated from
`$DSH_SUPERPOWERS_REPO`) → the legacy cache → `~/.claude/skills`. Explicit
sources are synced in place with no network and must be a checkout root or
its `skills/` directory — a bare skills directory outside that layout is
invalid, and `--check` and `--skills` fail the same way (narrower than change
`dsh-install-source` #49; the spec delta records the MODIFIED). Explicit
syncs stage into `~/.dsh/.skills.synced` beside the clone dir, which stays
reserved for the pin; an existing clone is updated by fetching
`$DSH_SUPERPOWERS_REPO` (not its origin) and reused offline only when already
on the ref. An invalid explicit source is a hard `FAIL`; a machine offline
without a clone is a `FAIL` with the clone hint, falling back to legacy only
when a legacy source exists.
### OpenSpec skills
Воркфлоу OpenSpec ставит генератор CLI, а не обвязка:
```bash
cd <project>
openspec init --tools agents # или: bash <harness>/dsh/install.sh --openspec
openspec update # обновить скиллы после апгрейда CLI
```
Скиллы лежат в `.agents/skills/openspec-{propose,apply-change,archive-change,explore,sync-specs,update-change}/SKILL.md`
и перезаписываются генератором: править их руками нельзя. Команды адаптер
`agents` не ставит, поэтому `/openspec` в DSH нет — модель вызывает скилл по
фразе «openspec propose» / «openspec archive».
Цикл без Claude Code:
```bash
openspec new change <id>
openspec status --change <id> --json
openspec instructions proposal --change <id> --json
openspec validate <id> --strict
openspec archive <id> -y
```
## 6. Install and verify
Prerequisites: the `claude-harness` checkout, DSH 0.2.1-rc.3, `python3`,
`git`, Node. Claude Code is not required at all: `--skills` clones the pinned
superpowers checkout itself (`DSH_SUPERPOWERS_REF`, default `v7.0.1`) and runs
the DSH sync + verify before installing, so a manual clone is no longer the
first step; `--roles` copies the role files; the hooks come from this
checkout.
```bash
# 1. Static checks (offline; reports the configured pin and the source ref)
bash dsh/install.sh --check
# 2. Global instructions, skills, and roles (run from a terminal; writes
# outside the session workspace). --skills clones the pinned superpowers
# checkout (DSH_SUPERPOWERS_REF, default v7.0.1) and syncs it; or pass
# --superpowers-from / DSH_SUPERPOWERS_SOURCE to sync a checkout directly.
bash dsh/install.sh --global
bash dsh/install.sh --skills # or: --skills --superpowers-from DIR
bash dsh/install.sh --roles
# or all three at once:
bash dsh/install.sh --global --skills --roles
# 3. Install the bundle in DSH:
# Plugins -> install bundle from dsh/bundle
# or ask the agent:
# plugin_manager install_bundle target=/absolute/path/to/claude-harness/dsh/bundle
# 4. Optional: CodeGraph MCP
# apply dsh/mcp.codegraph.yml as a --patch overlay; the tool is
# mcp__codegraph__codegraph_explore.
```
`--openspec` добавляет agents-адаптер в текущий проект (`$PWD`) и требует
существующий `openspec/`: без него скрипт отказывается и печатает готовую
команду. В живой сессии проверка такая: в проекте с `.agents/skills`
спросить «what skills do you have?» — должны быть шесть `openspec-*`.
`--roles` also appends the DSH SDD note to `~/.dsh/roles/dev.md` (the bullet that
points `dev` at the `sdd` skill). The note lives only in the installed copy: the
shared `roles/dev.md` stays Claude Code-compatible, so a Claude session never
sees DSH-only instructions. The insertion is idempotent — every `--roles` run
recopies the role from the repository and re-inserts exactly one note.
Live checks:
1. New session: ask "what skills do you have?" — superpowers skills and the
DSH catalog should be visible.
2. On `main`, ask the agent to create a file — expect
`BLOCKED [guard-main]`.
3. In a worktree on a feature branch, edit `src/...` without a plan — expect
`BLOCKED [require-plan]`; add `.bounded` and retry.
4. `/role dev` — expect the five-line summary and the injected role rules.
5. The acceptance prompt "Let's make a react todo list" must trigger
`brainstorming` before code. If it does not, the bootstrap is not visible;
check the plugin row and the skill path.
6. Guard marker: the injected message starts with
`<!-- DSH-HARNESS-BOOTSTRAP:<hash> -->`; after compaction a new marker is
appended.
Verified live on 2026-10-24 in the desktop profile:
- the bootstrap marker `<!-- DSH-HARNESS-BOOTSTRAP:6b676dd9bb8a0234 -->` and the
full `using-superpowers` body arrived in a fresh session, and the skill
catalog showed the superpowers skills;
- `write` to a file on `main` returned `BLOCKED [guard-main]`;
- a Bash redirect write on `main` returned `BLOCKED [guard-main]`;
- a `write` on a feature branch was allowed;
- `write` to `src/probe.ts` on the branch returned `BLOCKED [require-plan]`,
and the same write succeeded after creating `.bounded`.
Still pending: `/role dev`, the fresh-session "react todo list" acceptance, and
re-injection after `/compact`.
Automated tests:
```bash
bash dsh/tests/run.sh
```
They cover main/detached guards, branch allowance, Bash writes, `require-plan`
with `.bounded` and a branch plan, bootstrap frontmatter/marker/dedupe,
role-layer composition, and package metadata.
Composition smoke test (no model call): the bundle was installed with
`dsh plugin --profile test add dsh/bundle` into a temporary `DSH_HOME` based on
the shipped `headless` profile. `--dump-config` shows the `dsh-harness` row, the
profile lists `@local/dsh-harness` in `dsh.profile.bundles`, and the package's
internal `hooks` symlink resolves to the repository `hooks/`. The temporary
profile was removed; the real `desktop` profile was not touched.
## 7. Risks and open questions
- **Instructions are not enforcement — closed by gates A/B/C.** The upstream loop
(builder-check → `/approve <id> design` → plan → `/approve <id> plan` → sdd)
exists in superpowers as text, and the 24.10.2026 session skipped builder-check
while the plan was written before design approval. Change
`enforce-upstream-loop` adds `lib/gates.js` + `command-approve.js`: gate A
denies a plan for an unapproved design, gate B denies an sdd start (a dispatch
or a `.superpowers/sdd/**` write) for an unapproved or changed plan (sha256),
gate C keeps `approval.md` `/approve`-only, and bash write targets are parsed
by `harness_target.py` and gated too. Residual risk: only a session with the
reinstalled bundle is gated (D-13), and `terminal_*` tools stay outside the
chain (T3.6); the contract is pinned in
`openspec/changes/enforce-upstream-loop/specs/approval-gates/spec.md`.
- **DSH is 0.2.1-rc.3.** The plugin/event API is not frozen; pin the version and
re-run the tests after upgrades.
- **Contract self-check.** The plugin/event API drift is now caught from inside
DSH: at activation the bundle checks the contract it depends on
(`ctx.tools.guard`, `ctx.on` for `agent/pre-step`, `ctx.inject` for commands,
`workingDirectory.get`), logs
`[dsh-harness] self-check: <feature> not-ok: <detail>` for each missing
service, and skips the feature whose service is missing (guards, bootstrap,
or commands — each gated by its own check), so a DSH version without one of
the services does not crash the bundle.
`/dsh-harness-check` re-runs the same check on demand. This is the in-DSH
compat check that closes RV-11 (D-6) — the terminal `--check` cannot see the
SDK inside `app.asar`.
- **Local profile imports are not resolved from the DSH installation.** The
first install attempt failed at activation with
`ERR_MODULE_NOT_FOUND: Cannot find package '@deepseek-ai/schemastery'`. The
bundle now imports only Node builtins and local files: `lib/message.js`
replaces `createUserMessage` from `@deepseek-ai/dsh-llm`, and `Config` was
dropped in favor of defaults normalized in `apply()`. Any future DSH service
must be reached through `ctx` (injected service), never through an
`@deepseek-ai/*` import; a package test enforces this.
- **`ctx.tools.guard` is synchronous.** The guard resolves cwd through
`workingDirectory.get(session)` (sync) and runs the hooks with
`execFileSync`. If a future DSH version changes the guard contract or makes
cwd resolution async, the adapter needs a `tools/pre-execute` fallback. The
guard is global and monotonic; it runs after `tools/pre-execute`, so an earlier
user approval cannot turn a `guard-main` denial back into permission.
- **`agent/pre-step` injection.** Verified live: the bootstrap marker and body
arrived in a fresh session, and the skill catalog showed the superpowers
skills. The local `createUserMessage` copy works with `source.kind: "user"`,
which avoids an unknown session source variant. Re-injection after compaction
is still pending.
- **Subagent bootstrap.** `isSubagent` probes common fields; if none are present
on this version, the bootstrap reaches children too. The skill's
`<SUBAGENT-STOP>` makes that harmless but token-expensive. The pre-step
injections use the same predicate and are skipped for subagents; a fork
(`parentSession` without `origin`) is not a subagent and keeps them (T2.3).
- **Pre-step injection limits.** `harness-check` and `role-hint` are text
injections, not enforcement: nothing stops a model from ignoring them, and they
only exist in a session with the reinstalled bundle (D-13). `role-hint` matches
keywords as substrings, so a different stem («миграцию», «спеку») does not
match. Dedupe is per content (marker = hash of the text), not "exactly once per
session": a later step whose first user message has no keyword adds the
four-variant question even after an earlier role hint (D-11). `harness-check`
never adopts a project — there is no DSH port of `adopt-project.sh` (D-9).
- **Model tiers.** `sonnet`/`haiku`/`opus` are not DSH models. The port uses two
live routes (`deepseek-flash`, `deepseek-v4-pro`) from the opt-in overlay in
`dsh/subagent-models.yml`; without it every dispatch runs on the session model.
- **One-sided model route.** The trial's «child LLM provider and model must be
supplied together» was not a race: the logged tool call carried only `model`
(issue #52). DSH rejects a one-sided route correctly, so no upstream report is
needed; the `sdd` skill now says to retry with both fields.
- **`~/.claude` dependence.** No longer needed for install, bootstrap, or
roles: the install-time source is explicit, and `--skills --roles` copy real
files into `~/.dsh`. The Claude Code locations remain a **legacy migration
fallback**; the installer, `--check`, and the runtime warn when they are used
(runtime — once per process). An existing installation must rerun
`--skills --roles` once to stop relying on them; removal of the fallbacks is
a separate task.
- **Superpowers porting rules.** The upstream guide requires a session-start
bootstrap with no per-session opt-in; `agent/pre-step` satisfies that shape,
but a real acceptance transcript is still required before claiming a port.
- **Hooks symlink.** Local-directory installation links the checkout, so
`bundle/hooks -> ../../hooks` works. A packed/published bundle must include a
real copy of `hooks/`; the `files` field already lists it.
## 8. Next phases
1. Finish the live smoke test: the fresh-session `role` skill acceptance, plus
the bootstrap and `/compact` checks already verified.
2. `harness-check` and optional `role-hint` as non-blocking pre-step injections —
**done** (change `dsh-prestep`, capability `session-prestep`): implemented and
tested in `dsh/bundle/lib/prestep.js` + `index.js`; live verification waits for
the bundle reinstall.
3. Build `briefing` as an agent preset (read-only tools + model route).
4. SDD — **done** (change `dsh-sdd`): the `sdd` skill (async controller,
reports, review, fix-loop, ledger) plus the overlay in §5; proven by a
three-task trial run (`openspec/changes/dsh-sdd/trial/`, results in
`design.md`).
5. Enable CodeGraph MCP by default when the binary is present; update role and
project instructions to `mcp__codegraph__codegraph_explore`.
6. Port `harness-doctor` checks to DSH paths.
7. Decide the long-term home: keep `dsh/` in this repository while it shares
hooks/roles/skills, then extract a `dsh-harness` repository when the bundle
gets its own release cadence.
8. OpenSpec — **done** (change `dsh-openspec`): проектные скиллы, `--openspec`,
`--check`; приёмка — в дизайне change.
9. Install without `~/.claude` — **done** (change `dsh-install-source`):
`--superpowers-from`/`DSH_SUPERPOWERS_SOURCE`/`~/.dsh/superpowers`, hard
`FAIL` instead of a silent empty bootstrap, DSH-owned role paths in the
installed `AGENTS.md`, legacy warnings at install and runtime.