DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins

dsh-keyword-injector

Keyword Injector

Context injection + behavioural guards for DSH: keyword triggers on user input or agent activity, tool-window guards, and agent-manageable trigger tools. POWERFUL AND DANGEROUS: lets AI agents shape each other's behaviour at any step — read the warnings b

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add dsh-keyword-injector@0.6.0
READMECompatibilityVersions

Compatibility and provenance

Keyword Injector is published as dsh-keyword-injector and currently resolves to version 0.6.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
npm
Registry updated
11/4/2026

Versions

0.6.0stable
10/3/2026
0.5.2stable
9/27/2026
0.4.5stable
9/24/2026
Show 4 more versionsCollapse versions
0.4.3stable
9/24/2026
0.4.2stable
9/24/2026
0.4.1stable
9/23/2026
0.2.0-beta.1beta
9/3/2026

Related plugins

Loading related plugins…

Latest
0.6.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
269.1 kB
Files
16
Surface
web
License
MIT
Source
npm
Weekly downloads
27
View source ↗Project homepage ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in agents-orchestration.

Headless@deepseek-ai/dsh-headlessThe dsh one-shot bundle: a direct core Agent/Session runner over dsh-base with no Host, HTTP, or browser layerExperimental Ralph Bundle@deepseek-ai/dsh-experimental-ralph-bundleRun explicitly requested repeated work with fresh agents.Subagent Codex@deepseek-ai/dsh-subagent-codexOne-shot Codex subagent provider over the official app-server protocolSubagent Claude Code@deepseek-ai/dsh-subagent-claude-codeOne-shot Claude Code subagent provider over the official Agent SDK

README

dsh-keyword-injector

Keyword-triggered context injection for the DeepSeek Harness (DSH).

Define keywords once; the plugin watches a session and, when a trigger fires, injects your payload into the conversation as a Context injection message — the same delivery surface memos-local-memory uses. The reminder renders in the Web GUI as a collapsed Context injection · dsh-keyword-injector row and reaches the model with its next request. The agent's flow is never interrupted: no turns are started, nothing is steered, no extra model calls are made for the delivery itself.

user:  "please deploy to staging now"
       └─ Context injection · dsh-keyword-injector   ← collapsed row, model sees it too
          [KEYWORD-INJECTOR REMINDER] …rules you configured… [END KEYWORD-INJECTOR REMINDER]
agent: (answers with your rules applied)

⚠️ DANGER — read this before you use it

This plugin lets AI agents shape the behaviour of other AI agents — at any moment, in any session, persistently across restarts. Trigger rules are global by default (all-sessions), survive daemon restarts, and are delivered to the model with a "configured by the user" trust framing. One injected payload silently re-programs every session it reaches. If you would not hand a stranger your system prompt, do not hand them this plugin's write tools.

This plugin injects instructions into your agent's context automatically. That is its job — and exactly why it must be treated like loaded weaponry. Misconfigured, it can be turned against you.

0. Agent-to-agent coordination is the sharpest edge. The keyword_injector_* tools are registered for every agent session in the profile. Any agent — an executor on a task card, a subagent, an agent processing untrusted input — can create, edit, or delete triggers, and those changes apply to all other agents, including orchestrators and supervisors. Two agents can thus establish a private instruction channel: agent A plants a trigger keyed to agent B's vocabulary, and B obeys A's payload believing it came from you. A manipulated agent can also delete your guardrails while telling you everything is fine. In multi-agent setups, audit the trigger list (keyword_injector_list_triggers, or the Keywords panel) after any session that touched untrusted content, and treat unexpected triggers as incidents.

1. Agent-source triggers match EVERYTHING your agent reads. The agent source scans reasoning, tool calls, and tool results. Tool results include web pages, file contents, code comments, task cards, and messages from other agents. Untrusted content can deliberately contain your keyword and fire your trigger — an attacker who knows your keyword can inject your payload at a moment of their choosing. If any session with an agent-source trigger fetches external content, assume the trigger is remotely fireable by strangers.

2. Triggers are a covert instruction channel. Injected reminders render as a collapsed row and carry implicit "configured by the user" trust. Anyone who can edit your trigger list — via the settings file, the GUI, or the agent tools — can silently shape every session's behavior. Treat trigger configuration with the same seriousness as your system prompt.

3. The agent can edit its own triggers. This plugin registers write tools (create/update/delete) for the model. A manipulated agent can be talked into editing its own triggers — including removing your guardrails. In untrusted workflows, audit the trigger list afterwards, or don't expose the tools.

4. Broad matches = context flooding and cost amplification. contains: "the" or regex: .* on the agent source fires every turn, stuffing your payload into every request — token spend, degraded reasoning, pushed-out context. Keep keywords narrow; check the live-test panel; prefer exact for common words.

5. Payloads inherit user trust. Whatever you write in a payload, the model is told the user configured it. Never put secrets in payloads. Never configure payloads on behalf of someone you don't fully trust. A steer-skill trigger auto-loads and runs skill instructions — that's code execution adjacent.

