DSH_SOURCE is an install-time shell variable the installer never exports, so
a skill reading ${DSH_SOURCE} at runtime reads nothing. Verified unset in a
running dsh process.
Git resolves the main clone identically for every install, so the curl-vs-
adopted distinction was never a branch point in these workflows. Verified
one launcher-then-Git recipe against three shapes: a curl install cloning
into the container, an adopted clone nested far outside any container, and
a custom DSH_SOURCE container.
dsh-customize now states that single procedure and warns off the installer
variables. dsh-upgrade's Layout describes what the resolution finds rather
than a path convention, and no longer teaches install shapes as cases.
4.8 KiB
name, description
| name | description |
|---|---|
| dsh-customize | Customize or maintain any dsh source checkout — the one powering the current DSH process, the installed `dsh` command, or a sibling dsh/deepseek-harness clone. Use before any requested action that alters such a checkout's files or git state. Read-only questions that only inspect the checkout do not trigger this. Do not edit the personal staging checkout directly. |
DSH Customize
Make personal DSH changes in task worktrees and integrate them under the staging lock. Repository instructions still apply.
Find staging
Do not assume a path or branch name. DSH is usually installed from source with a personal staging branch; create one for the user only when none exists.
-
Inspect
command -v dshin the user's launch environment before resolving symlinks. -
Follow the launcher through the full symlink chain to reach the source checkout, then ask Git for everything else. The
dshon PATH is a symlink, usually through a stablecurrentsymlink into the active staging worktree; resolve the chain physically and take the launcher's parent directory as the checkout. Derive the rest from that checkout rather than from any path convention:git -C <checkout> rev-parse --show-toplevelconfirms the checkout root, andgit -C <checkout> rev-parse --git-common-dirgives the shared git directory — a linked worktree reports the real clone's, not its own — whose parent is the main clone, the one real clone whose object store every worktree shares.--git-common-diranswers relatively for a plain clone, so anchor it against the checkout before use, and resolve it physically: comparing a resolved path against an unresolved one silently misidentifies the clone, since macOS reaches/varthrough a symlink to/private/var.git -C <main clone> worktree listthen enumerates every checkout sharing it.This one procedure covers every install.
scripts/install.shputs staging worktrees andcurrentunder a container directory (default~/.dsh/source), and acurlinstall also clones into that container while installing from an existing clone adopts that clone where it already lives — but nothing in this workflow depends on which happened, on the container's path, or on the main clone's branch.DSH_SOURCEand the installer's other variables exist only while the installer runs; they are never exported, so never read them here. An older install may link PATH straight at a worktree with nocurrent, which the same launcher-then-Git procedure resolves unchanged. -
Verify the checkout with Git, then record its branch, tip, status, remotes, worktrees, in-progress operations, and applicable
AGENTS.mdfiles. -
Treat the launcher checkout's branch as staging unless the user says otherwise. The installed launcher must resolve to a staging worktree on a staging branch, never the main clone or a task, preparation, review, publication, or detached checkout. Ask if the launcher, checkout, or branch ownership is ambiguous; warn explicitly for a detached HEAD, the main clone, or a non-staging branch.
Customize
- Create a fresh task branch and worktree from the recorded staging tip, using the repository-required worktree location — default to
.worktrees/under the repository root unless the repository requires otherwise. Never implement or commit directly on staging. - Implement the change, then select and run the repository-required review and checks. If a check fails, fix the cause and rerun it before integration.
- For TUI or interactive behavior, test the assembled application interactively in a dedicated tmux session; unit tests and snapshots alone are insufficient.
- Record the task tip and confirm the task worktree is clean before integration.
Integrate under the lock
- Resolve the worktree that owns staging and use
<staging-worktree>/.agents/merge.lock. Keep it Git-ignored; never remove or replace it. Requireflock. - Acquire the lock, then re-check branch ownership, exact staging tip, clean status, and absence of an in-progress Git operation. If staging moved, unlock and restart discovery against its current owner's lock.
- Hold the same lock through final precondition checks,
git merge --no-ff, required post-merge checks, conflict handling, and rollback. - If the merge or a post-merge check fails, abort the merge or restore the recorded clean staging tip before unlocking. Never discard unknown user files.
- Before unlocking, verify staging's branch, commit, clean status, and required checks. Report that evidence and the commands run.
- Remove the task worktree and branch only when their commits are reachable from staging and no longer needed.
Use dsh-upstream-customization when the user wants to contribute a personal feature upstream.