DeepSeek Harness

Preview

Run DeepSeek Harness in a sandbox on the open models of Munito AI, headless or through the remote Web UI.

For files on your computer, use the local desktop and CLI guide.

Install the CLI

npm install -g @munitoai/cli

The command is munito. See the command line tool.

One command

munito agent dsh "fix the failing test"

It creates the sandbox, runs the task and applies the patch back. The agent template carries DeepSeek Harness, pointed at Munito AI.

munito agent dsh --model deepseek-ai/deepseek-v4.1-flash-1017 "fix the failing test"

See Regions for the EU host.

Through the API

SANDBOX=$(
  curl -sS --fail-with-body https://api.munito.ai/sandboxes/v1/sandboxes \
    -H "Authorization: Bearer $MUNITO_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"template": "agent", "agent": "dsh", "internet": true, "persistent": true,
         "env": {"MUNITO_API_KEY": "'"$MUNITO_API_KEY"'"}}' |
  jq -er '.id'
)
export SANDBOX

"agent": "dsh" writes the provider profile and puts the key where Harness reads it. Add "model" to select another model. Then run a task:

curl -sS --fail-with-body "https://api.munito.ai/sandboxes/v1/sandboxes/$SANDBOX/exec" \
  -H "Authorization: Bearer $MUNITO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"command": "dsh headless \"Add a test for the empty case\"", "cwd": "/workspace", "timeout": 1800}' |
  jq -er 'if .exit_code == 0 then .stdout else error(.stderr) end'
  • dsh headless runs one task and exits.
  • Upload your project through the files API, or clone it into /workspace.
  • For a task over 30 minutes, use a background command.

The remote Web UI

The Web UI runs in the sandbox, and your browser reaches it through an SSH tunnel. Port 3080 stays private.

Start the server. The provider is at /root/.dsh/cordis.patch.yml, which every surface of Harness reads, so the Web UI needs no setup of its own:

DSH_COMMAND=$(
  curl -sS --fail-with-body "https://api.munito.ai/sandboxes/v1/sandboxes/$SANDBOX/commands" \
    -H "Authorization: Bearer $MUNITO_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"command": "dsh web --no-open --port 3080", "cwd": "/workspace", "timeout": 3600}' |
  jq -er '.id'
)
export DSH_COMMAND
  1. Open the tunnel: munito ssh $SANDBOX -- -N -L 3080:127.0.0.1:3080.
  2. Read the launch URL of the Web UI:
curl -sS --fail-with-body \
  "https://api.munito.ai/sandboxes/v1/sandboxes/$SANDBOX/commands/$DSH_COMMAND" \
  -H "Authorization: Bearer $MUNITO_API_KEY" | jq -r '.stdout'
  1. Open that whole http://127.0.0.1:3080/... URL in your browser, including its authentication part.

The launch URL is a credential. Keep it private. If the output is still empty, Harness is starting: read the command again. If local port 3080 is taken, tunnel 3081:127.0.0.1:3080 and change the port in the URL.

Every surface shares one Harness home, so the Web UI can reopen the session of a headless task. A pause keeps the files and ends the Web UI, so start it again after a resume.

The Web UI on a sandbox desktop

A desktop sandbox has its own Firefox, so the Web UI needs no tunnel and the launch URL never leaves the sandbox. Create it with "template": "desktop", then copy the profile and start the server as above. Open the launch URL on the desktop:

DSH_URL=$(
  curl -sS --fail-with-body \
    "https://api.munito.ai/sandboxes/v1/sandboxes/$SANDBOX/commands/$DSH_COMMAND" \
    -H "Authorization: Bearer $MUNITO_API_KEY" |
  jq -r '.stdout' | grep -o 'http://127.0.0.1:3080/[^ ]*' | head -1
)

curl -sS --fail-with-body "https://api.munito.ai/sandboxes/v1/sandboxes/$SANDBOX/exec" \
  -H "Authorization: Bearer $MUNITO_API_KEY" -H "Content-Type: application/json" \
  -d "$(jq -n --arg u "$DSH_URL" '{command: ("DISPLAY=:0 setsid firefox \"" + $u + "\" >/dev/null 2>&1 &")}')"

Watch and use the desktop with munito open $SANDBOX. A desktop needs 2 vCPUs and 4 GiB at least, and it adds $0.10 for each hour that it runs.