This checklist keeps a release tied to the same gates that protect the agent workflow.
Start from the remote mainline:
git fetch origin
git switch main
git merge --ff-only origin/mainConfirm the version and workspace health:
deepseek version
deepseek doctor
deepseek doctor --jsonFor source builds, deepseek version must match the version in Cargo.toml.
deepseek doctor --json must emit valid JSON for local supervisors and release automation.
For launch-quality README media, use the model-backed demo recorder against a disposable fixture before generating GIF/MP4 assets:
printf '%s\n' '<deepseek-api-key>' > /tmp/deepseek-demo.key
chmod 600 /tmp/deepseek-demo.key
DEEPSEEK_DEMO_KEY_FILE=/tmp/deepseek-demo.key docs/demo/record-model-backed-demo.sh
latest_log=$(ls -t docs/demo/deepseek-code-model-demo-*.log | head -n 1)
docs/demo/verify-model-backed-demo.js "$latest_log"
docs/demo/render-model-backed-demo-svg.js "$latest_log" --out docs/demo/deepseek-code-model-demo.svgRun the full local release gate before tagging or publishing:
cargo fmt --check
cargo test -- --test-threads=1
cargo package --allow-dirty
node scripts/check-secrets.js
deepseek benchmark
docs/demo/record-model-backed-demo.sh --dry-run
docs/demo/record-model-backed-demo.sh --redaction-self-test
docs/demo/verify-model-backed-demo.js --self-test
docs/demo/render-model-backed-demo-svg.js --self-test
mkdir -p target/loop-evidence
deepseek dogfood repair-cache-evidence --out target/loop-evidence/repair-cache-evidence.json --json
after_thread=$(node -e "const fs=require('fs'); const j=JSON.parse(fs.readFileSync('target/loop-evidence/repair-cache-evidence.json','utf8')); process.stdout.write(j.after_thread_id)")
deepseek stats --thread "$after_thread" --require-prefix-stable --jsondeepseek benchmark must pass all three layers:
- benchmark case expectations
- benchmark trend gate
- dogfood live gate
The live gate blocks release when new dogfood failures, stuck runs, or manual interventions appear after the previous benchmark snapshot.
Failed benchmark gates do not advance the saved benchmark history baseline. After triaging known live failures, use
deepseek benchmark --accept-live-baseline only to intentionally accept the current dogfood snapshot; do not use it for normal release checks.
deepseek benchmark --category <name> and repeatable --case <name> are for targeted evidence reports only; filtered runs skip history writes and full trend/live enforcement, so they do not replace the release benchmark.
The Release Matrix packaging job also runs the deterministic repair/cache
evidence command and stats --require-prefix-stable, then uploads the JSON
outputs as the deepseek-loop-evidence artifact.
Replay at least one standard write/validate task and one retry task:
deepseek dogfood run --from-benchmark fixture-write-validate-rust-mini --notes "release replay"
deepseek dogfood run --from-benchmark fixture-retry-write-validate-python-mini --notes "release retry replay"
deepseek dogfood report --limit 5If a replay exposes a new failure, fix the root cause before publishing. Do not release by overriding the dogfood outcome.
For external write-fixture evidence, use a disposable git repository outside
this checkout. Always dry-run first; the real run copies the repository to an
isolated workdir and records an external-write-fixture dogfood row. Real
external fixture evidence now fails closed unless the configured model transport
is online/model-backed. --allow-offline exists only for rehearsal and does not
satisfy release gates:
deepseek dogfood external-fixture --workdir /tmp/disposable-repo --dry-run \
'replace `a - b` with `a + b` in src/lib.rs and validate with cargo test'
deepseek dogfood external-fixture --workdir /tmp/disposable-repo --benchmark-gate \
--evidence-out .dscode/dogfood/external-fixture-evidence.json \
'replace `a - b` with `a + b` in src/lib.rs and validate with cargo test'
deepseek dogfood report --limit 10
deepseek dogfood live-plan --limit 10
deepseek dogfood live-run --api-key-file /tmp/deepseek-live.key --category mcp --limit 3 --json
deepseek dogfood live-run --api-key-file /tmp/deepseek-live.key --category mcp --limit 3
# Add --execute only when you intend to spend online model calls:
deepseek dogfood live-run --api-key-file /tmp/deepseek-live.key --category mcp --limit 3 \
--evidence-out .dscode/dogfood/live-evidence.json --execute
deepseek dogfood live-evidence --file .dscode/dogfood/live-evidence.json \
--out .dscode/dogfood/live-evidence-verification.json \
--require-benchmark-gate --require-report-gate \
--require-loop-surface-gateThe live-plan and live-run --json output include post_run_report_command;
run that command after the online batch to verify the model-backed rows and
category thresholds. With --evidence-out, the online batch also writes a
deepseek.dogfood.live_run_evidence.v1 JSON summary covering before/after live
counts, appended model-backed rows, per-case outcomes, and benchmark gate result
without storing the API key value. The summary also binds the evidence to the
ledger file with an fnv1a64 fingerprint. dogfood live-evidence verifies that
summary as a fail-closed release step; --require-report-gate validates the
structured evidence_gate thresholds, including the live recency threshold,
against the current ledger instead of executing a shell command from the JSON
file, rechecks the ledger fingerprint, and verifies that each appended case
evidence row can be matched back to the ledger by timestamp, outcome, transport,
and category.
--require-loop-surface-gate additionally requires MCP dynamic and resource
loop-surface evidence plus a structured evidence_gate mcp live-category
threshold of at least three runs.
Use --out to persist the verification JSON for release evidence upload.
For external fixtures, --evidence-out writes
deepseek.dogfood.external_fixture_evidence.v1 with the source workdir, appended
external-fixture ledger row(s), the extracted validate with ... command,
post_validation_passed, release-evidence readiness boolean, and the same
ledger fingerprint binding used by live-run evidence. dogfood external-evidence --require-successful-external-fixtures N fails closed unless
the evidence is online/model-backed, completed, matched back to the current
ledger, and has post_validation_passed=true.
The canonical tracked release fixture is the disposable Python invoice sample. Tracked Rust and Node evidence files are also available for broader evidence depth, and the fixture generator can refresh all three samples:
base=/tmp/deepseek-external-fixtures
scripts/create-multifile-external-fixture.sh "$base/python-invoice-multifile" python-invoice-multifile --force
scripts/create-multifile-external-fixture.sh "$base/rust-order-multifile" rust-order-multifile --force
scripts/create-multifile-external-fixture.sh "$base/node-task-report" node-task-report --forceUse the Python invoice fixture as the canonical release-evidence path:
fixture_dir=/tmp/deepseek-external-fixtures/python-invoice-multifile
scripts/create-multifile-external-fixture.sh "$fixture_dir" python-invoice-multifile --force
task='replace `return amount - discount` with `return max(amount - discount, 0.0)` in src/invoice_math/pricing.py and replace `Invoice total` with `Final total` in src/invoice_math/summary.py, validate with python3 -m unittest discover -s tests'
deepseek dogfood external-fixture --workdir "$fixture_dir" \
--evidence-out .dscode/dogfood/external-fixture-python-invoice-multifile-evidence.json \
"$task"
deepseek dogfood external-evidence \
--file .dscode/dogfood/external-fixture-python-invoice-multifile-evidence.json \
--out .dscode/dogfood/external-fixture-python-invoice-multifile-verification.json \
--require-successful-external-fixtures 1For a release-readiness evidence gate, make the report fail closed when the ledger does not have enough live proof:
deepseek dogfood report --limit 20 \
--require-min-runs 100 \
--require-success-rate 90 \
--require-live-runs 100 \
--require-live-success-rate 90 \
--require-live-recent-days 7 \
--require-recent-clean 20 \
--require-external-write-fixtures 3 \
--require-category write_validate:25:90 \
--require-category recovery:25:90 \
--require-category pr_workflow:25:90 \
--require-live-category write_validate:25:90 \
--require-live-category recovery:25:90 \
--require-live-category pr_workflow:25:90 \
--require-live-category mcp:3:90For a local release binary:
cargo build --release
./target/release/deepseek version
./target/release/deepseek doctor
./target/release/deepseek doctor --json
./target/release/deepseek update package --bin ./target/release/deepseek
./target/release/deepseek update verify-install --bin ./target/release/deepseek
./target/release/deepseek agents service --kind all --out target/service-smoke --bin ./target/release/deepseek --workdir "$PWD"
./target/release/deepseek agents service-doctor --kind all --out target/service-smoke --bin ./target/release/deepseek --workdir "$PWD" --json
mkdir -p /tmp/dsc-smk
./target/release/deepseek agents service-smoke --bin ./target/release/deepseek --workdir /tmp/dsc-smk --json
./target/release/deepseek agents shell-fixture-smoke --json
./target/release/deepseek task fixture-smoke --json
./target/release/deepseek github fixture-smoke --json
./target/release/deepseek tui --entrypoint-smoke --smoke-bin ./target/release/deepseek
test -f target/service-smoke/SERVICES.md
./target/release/deepseek agents rlm-status --json
cargo package --allow-dirty
(cd npm && npm run check:version)
(cd npm && npm test)
DEEPSEEK_BINARY=./target/release/deepseek node npm/bin/deepseek.js version
DEEPSEEK_BINARY=./target/release/deepseek node npm/scripts/test-tui-entrypoint-wrapper.js
node npm/scripts/stage-platform-package.js --platform linux-x64 --binary ./target/release/deepseek
node npm/scripts/verify-platform-package.js --platform linux-x64
./target/release/deepseek update publish-statusFor the runtime contract, start ./target/release/deepseek serve --http and
capture /health plus /runtime from the release binary before publishing.
Also smoke the MCP stdio server with initialize and tools/list:
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
'{"jsonrpc":"2.0","id":3,"method":"prompts/list","params":{}}' \
'{"jsonrpc":"2.0","id":4,"method":"prompts/get","params":{"name":"review_code","arguments":{"path":"README.md"}}}' \
'{"jsonrpc":"2.0","id":5,"method":"resources/list","params":{}}' \
'{"jsonrpc":"2.0","id":6,"method":"resources/templates/list","params":{}}' \
| ./target/release/deepseek serve --mcpFor the side-effect MCP surface, smoke the trusted direct path in a temporary workspace:
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"run_shell","arguments":{"command":"pwd"}}}' \
| DSCODE_MCP_ENABLE_SIDE_EFFECTS=1 ./target/release/deepseek serve --mcpThe durable approval path for run_shell and apply_patch is covered by
cargo test mcp; release notes should call out
DSCODE_MCP_ENABLE_DURABLE_APPROVALS=1 and
DSCODE_MCP_APPROVAL_THREAD_ID=<thread-id> when documenting MCP clients.
Smoke the ACP stdio adapter with initialize and session/list:
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":1}}' \
'{"jsonrpc":"2.0","id":2,"method":"session/list","params":{"limit":5}}' \
| ./target/release/deepseek serve --acpSmoke MCP self-registration in a temporary workspace so it does not touch your user MCP config:
tmp="$(mktemp -d)"
(cd "$tmp" && "$OLDPWD/target/release/deepseek" mcp add-self --project --name release-deepseek)
(cd "$tmp" && "$OLDPWD/target/release/deepseek" mcp add release-http --project --url http://127.0.0.1:3999/mcp --disabled)
(cd "$tmp" && "$OLDPWD/target/release/deepseek" mcp get release-http)
(cd "$tmp" && "$OLDPWD/target/release/deepseek" mcp resources)
(cd "$tmp" && "$OLDPWD/target/release/deepseek" mcp resource-templates)
(cd "$tmp" && "$OLDPWD/target/release/deepseek" mcp remove release-http --project)The TUI full-width MCP manager screen and scrollable right-side discovery detail panel are covered by the focused unit filter:
cargo test mcpFor the Docker artifact:
docker build -t deepseek-code:<version> .
docker run --rm deepseek-code:<version> versionTag releases also publish the source-built image to GHCR through the Release Matrix workflow:
docker pull ghcr.io/<owner>/<repo>:<version>
docker run --rm ghcr.io/<owner>/<repo>:<version> versionFor the GitHub release matrix:
gh workflow run "Release Matrix"
gh run watchThe workflow builds release binaries for Linux x64, Linux arm64, macOS x64,
macOS arm64, and Windows x64. Linux jobs run the full serial test suite with
cargo test -- --test-threads=1; macOS and Windows run
cargo check --all-targets before the release binary/package smoke so the
platform matrix still catches compile drift without depending on Unix-specific
test fixtures.
The workflow also runs packaging checks for Cargo metadata, cargo package,
Cargo/npm/Homebrew version sync, the npm wrapper, root/platform npm dry
packaging, Homebrew formula syntax, Docker image build/run smoke, and runtime
service template rendering.
Each platform build also smoke-runs the binary after staging it into the
matching npm platform package, before packing the tarball that may be published
to npm.
Each platform artifact includes a sibling .sha256 file, for example
deepseek-macos-arm64.tar.gz.sha256. The build job also creates GitHub signed
artifact attestations for each archive and checksum file.
Before relying on a tag workflow to publish npm or Homebrew, run the local readiness check. Without artifact directories it reports metadata and missing external configuration only:
deepseek update publish-status
deepseek update publish-status --jsonAfter downloading release matrix assets and npm platform package artifacts, run the strict gate:
deepseek update publish-status \
--dist dist-assets \
--npm-dist npm-dist \
--live-evidence-verification .dscode/dogfood/live-evidence-verification.json \
--strict--strict fails when NPM_TOKEN/NODE_AUTH_TOKEN,
HOMEBREW_TAP_REPOSITORY, HOMEBREW_TAP_TOKEN, platform release archives,
non-placeholder .sha256 files, platform npm package tarballs, or verified
recent online dogfood live evidence with MCP dynamic/resource loop-surface
coverage and gate are missing.
The text and JSON output also include a public_install audit for source
checkout, GitHub Release, npm, Homebrew, GHCR, and Cargo registry policy. Treat
ready_to_publish as local readiness only: do not advertise npm, Homebrew,
Docker, or release-binary install paths until the corresponding verification
command in that audit succeeds against the live public channel.
When the workflow runs from a v* tag, it also creates or updates the matching
GitHub Release and uploads every platform archive plus checksum file as release
assets. It also packs platform npm packages from the compiled binaries. Manual
workflow_dispatch runs keep assets as workflow artifacts only. Tag runs also
publish a GHCR Docker image as ghcr.io/<owner>/<repo>:<version>,
ghcr.io/<owner>/<repo>:v<version>, and ghcr.io/<owner>/<repo>:latest with
OCI source, revision, and version labels. Tag runs also run the Cargo registry
policy job after packaging checks and run npm publish after platform package
artifacts are available. Cargo registry distribution is intentionally
source-build/package-only for now: Cargo.toml sets publish = false, and the
Cargo registry workflow job exits successfully when that policy is present.
Remove that flag only after there is an explicit crates.io or private registry
ownership decision. The npm publish step is skipped when NPM_TOKEN is not
configured. The Homebrew tap publish step is skipped unless
HOMEBREW_TAP_REPOSITORY and HOMEBREW_TAP_TOKEN are configured; when enabled,
it renders Formula/deepseek.rb from the uploaded release checksums and pushes
it to the tap repository after the GitHub Release assets are published. The
npm publish step fails if the tag does not match the package version it
publishes.
Verify downloaded release artifacts with:
deepseek update download-plan --version <version>
deepseek update download-plan --version <version> --json
deepseek update release-smoke --version <version>
deepseek update release-smoke --version <version> --json
gh attestation verify deepseek-macos-arm64.tar.gz --repo <owner>/<repo>
gh attestation verify deepseek-macos-arm64.tar.gz.sha256 --repo <owner>/<repo>release-smoke is the operator shortcut for current-platform release-binary
evidence: it downloads the archive and .sha256, verifies the checksum,
extracts the deepseek binary, and runs the same install verifier used by
deepseek update verify-install. It only executes binaries for the current
platform; use the Release Smoke workflow when you need clean hosted evidence
for Linux x64, Linux arm64, macOS x64, and macOS arm64 from one run.
If GitHub release downloads are slow or blocked for an operator, mirror the
release archive and .sha256 files to a private/static asset host and point the
plan generator at that directory:
DSCODE_RELEASE_BASE_URL=https://<mirror>/<release-assets> \
deepseek update download-plan --version <version>For the Homebrew formula:
node packaging/homebrew/verify-formula.js
ruby -c packaging/homebrew/deepseek.rb
deepseek update homebrew-formula \
--version <version> \
--repo <owner>/<repo> \
--dist <downloaded-release-artifact-directory> \
--formula packaging/homebrew/deepseek.rb
node packaging/homebrew/verify-formula.js --release
ruby -c packaging/homebrew/deepseek.rbBefore publishing a tap, download the release matrix .sha256 files next to
their archives and run deepseek update homebrew-formula. The updater reads
deepseek-linux-x64.tar.gz.sha256, deepseek-linux-arm64.tar.gz.sha256,
deepseek-macos-x64.tar.gz.sha256, and deepseek-macos-arm64.tar.gz.sha256,
then rewrites the formula with matching release URLs and checksums.
To automate tap publishing from the tag workflow, set repository variable
HOMEBREW_TAP_REPOSITORY to the tap repository, for example
owner/homebrew-tap, and set secret HOMEBREW_TAP_TOKEN to a token with write
access to that repository.
Release notes should include:
- version
- commit SHA
- platform
deepseek versionoutputdeepseek doctor --jsonoutputdeepseek serve --http/healthand/runtimeoutputdeepseek serve --mcpinitialize,tools/list,prompts/list,prompts/get,resources/list, andresources/templates/listoutput; plus trustedDSCODE_MCP_ENABLE_SIDE_EFFECTS=1run_shellsmoke in a temp workspace and unit coverage for the durable approval path, including MCPapply_patchdeepseek serve --acpinitializeandsession/listoutputdeepseek mcp add-self --projectandmcp add/get/remove --projecttemp-workspace smoke outputcargo test mcpoutput covering TUI MCP manager command parsing, full-width manager rendering, local project/user config mutation, right-side MCP detail rendering/scrolling, and MCP prompt/resource/template client bridgesrelease.jsonfromdeepseek update packageSERVICES.md, generated service-template smoke output includingtarget/service-smoke/SERVICES.md,deepseek agents service-doctor --jsonoutput showing zero blockers for rendered templates and a passingtemplate_command_vectorscheck proving generated systemdExecStartplus launchdProgramArgumentsparse to the expected argv/workdir,deepseek agents service-doctor --installed --jsonoutput from any clean machine where the generated user services were actually installed, showing the four systemd units or four launchd labels are loaded/running,deepseek agents service-smoke --installed --jsonoutput from that same clean machine showing the installed runtime/healthand shell-supervisor control plane respond without stopping service-manager-owned processes,deepseek agents service-smoke --jsonoutput showing runtime startup plus shell-supervisor start/wait/attach/replay proof plus Linux PTY stdin/resize/cancel proof, anddeepseek agents rlm-status --jsonoutput showing the live RLM service lifecycle surfacedeepseek task fixture-smoke --jsonoutput showing the background worktree runner can create an isolated task worktree, list the durable record, dry-run merge, apply tracked/untracked changes back to the original repo, reject a task, and clean up the temporary repodeepseek github fixture-smoke --jsonoutput showing GitHub Action event routing, write-mode/fork guard behavior, fixture branch push verification, and background-task worktree/record creationnpm testoutput fromnpm/- root and platform npm package tarball names
- Docker image tag and
docker run ... versionoutput - release matrix run URL, artifact names,
.sha256file contents, and attestation verification output - Homebrew formula SHA-256 values
- release gate result
- upgrade and rollback instructions
deepseek is the release artifact name. dscode is only a compatibility alias.
Source upgrade:
git pull
cargo install --path . --force
deepseek version
deepseek doctorBinary upgrade:
deepseek update install-package --package target/deepseek-release/deepseek-<version>-<platform>Replace the binary, then validate:
deepseek update verify-install --bin "$(command -v deepseek)"Rollback:
deepseek update rollback
deepseek update verify-install --bin "$(command -v deepseek)"