DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

imroc /

imroc/dsh-project-prompt

Verified

Private, per-project prompt rules for DeepSeek Harness — matched by git remote/repo/path, worktree-aware, never committed to the repo

★ 2 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@65863df0

dsh-project-prompt

English | 中文

Private, per-project prompt rules for DeepSeek Harness (DSH).

Some agent instructions belong to your machine, not to the repository: environment-specific E2E procedures, internal-only endpoints, personal workflow preferences. AGENTS.md is committed and shared, so it is the wrong place for them. This plugin keeps such text in $DSH_HOME, never in the repo, and injects it into every session whose workspace matches a rule — including every subagent and every git worktree of the repository.

flowchart LR
    subgraph repo["git repository (any clone / worktree / subdir)"]
        wt1["main checkout"]
        wt2["linked worktree A"]
        wt3["worktree B"]
    end
    cfg["$DSH_HOME/cordis.patch.yml\nrules (machine-local, private)"]
    plugin["dsh-project-prompt\nagent/session-start listener"]
    sp["session system prompt\n(or first injected message)"]
    cfg --> plugin
    wt1 & wt2 & wt3 -->|match by remote / repo / path| plugin
    plugin -->|section / inject| sp

Features

  • Three matchers — match sessions by git remote URL (any clone, anywhere on disk), by local main-repo path, or by plain cwd prefix. Keys within a rule are OR-combined.
  • Worktree-aware — a linked worktree is traced back to its main repository through the .git file's gitdir: pointer, so a rule written once covers worktrees created later, and their subdirectories.
  • Two injection modes — section (a stable system-prompt segment, KV-cache friendly, supports {{cwd}}/{{model}}) and inject (a first context message, no template interpolation — use it when the text contains literal {{...}} braces, e.g. Helm or Go templates).
  • Covers subagents — subagents inherit the session cwd, so delegated work follows the same rules.
  • Fails loudly at load time — malformed rules (missing text, unknown {{var}} in section mode) throw when the plugin loads, not on every request.
  • Zero dependencies — a single ESM file importing only Node builtins; no build step, nothing to compile.

Requirements

  • DeepSeek Harness ≥ 0.1.1-rc.2 (uses the agent/session-start event, systemPrompt.section, and agent.inject extension points).
  • Node.js ≥ 18 (DSH itself currently requires ≥ 22).

Install

Install into a profile with DSH's plugin command:

dsh plugin --profile web add dsh-project-prompt
# or install straight from the GitHub repository:
dsh plugin --profile web add github:imroc/dsh-project-prompt

Restart DSH afterwards — bundles are composed at startup.

Uninstall:

dsh plugin --profile web remove dsh-project-prompt

Configure

Rules live in $DSH_HOME/cordis.patch.yml (~/.dsh/cordis.patch.yml by default) — the machine-local layer that applies to every profile on the machine. Override the row the bundle installed:

- id: project-prompt
  config:
    rules:
      # Matches this repository wherever it is cloned, and in all worktrees.
      - remote: github.com/my-org/my-project
        text: |
          ## E2E testing for this project (environment-specific, private)

          1. Test entry point: http://e2e.internal.example.net (internal only)
          2. Run `make e2e-prepare` before the first E2E run.
          3. On failures, check ... first.

      # Matches by local main-repo path; the rule text contains literal
      # {{...}} braces, so it must use inject mode.
      - repo: /home/me/dev/another-project
        mode: inject
        text: |
          Render values like {{ .Values.replicas }} are literal here.

      # Matches any session started under a plain directory prefix.
      - path: /home/me/dev
        text: |
          ...

The file is watched for changes — saving it hot-reloads the plugin row (take effect for sessions started afterwards).

Rule reference

Key Type Default Description
remote string — Git remote URL (origin) to match. Compared after normalization: scheme, user@, scp-style : separator, trailing .git and slashes, and case are ignored. git@github.com:u/r.git ≡ https://github.com/u/r. A bare host/org/repo suffix also matches.
repo string — Local absolute path of the git main repository. Any linked worktree and any subdirectory of it matches (worktrees are traced back via the .git gitdir pointer).
path string — Cwd prefix: the session workspace equals this directory or lives underneath it.
text string required The prompt text to inject.
mode section | inject section Injection mode, see below.
sectionName string project-prompt (auto-increments when several section rules match one session) System-prompt section name.
order number 50 System-prompt section order (DSH conventions: 0 persona, 100–199 tool guidance).

A rule needs at least one of remote / repo / path; several matching rules all apply.

Injection modes

section (default) inject
Lands as System-prompt segment on the agent-scoped systemPrompt service First user-side context message (same path AGENTS.md content takes)
Visible Every request of the session Every request of the session
Template interpolation Yes — {{cwd}} and {{model}} resolve; any other complete {{...}} group throws No — braces are literal
Best for Stable instructions; KV-cache-friendly Text containing literal {{...}} (Helm/Go templates, Terraform, etc.)

The plugin validates section text at load time: an unknown {{var}} fails the load with a message telling you to switch that rule to mode: inject.

How it works

  1. DSH emits agent/session-start synchronously before the first model request of every new session (fresh, resumed, after clear/compact — each publish mints a new agent scope).
  2. The plugin reads agent.session.header.cwd and tests each rule; git repository identity is resolved by walking up from the cwd to .git (a file means a linked worktree, whose gitdir: pointer leads back to the main repository root and its remote URLs).
  3. On match, the rule's text is registered on agent.ctx — the agent-scoped context — so it applies to that agent only and is discarded with it.
  4. Every model request of that session re-assembles the system prompt (or re-reads the injected message), so the rule text is present throughout.

"Model-visible means logged": injected sections appear in the request headers recorded in the session log ($DSH_HOME/sessions/…), which is also how you verify a rule landed.

Verify an installation

  1. Check the row composed: dsh --profile web --dump-config | grep -A3 project-prompt.
  2. Start a session in a matched directory and ask the model a question the rule text should influence.
  3. Or inspect the recorded prompt: the session's session.jsonl.zstd contains the assembled system prompt with your section.

Limitations

  • Matching is identity-by-path or by-remote, not by content: two different clones of the same remote both match a remote rule (that is usually the point).
  • Submodule directories (.git pointing into .git/modules/…) are not traced; use a path rule for them.
  • Rules are static configuration — this plugin intentionally does not read files from inside the repository (that would reintroduce shared state). For workspace-local files, see DSH's built-in AGENTS.md/CLAUDE.md loading.

Development

git clone github:imroc/dsh-project-prompt && cd dsh-project-prompt
npm test          # node --test; git fixtures are created in a temp dir
node --check index.js

The plugin is a single dependency-free ESM file; the committed source is the shipped artifact (no build, no prepare script — which is also why git installs need no pnpm allowBuilds entry). See AGENTS.md for the constraints that keep it that way.

License

MIT © roc

—/ 5

No ratings yet

Verified DSH bundle

Commit 65863df0fb32

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout