返回目录
Agent 与会话 插件

dsh-precedent

dshplugin-me/dsh-precedent

Evidence-backed working memory for DeepSeek Harness: a cited ledger of what already worked in this workspace, built from the session log you already have. No index, no model, no capture step.

Stars
0
Forks
0
Issues
0
更新
今天

PROJECT TOPICS

项目标签

PROJECT README

README

dsh-precedent

Your agent forgets. Your log doesn't.

English | 简体中文

Version License Node Platform Index Indexed on dshplugin.me

dsh-precedent turns session logs into an evidence-backed command ledger

A DeepSeek Harness plugin that reads the session log DSH already writes and hands the agent a short, cited ledger of what has actually worked in this workspace — the commands that succeed, the ones that reliably fail, and the variant that fixed them.

No capture step. No index to build. No model to download. It works on sessions recorded before you installed it.

The problem

Every new session, your agent starts from zero in a codebase it has already worked in for weeks.

It runs npm test in a Bun repo. Again. It re-greps the same three files to find where routes live. Again. It hits the same build error you already walked it past on Tuesday, and you type the same correction you have now typed four times.

None of this is a memory problem in the usual sense. The information was never lost — DSH appends every message, tool call, tool result, and failure to a durable log on disk. What's missing is anything that reads it back.

Two things quietly widen the gap:

  1. Compaction rewrites the model's context, not the log. When a long session compacts, the model loses the detail; the raw events stay on disk, marked shadowed. The agent cannot see them anymore. The file still can.
  2. Out of the box, DSH's own content search is off. The shipped web profile mounts session-query-sqlite with openAt: never, so full-text search calls fail with SESSION_QUERY_SEARCH_DISABLED and the sidebar matches session titles only. Months of transcripts sit on disk, unsearchable, by default.

What it does

Reads — walks this workspace's sessions through ctx.sessionQuery exact reads, pairs every tool/call with its tool/result, and keeps the outcome.

Distills — aggregates that into a ledger: command → runs, failures, last success, and the repair (the variant that succeeded right after a failure in the same session). This step is arithmetic, not summarization. No LLM in the extraction path, so it cannot hallucinate a precedent.

Serves — injects the top entries as one compact, prefix-stable system-prompt section, and prints the full ledger on /precedent.

Every line carries a citation back to the exact session:seq that produced it, so you can always ask "says who?" and get an answer.

Example

Launch as usual:

$ dsh --profile web

The agent's system prompt gains one section — this is the renderer's real output, with commands that never work sorted above commands that always do:

## Precedent for /Users/thor/Github/acme-api

Observed in this workspace (12 sessions, 2026-06-02 → 2026-08-15). Each line is counted from the session
log, not summarized — treat it as evidence, not instruction.

- `npm test`            4 runs, 4 failed     — repaired by `bun test`  [s/7f3a:212]
- `docker compose up`   3 runs, 3 failed     — no known repair  [s/91bc:88]
- `bun test`            22 runs, 0 failed    — last ok 2026-08-15
- `bun run build`       9 runs, 0 failed     — last ok 2026-08-14

/precedent prints the same ledger uncapped, on demand.

Install

dsh plugin --profile web add 'github:dshplugin-me/dsh-precedent#v0.1.0'

No global dsh on PATH? Use npx -y @deepseek-ai/dsh plugin --profile web add …. Running dsh from a source checkout? Use pnpm dsh plugin … from the checkout root. Replace web with whichever profile you actually launch.

