Getting Started · 03
Run from Source: Clone, Build with pnpm, and Start Developing
Build a reproducible contributor checkout, understand generated artifacts, launch the Web and headless profiles, and diagnose source failures without hiding them.
- Reading time
- 16 minutes
- Sources verified
Know when source execution is the right tool
Use a source checkout when you need to trace a plugin dependency, inspect generated contracts, change a package, reproduce a repository test, or contribute upstream. If your only objective is to evaluate the shipped Web interface, the published npx command is smaller and avoids a monorepo build. Source execution adds responsibility: your working tree, dependency graph, generated artifacts, and browser bundles all become part of the runtime you are testing.
The repository is a pnpm workspace containing host packages, client packages, apps, Python assets, examples, scripts, and vendored code. A successful install alone does not create every JavaScript file or declaration that production-style profile boot expects. The CLI source entry runs TypeScript directly, but many dependencies still consume generated or built artifacts. Keep ‘launcher can execute TypeScript’ separate from ‘the complete profile has current artifacts.’
- Use source mode to change or debug plugins and configuration.
- Use package mode to evaluate a reviewed published release.
- Use a separate checkout for experiments that allow agent writes.
- Never interpret an unbuilt or dirty checkout as evidence about a released package.
Meet the repository-owned Node.js and pnpm floors
The current development guide supports Node.js 22.19+ and 24+, while CI also carries a forward signal on 26. The repository pins pnpm 11.7.0 in packageManager. Corepack should resolve that pinned version, preventing a global pnpm from silently selecting different lockfile or lifecycle behavior. Verify the exact binaries before installation, especially when a version manager changes shells independently.
node --version
corepack enable
pnpm --version
node -p "require('./package.json').packageManager"Success means Node satisfies the declared engine and pnpm reports 11.7.0 through Corepack. If pnpm is missing after corepack enable, confirm that the selected Node distribution includes Corepack and that your shell resolves the same Node binary. Do not edit packageManager merely to match a machine; align the machine to the checkout.
Clone the official repository and install the locked workspace
Clone over HTTPS unless your environment already has an approved SSH identity. Inspect the current branch and status before installing, then let pnpm resolve the workspace from its lockfile. The official contributor setup uses pnpm install. Avoid deleting or regenerating the lockfile as a generic recovery step because that changes the dependency experiment you are trying to reproduce.
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
git status --short --branch
corepack enable
pnpm installA successful install completes without unresolved workspace packages and creates node_modules links managed by pnpm. If registry access fails, diagnose DNS, proxy, authentication, or certificate policy before retrying. If lifecycle execution is blocked, read the exact pnpm message rather than disabling all build protections. The root instructions explicitly require narrow host escalation when a sandbox blocks network or IPC, but they do not permit bypassing a genuine dependency or test failure.
pnpm config get registry
pnpm why typescript
git diff -- pnpm-lock.yamlUse typecheck as the setup completion signal
The development guide defines setup completion as pnpm run typecheck exiting successfully. This gate is more substantial than a single tsc call. Host-side Typert generation runs before the Client TypeScript phase so generated remote contracts exist when client types are checked. A typecheck failure can therefore reveal a missing host artifact, an invalid package boundary, or a real type error before you spend time on a complete build.
pnpm run typecheckSuccess is exit status zero with no suppressed diagnostics. When it fails, identify the owning package from the path and error, preserve the first failure, and select the smallest relevant command from that package. Do not add casts, skipLibCheck, or generated files by hand simply to make the root command green. Generated contracts have an owner and regeneration path.
git status --short
pnpm --filter @deepseek-ai/dsh --help
# Then run the owning package's documented test or build command.Build runtime packages and browser artifacts in the owned order
Run the root build after a fresh checkout and whenever artifacts need updating. It emits package JavaScript and declarations, bundles runtime code, and continues through client and Web builds. The source launcher itself uses node with tsx/esm, but profile dependencies may import built libraries. Missing Typert host artifacts fail as module-resolution errors; missing frontend or client-plugin bundles fail at startup with an instruction to build.
pnpm run buildThe launcher does not check artifact freshness. Existing output from another commit can boot and serve older browser code, creating a particularly misleading failure: server-side changes appear current while the UI remains stale. Rebuild after changing revisions or client packages. For focused Web work, the repository also exposes build:web, but that narrower command is not a substitute for the initial complete build when host artifacts are absent.
pnpm run build:web
git status --short
find apps packages -path '*/lib/*' -type f | headSuccess means the command exits zero and the expected bundles exist. A fresh checkout has no bundled JS or declarations before build, so hygiene commands that validate package entry points should not be used as a shortcut around this step.
Launch Web and headless through the source CLI
From the repository root, pnpm dsh forwards arguments to the TypeScript CLI entry. Start with help and dump-config so you can separate launcher and composition errors from application boot. Then boot the desired profile. The invoking directory is the default workspace root, so launching from the harness repository grants the session a view of the harness checkout. For an agent experiment, use a separate disposable workspace or explicitly select one in Web.
pnpm dsh --help
pnpm dsh --profile web --dump-config > /tmp/dsh-web.yml
pnpm dsh webThe production Web runner defaults to http://127.0.0.1:3080. A source process still needs built Web assets. For a one-shot smoke test, headless accepts the job after profile selection, prints its final answer, persists a fresh session, and exits.
export DEEPSEEK_API_KEY="<injected-by-your-secret-manager>"
pnpm dsh --profile headless "Summarize this workspace without modifying files."Use the Web development loop without confusing host and client rebuilds
The installed production runner serves built assets. For client development, the CLI reference notes that the client-plugin HMR receiver is always mounted but remains idle until a separate pnpm run dev:web watcher rebuilds client bundles. Run the host and watcher in separate terminals. A client edit should trigger a rebuild and reach the browser receiver; a host-package edit may require the owning build or a profile restart depending on its artifact and lifecycle contract.
# Terminal 1, after the complete build:
pnpm dsh web
# Terminal 2:
pnpm run dev:webObservable success is a watcher rebuild followed by the expected browser update, without the host serving a previous bundle. If the receiver stays idle, confirm that the watcher is running from the repository root and that it produced the relevant client package. If server behavior changes but UI behavior does not, rebuild Web artifacts and perform a hard reload before diagnosing application state.
Change classification
Client component or style → dev:web watcher and browser HMR
Host plugin implementation → owning package build/test, often restart
Cordis patch row → watched transactional reapply when valid
Profile dependency → dsh plugin workflow, then restart and dump configInspect and change Cordis configuration without losing fields
A profile layers Bundles, the profile cordis.patch.yml, the home patch, and optional --patch overlays. Each patch targets a row by id and replaces its entire config rather than deep-merging nested values. Begin from the resolved row, preserve every field you still need, and compare dumps before boot. Valid edits to profile and home patch files are watched and reapplied transactionally.
pnpm dsh --profile web --dump-default-config > /tmp/default.yml
pnpm dsh --profile web --dump-config > /tmp/resolved.yml
diff -u /tmp/default.yml /tmp/resolved.ymlA CLI-provided service can feed expressions in a row, such as the Web startup port. Replacing the whole config with literals can remove that runtime expression and make a flag appear ineffective. If a patch breaks boot, restore the complete previous row, rerun dump-config, and add one intentional change at a time.
# Example shape only: preserve the complete resolved config.
- id: llm-deepseek
name: '@deepseek-ai/dsh-llm-deepseek'
config:
apiKeyEnv: DEEPSEEK_API_KEY
baseURL: https://api.deepseek.comSelect tests that match the surface you changed
The repository exposes unit tests, typecheck, lint, build, documentation synchronization, snapshots, real-API e2e, and comprehensive gates. The root instructions say to choose the smallest checks that cover the changed surface. A package implementation change normally needs its focused tests plus typecheck. A public behavior or JSDoc change may require the owning README and doc gates. A built-artifact consumer needs a build first.
pnpm --filter <owning-package> test
pnpm run typecheck
pnpm run lint
pnpm run buildReal-API e2e requires DEEPSEEK_API_KEY and self-skips without it. Snapshot recording also needs a key, while replay against expected output is keyless. Do not record new snapshots simply because replay failed; determine whether behavior intentionally changed and review the resulting session facts.
pnpm run test:snapshot
# Only for an intentional, reviewed update with credentials:
pnpm run test:snapshot:recordDiagnose common source failures and leave a reproducible handoff
Classify failures by phase. Installation errors belong to registry access, pnpm policy, or lockfile resolution. Typecheck errors identify source or generated-contract inconsistencies. Build errors identify artifact production. dump-config errors identify profile or patch composition. Boot errors after a successful dump belong to the selected runner, missing assets, port, trust, credential, or provider. A task failure after boot belongs to session, model, tools, or policy.
Proxy-dependent Node fetches may require NODE_USE_ENV_PROXY=1 on supporting Node versions so inherited HTTP_PROXY and HTTPS_PROXY are honored. Use this only when the environment actually mandates a proxy. A refused local port is not a proxy problem. A stale browser is not a credential problem. Preserve the earliest specific error rather than applying several speculative fixes at once.
git status --short
node --version
pnpm --version
pnpm run typecheck
pnpm dsh --profile web --dump-config > /tmp/resolved.yml
NODE_USE_ENV_PROXY=1 pnpm dsh webFor handoff, record the commit, Node and pnpm versions, commands run, focused test results, and whether credentials or real APIs were involved. Do not delete another contributor's dirty changes, generated evidence, or session data. Use pnpm run clean only for the safe build outputs defined by the repository, and review git status before and after.
git rev-parse HEAD
git status --short
printf 'Node %s; pnpm %s\n' "$(node --version)" "$(pnpm --version)"Official sources
- Development guide ↗Supports: Node.js support, pnpm setup, typecheck completion, build and demo commands, generated contract ordering
- CLI source-execution reference ↗Supports: Source launcher, artifact failures, Web HMR, patch watching, proxy and workspace behavior
- CLI application README ↗Supports: Profile modes, argument forwarding, production build requirement, headless source command
- Cordis configuration tutorial ↗Supports: Plugin configuration, schema and configuration lifecycle
- Architecture guide ↗Supports: Profile, Bundle, and patch precedence, whole-row replacement semantics