Hard rules we recommend:

  • Only edit triggers from a trusted seat (your machine, your settings file).
  • Prefer user-source triggers; use agent-source deliberately, with narrow keywords, on sessions that handle trusted input.
  • Never use keywords likely to appear in code, data, or fetched content.
  • Audit ~/.dsh/settings.yaml (namespace dsh-keyword-injector) after letting agents near untrusted content.
  • Keep payloads short, factual, and secret-free.

The plugin itself sends no network traffic and stores no secrets — but it automates instruction delivery. The safety of that automation is entirely in how you scope your triggers.

Why two trigger sources

Most injectors only watch user input. Real prompts often don't contain the word that matters — the agent's own reasoning does:

User: "resolve the issue" → agent thinks "I need to triage this first" → *triage rules arrive on their own.

SourceWatchesFires when
user (default)What the user typesThe triggering message lands in the session inbox — the reminder joins that message's step (reminder first, one model request)
agentThe agent's own reasoning and actions (assistant messages incl. thinking, tool calls + arguments, tool results)The agent's step boundary — e.g. it thinks "I need to triage this" mid-task and the rules are injected for its next step of the same turn

The matcher enforces source isolation (user triggers never fire on agent text and vice versa), and agent-source triggers fire once per turn per trigger — the agent echoing the keyword after reading the rules never re-triggers.

Real use cases

  1. Standing rules on demand — trigger Follow the rules (user source, static-text) injects your personal operating law: keep the session to-do list updated, use SEQUENTIAL THINKING for long problems, escalate to the advisor when stuck, never work around broken system tools, clean up leftover scripts. Three words typed; the full rulebook arrives as context.
  2. Skill steering — trigger context manager (user source, steer-skill) injects "load the context-manager skill" — the agent picks up the whole methodology without pasted instructions.
  3. Triage rules the agent asks for itself — the agent-source example above: user says "resolve the issue", the agent's own reasoning matches triage, rules arrive at its next step.
  4. Deploy guardrail — trigger deploy to staging rides a smoke-test reminder along with every matching request, in every session.

Trigger model

FieldValuesNotes
keywordany text (≤ 200 chars)what to match
matchTypeexact / contains / regexregex validated at save time; ReDoS-shaped patterns (e.g. (a+)+) rejected up front; runtime matcher has a sample cap + budget as a second guard; case-sensitivity toggle
modestatic-text / steer-skillinject a verbatim payload, or an instruction to load a named skill (validated against the live skills catalog at save time)
sourceuser / agentsee above
scopeall-sessions / this-sessionthis-session only settable from inside a session
enabledon/offtoggle straight from the table

Payloads are wrapped in fixed [KEYWORD-INJECTOR REMINDER] … [END KEYWORD-INJECTOR REMINDER] delimiters and sanitised (invisible control bytes stripped), so user-supplied payload text can never pose as system instructions — the model always sees it as data inside a marked block.

UI

Two surfaces, same manager:

  1. Sidebar → Keywords — a main panel alongside Task Board / SSH / Skill Center.
  2. Settings → Keyword Injector.

Both provide: trigger table (enabled toggle, keyword, match type, mode, source, payload preview, scope, edit/delete), filter box, and an edit modal with a live test panel — a host-side dry run using the exact runtime matcher, so the panel is always honest about what will fire.

Agent tools

The model can manage triggers itself (useful for self-configuring agents — and dangerous; see warning 0 above):

  • keyword_injector_list_triggers
  • keyword_injector_create_trigger (skill targets validated)
  • keyword_injector_update_trigger
  • keyword_injector_delete_trigger
  • keyword_injector_test_trigger

There is no allowlist, approval step, or per-session restriction on these tools: any agent in the profile can rewrite the rulebook of every other agent. If you only want you to configure triggers, audit the list frequently and treat unexpected triggers as incidents.

Guards (behavioural triggers)

Besides keyword triggers, the plugin ships guard triggers — conditions over session behaviour rather than message text. Guards carry no keyword; they are evaluated at each agent step and fire (subject to a cooldown, in tool-call steps) by injecting their payload as a binding reminder.

GuardConditionFires when
todo-compliance{ window: N }N tool calls passed with no todo_write / taskboard_* in the window — nudges the agent to maintain its in-session task list
orphan-process—a background job/agent exists with no reminder/schedule covering it — nudges the agent to set a reminder before answering
tool-window (v0.4.0){ window: N, noneOf?: [tool globs], anyOf?: [tool globs], cooldownSteps }over the LAST N tool calls: no call matched any noneOf glob, and (when anyOf is set) none of those appeared either

tool-window examples: {window: 8, noneOf: ["mcp__*sequentialthinking*"]} = "reason step-by-step if you haven't for 8 calls"; {window: 15, anyOf: ["skill"]} = "load the matching skill if you haven't recently". Any "do X whenever the agent hasn't done Y recently" rule becomes a one-line config. Guards keep a bounded 64-name ring buffer of recent tool calls per session; globs are cached, not recompiled per step.