Pinning the version is deliberate: an unpinned git install resolves to whatever main points at right now, so a later push silently changes what is mounted in your profile. A commit sha (#<sha>) works too, and not even a maintainer can move that.

Pure JavaScript, no build step, no native module, no allowBuilds prompt.

Verify before launching:

dsh --profile web --dump-config   # look for the "# == dsh-precedent" layer
dsh --profile web

Remove with dsh plugin --profile web remove dsh-precedent, which takes the patch layer and the dependency together.

How it works

flowchart LR
  log[("Session log<br/>~/.dsh · JSONL")]
  sq["ctx.sessionQuery<br/>exact reads"]
  led["Ledger<br/>pure aggregation"]
  sp["ctx.systemPrompt<br/>.section()"]
  cmd["ctx.commands<br/>/precedent"]
  model(["Model"])
  you(["You"])

  log --> sq --> led
  led --> sp --> model
  led --> cmd --> you

The seams it uses

Harness surface Used for Notes
ctx.sessionQuery.filterSessions Select this workspace's sessions Filtered by cwd, the same conservative scope DSH's own cross-session tool uses
ctx.sessionQuery.readSession Read one session's raw event log Replay-validated; an unreadable log is skipped, never fatal
ctx.systemPrompt.section Inject the ledger One global section at order 150, rendering with tool guidance
agent/pre-step Warm the ledger before the first request Awaited waterfall — the only hook that runs before prompt assembly
ctx.commands.register /precedent Human surface, never sent to the model

Pairing happens inside readSession's event array: a tool/call with name: 'bash' is matched to its tool/result by callId, and the result's error field (or the result block's isError) decides the outcome.

Why there is no index

ctx.sessionQuery splits into two halves. Full-text search (searchSessions, searchEvents) needs a provider and is off in the shipped profile. Everything else — listSessions, filterSessions, readSession, listEvents, readEvent, lineage and event traces — is backend-independent concrete behavior that works whether or not a search backend is open.

dsh-precedent uses only the second half. That is the whole reason it needs no index, no embedding model, and no warm-up: it reads the log the way the harness itself reads it for resume and export.

The cost is honest and bounded: a ledger build is a linear pass over this workspace's logs, done once per workspace per process, capped at maxSessions, and it stops blocking the first step after buildTimeoutMs whether or not it has finished.

Why the extraction has no LLM in it

A command either exited non-zero or it didn't. tool/result.error records which. Pairing it to its tool/call by callId and counting is arithmetic — deterministic, reproducible, and impossible to hallucinate.

The one place judgment is genuinely required is deciding whether a user correction is a durable convention ("use bun, never npm") or one-off steering ("no, the other file"). That is why v0.1.0 ships no correction mining at all: the command ledger stands on arithmetic alone.

Configuration

- id: precedent
  name: dsh-precedent
  config:
    maxEntries: 40        # ledger lines injected per session
    minRuns: 2            # ignore commands seen only once
    lookbackDays: 90      # ignore sessions older than this
    maxSessions: 200      # upper bound on logs read in one build
    buildTimeoutMs: 5000  # stop blocking the first step after this
Key Default Meaning
maxEntries 40 Hard cap on injected ledger lines, so the section stays a fixed, small token cost. /precedent is never capped
minRuns 2 A command seen once is an anecdote, not a precedent
lookbackDays 90 A convention from six months ago may no longer be true
maxSessions 200 Newest sessions first; a workspace with years of history stays cheap to read
buildTimeoutMs 5000 A slow build releases the first step and lands on a later one instead

Scope is not configurable: sessions are matched on exact cwd string equality, the same conservative rule DSH's own cross-session authorization uses — a symlinked path is a different workspace.

Commands

Command What it does
/precedent Print the full ledger with citations, uncapped
/precedent rebuild Discard the cached ledger and re-scan

Everything the plugin injects is visible on demand before you trust it. A memory you cannot audit is a memory you cannot trust.

What it is not

  • Not a search tool. It does not answer "what did we discuss in June". It answers "what already works here", before you ask. If you want verbatim transcript retrieval, use a recall plugin — they compose fine.
  • Not a note-taker. Nothing asks you to write memories. There is no capture step to forget to run.
  • Not context stuffing. The injected section is capped and prefix-stable, so it costs a fixed small number of tokens and does not invalidate the KV cache between turns.
  • Not a replacement for AGENTS.md. Hand-written intent still wins. Precedent covers the part nobody keeps up to date: what actually happened.
  • Not cross-workspace. By design. See below.

Privacy and safety

  • Everything stays local. The plugin reads the session log through ctx.sessionQuery and holds the ledger in memory. No files written, no network calls, no telemetry, no upload path in the code.
  • Workspace-scoped. Sessions are selected by exact cwd equality, mirroring the boundary DSH's own tool-session-query enforces. Another project's log is not read, even on the same machine.
  • Secrets are dropped, not stored. Command strings routinely contain tokens (curl -H "Authorization: …", DEPLOY_KEY=… ./ship). Every command is matched against secret-shaped patterns and the whole entry is discarded — not masked, discarded — before it reaches the ledger.
  • Auditable by construction. /precedent prints exactly what gets injected, with a session:seq citation on every line that came from a failure.

How it compares

Verbatim search plugins Note-taking memory plugins AGENTS.md editors dsh-precedent
Works on pre-install history Yes, after indexing No — starts empty No Yes, immediately
Needs an index or model Usually No No No
Acts before you ask No Sometimes Yes Yes
Sources are citable Yes Rarely N/A Always
Can hallucinate an entry No Yes N/A Not in the ledger path
Answers "what did we discuss" Yes Partly No No

Different jobs. A recall plugin is a search box; precedent is a track record. Running both is reasonable.

Roadmap

  • [x] v0.1.0 — command ledger, system-prompt injection, /precedent
  • [ ] v0.2.0tools/pre-execute advisory on a known-bad call, intercept: warn | ask | deny via ctx.tools.guard
  • [ ] v0.3.0 — correction mining with citations, /precedent why, /precedent pin, /precedent forget
  • [ ] v0.4.0 — incremental rebuild as the current session appends, instead of once per process
  • [ ] Later — export the ledger as an AGENTS.md draft for human review

Interfaces above are frozen against deepseek-ai/deepseek-harness@47f943859bef (read 2026-08-16). Anything that changes upstream will be noted here rather than silently adjusted.

Contributing

Issues and PRs welcome. Useful contributions, roughly in order of value:

  1. A precedent your agent should have caught and didn't. Paste the situation (no logs needed). Missed patterns are the roadmap.
  2. Extraction rules for a toolchain we get wrong. Command normalization is heuristic; every ecosystem has its own shape.
  3. Secret-shaped patterns we fail to drop. Treat these as security reports — open an issue and we will fix before discussing.

License

BSD-3-Clause.


Part of dshplugin.me · sibling project: dsh-plugin-radar

CLASSIFICATION EVIDENCE

分类依据

项目类型插件
功能分类Agent 与会话
规则置信度

系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。