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
cwdof 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 rootinstead 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);
undefinedor 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 whenallowNetwork: false),console,TextEncoder/TextDecoder,URL/URLSearchParams,atob/btoa,structuredClone,AbortController,setTimeout/setIntervaland their clear counterparts.envis{ tool, scope }; the workspace scope additionally providesfs.
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
- The plugin runs with the current dsh process permissions; review the source code and MIT license before installation.
- The
fsrestrictions in theworkspacescope are lexical-level and do not prevent symlink escapes; only place trusted code in workspace tools. - Models require user approval to create global-location tools; user-created tools can only be deleted by the user in the settings UI.
- Default
allowNetwork: true; if the environment prohibits tools from accessing the external network, disable it in the configuration. - 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