Preface

The common practice for extending agent capabilities in DeepSeek Harness (DSH) is to package new features as harness packages and publish them. This incurs high iteration costs due to the packaging and installation process required for each small change. Additionally, models themselves cannot persist the tools they need midway through a session—temporary capabilities disappear once the session ends.

dsh-custom-tool addresses these two issues: users can write JavaScript tools in the settings interface using the Monaco editor, while the model can dynamically add and remove tools via custom_tool_create / custom_tool_remove / custom_tools_list. Tools are persisted, hot-registered, and become immediately visible in the next system prompt.

What This Is

  • Plugin Name: dsh-custom-tool
  • Maintainer: omdsh-dev
  • Category: admin-security
  • GitHub Stars: 24
  • License: MIT
  • Current Version: v0.1.2

One-line positioning: Create and manage sandboxed JavaScript tools within the DSH settings UI, equipped with a Monaco editor and model-driven tool lifecycle management.

Core Features

Settings Interface

The settings page adds a Custom Tool section (with a dedicated navigation icon), supporting listing, creating, editing, enabling/disabling, and deleting tools. Tools created by the model and those scoped to the workspace are marked accordingly. Interface strings follow the harness language preference (Chinese/English) for switching.

Monaco Editor

Utilizes the VS Code engine and TypeScript language service: args auto-completes types based on the parameter schema, while env and sandbox global variables have declarations, with real-time completions and diagnostics. The editor and TS worker are bundled inline, resulting in a single-file client bundle.

Persistence and Hot Registration

Tools are stored in the custom-tools settings namespace (with schema defaults, composite base classes, and user documentation—following standard settings layering). Edits take effect immediately, and tools are restored after a restart. Enabled tools are registered to ctx.tools upon settings write commitment; they are immediately unregistered when disabled or deleted. The harness automatically assembles tool schemas into the system prompt.

Model Self-Management

Tool Purpose
custom_tool_create Upsert a tool by name
custom_tools_list List tools
custom_tool_remove Delete a tool

All three share the same validation gates with the UI. Tools created by the model are marked with source: model; those created by the user are marked with source: user, and the model cannot delete the latter.

Creating a tool with location: 'global' requires explicit user approval (via the harness approval popup); tools with location: 'workspace' can be created autonomously.

Execution Scopes and Permission Boundaries

Each tool declares one of two execution scopes:

global (default) workspace
Use Case Pure computation, external data, workflows Repetitive file tasks within the session workspace
fetch (network) Based on allowNetwork configuration Based on allowNetwork configuration
console, timers, TextEncoder, URL, etc. Yes Yes
fs capabilities No readFile / writeFile / list, limited to the session workspace root directory
require / import / process Never Never

Path restrictions for workspace scope:

  • The root directory is the session workspace directory (the cwd of the agent that initiated it), resolved at invocation time.
  • Relative paths are resolved from the root; absolute paths cannot escape the root.
  • If no initiator context is available, it returns no workspace root instead of running without boundaries.
  • Restrictions are lexical-level (resolve + prefix check); symlinks within the workspace may still point outside—the workspace scope is for trusted code, not a fully isolated sandbox against malicious hosts.

Storage Locations

location Storage Location Visibility
global Shared settings namespace All workspaces, until deleted
workspace <dsh home>/workspace-tools/, keyed by the canonical workspace root Only sessions within that workspace

The two dimensions can be freely combined: for example, a tool with location: global and scope: workspace will have its fs operations act on the caller’s workspace when invoked in any workspace.

Sandboxed Execution

Each invocation runs in an isolated worker thread within a node:vm realm, equipped with explicit allowlists, Node Permission Model, and strict budgets. Workers do not inherit environment variables, have no file system access beyond configuration scope, and no subprocess capabilities.

Execution budgets (applicable to both scopes):

  • One worker thread per invocation, terminated upon timeout, abort, or completion.
  • Wall-clock deadline (timeoutMs), heap limit (memoryLimitMb), result text limit (maxResultChars), code size limit (maxCodeBytes), and stored tool count limit (maxTools).

Installation and Enablement

dsh plugin --profile web add https://github.com/omdsh-dev/dsh-custom-tool/archive/refs/tags/v0.1.2.tar.gz
dsh web   # restart the server to pick the plugin up

The package declares dsh.bundle.patch (for mounting host plugins) and dsh.client (providing browser-side code at /plugins/dsh-custom-tool/client.js). The lib/ directory is committed, so installing via GitHub tarball requires no build steps.

Harness Requirement: The settings namespace must be exposed to the web configuration client via the WEB_SETTINGS_NAMESPACES allowlist (the string 'custom-tools' must be included in packages/host/apiproxy/src/api-proxy.ts; this was added in upstream harness commit d6ea05b5). If missing, the UI may render, but saves will be silently rejected (settings-not-exposed).

Typical Usage

Tool Code Contract

The code field is an async function body: async (args, env) => value.

// args is automatically typed based on the JSON Schema you declare for parameters
const url = `https://api.example.com/weather?city=${encodeURIComponent(args.city)}`
const response = await fetch(url)
if (!response.ok) throw new Error(`upstream returned ${response.status}`)
return await response.json()

Conventions:

  • Return a JSON value (string, number, boolean, null, array, or plain object); undefined or non-JSON values will cause invocation failure.
  • Parameters: Object root JSON Schema, supporting a harness subset (type, properties, required, items, enum, const, oneOf, additionalProperties, description, title, default, examples).
  • Global variables: fetch (disabled when allowNetwork: false), console, TextEncoder/TextDecoder, URL/URLSearchParams, atob/btoa, structuredClone, AbortController, setTimeout/setInterval and their clear counterparts. env is { tool, scope }; the workspace scope additionally provides fs.

Configuration Options

Adjust under the dsh-custom-tool entry in cordis.yml:

Field Default Value Meaning
timeoutMs 30000 Wall-clock budget per invocation
memoryLimitMb 128 Worker old-space heap limit per invocation
maxResultChars 16000 Result text rendering limit
maxCodeBytes 65536 Tool code UTF-8 byte limit
maxTools 100 Stored tool count limit
allowNetwork true Whether the tool code can invoke fetch or use network APIs

Use Cases and Considerations

Who This Is For

  • Developers who need to quickly extend agent capabilities in DSH without packaging the harness for every change.
  • Scenarios where models need to create and persist tools on-demand during a session (e.g., repetitive data processing, file operation workflows).
  • Deployment environments that focus on admin-security and require clear permission boundaries.

Important Notes

  1. The plugin runs with the current dsh process permissions; review the source code and MIT license before installation.
  2. The fs restrictions in the workspace scope are lexical-level and do not prevent symlink escapes; only place trusted code in workspace tools.
  3. Models require user approval to create global-location tools; user-created tools can only be deleted by the user in the settings UI.
  4. Default allowNetwork: true; if the environment prohibits tools from accessing the external network, disable it in the configuration.
  5. Node engine requirement: ^22.19 || >=24.

Conclusion

dsh-custom-tool reduces “extending the agent” from packaging and publishing to a settings form: write tools with the Monaco editor, execute in a sandboxed worker, and let the model self-manage additions and removals via API. For developers needing to flexibly customize toolchains in DSH, this is one of the more comprehensive solutions in the admin-security category.

  • Catalog Page: https://www.skillhub.cn/plugins/omdsh-dev/dsh-custom-tool
  • GitHub: https://github.com/omdsh-dev/dsh-custom-tool