Guard limits (by design): the engine sees tool names only — not tool arguments, not whether a loaded skill is semantically right for the job, not wall-clock time. Those need an LLM judge or a scheduler; deliberate scope cut.

Install

On npm as dsh-keyword-injector (beta channel):

dsh plugin --profile web add dsh-keyword-injector@beta

or with pnpm directly:

cd ~/.dsh/profiles/web
pnpm add dsh-keyword-injector@beta
# then add "dsh-keyword-injector" to dsh.profile.bundles in package.json

Prefer the source? Install straight from GitHub:

dsh plugin --profile web add github:markelayan/dsh-keyword-injector

Local-development (link:) installs: clone anywhere, run npm install (pulls schemastery), then dsh plugin --profile web add link:<path>. Note for link: users: DSH resolves a plugin's imports from its realpath, so the cloned copy needs its own node_modules (the npm install above provides it).

Restart dsh web and hard-refresh the browser after installing.

Requires a DSH core from the 0.1.1-rc line (tested on 0.1.1-rc.2 and 0.1.6-alpha.2) — see Compatibility for the full matrix.

Architecture

lib/
├── index.js            host half — events, persistence, HTTP routes, agent tools
├── client.js           client half SOURCE (sidebar entry, panel, settings page)
├── client.bundled.js   SHIPPED client — esbuild bundle in ModuleLoader format
├── schema.js           trigger validation (all trust boundaries)
├── matcher.js          runtime matching (regex cache, budgets)
└── reminder.js         reminder text formatting + sanitisation
  • Persistence: settings namespace dsh-keyword-injector (ends up in ~/.dsh/settings.yaml), registered on boot with a permissive schemastery schema; every read passes strict validateDocument, so a corrupted store degrades to an empty trigger list — never a crash.
  • Client ↔ host: bundle clients have no host.call bridge, so the UI talks to plain HTTP routes on the host: POST /api/dsh-keyword-injector/{list,create,update,delete,test,skills}.
  • Delivery: reminders are durable, plugin-sourced user/message events inserted through the agent inbox (agent.inject() → next-step queue), so they are claimed together with the triggering message — reminder first — and render as Context injection rows. The inbox claims exactly one next-turn message per turn, so the plugin never prepends to that queue (that would strand user messages).
  • Events used: agent/inbox/inserted (user source) and agent/pre-step (agent-source scanner).

Rebuilding the client

The browser loader requires a single self-contained window.__ModuleLoader__.load file, so the client ships bundled. After editing lib/client.js:

npm install                      # once
npx esbuild lib/client.js --bundle --format=cjs \
  --external:react --external:react-dom --external:react-dom/client \
  --outfile=/tmp/kwi.cjs
# re-wrap with the ModuleLoader factory — see the exact steps in the header
# comment of lib/client.bundled.js

Then restart dsh web and hard-refresh.

Security & privacy

  • No network calls. The client fetches same-origin DSH routes only; the host touches local files (the DSH settings store) and in-process APIs. No telemetry, no analytics, no outbound requests, ever.
  • No secrets. The plugin stores no credentials and reads none.
  • Injection-hardened. Reminder payloads are fenced in constant delimiters, sanitised, and length-capped; the keyword itself is sanitised before embedding. The model is told, in-band, that the block is configured by the user — not instructions from the payload author.
  • ReDoS guards. Regex triggers are shape-checked at save time and sample-capped + budgeted at match time.
  • Self-matching impossible. The scanner reads only genuine user input or assistant/tool events — never the plugin's own injections — and fires at most once per message (user source) or per turn (agent source).

Compatibility

RequirementDetails
DSH core0.1.1-rc+ required; tested on 0.1.1-rc.2 and 0.1.6-alpha.1/alpha.2. Uses tools/pre-execute hooks, agent.inject() inbox delivery, settings namespaces, web bundle loading, and ctx.webServer HTTP routes — stable across those versions. The pre-0.1.6 agent.session.event hook is NOT used (removed in dsh 0.1.6).
Install shapeStandard DSH bundle plugin: declares dsh.bundle.patch: ./cordis.patch.yml and mounts its own insert row into the profile — never add a second - insert: for this id in the profile's main cordis.patch.yml (duplicate insert ids crash dsh web on boot).
RuntimeNode ≥ 18 (ESM). No native deps; the only runtime dep is schemastery.
ClientWeb GUI bundle (esbuild → ModuleLoader format). Sidebar Keywords panel + Settings page; hard-refresh the browser after install/upgrade.
StorageTrigger list lives in the dsh-keyword-injector namespace of ~/.dsh/settings.yaml — plain YAML, survives restarts, included in normal settings backups.
NetworkNone. No outbound calls, no telemetry. All matching is local.
UpgradesUpdate the package in ~/.dsh/profiles/web, then restart dsh web (user-only) — bundle source changes never hot-reload; only the patch file does. Trigger data is untouched by upgrades.

Changelog

See CHANGELOG.md. MIT license — see LICENSE.