{"_id":"@achasoft/dsh-memory","name":"@achasoft/dsh-memory","dist-tags":{"latest":"0.2.0"},"versions":{"0.2.0":{"name":"@achasoft/dsh-memory","version":"0.2.0","description":"Persistent, searchable, per-project memory for the DeepSeek Harness: decisions, rules, and sprint context in a queryable DuckDB file, rules enforced on every model request, with a full management UI in the Web Client","license":"MIT","type":"module","main":"lib/index.js","types":"./types/index.d.ts","exports":{".":{"types":"./types/index.d.ts","default":"./lib/index.js"},"./host":{"types":"./types/host/index.d.ts","default":"./lib/host.js"},"./tools":{"types":"./types/tools/index.d.ts","default":"./lib/tools.js"},"./embeddings-openai":{"types":"./types/providers/openai-embeddings.d.ts","default":"./lib/embeddings-openai.js"},"./client":{"default":"./lib/client.js"},"./remote":{"default":"./lib/remote.js"},"./typert":{"default":"./lib/typert.host.js"},"./cordis.patch.yml":"./cordis.patch.yml","./package.json":"./package.json"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"platform":"web","inject":["@deepseek-ai/dsh-api-remotes","@deepseek-ai/dsh-client-locale","@deepseek-ai/dsh-client-ui-conversation","@deepseek-ai/dsh-client-ui-settings","@deepseek-ai/dsh-client-ui-settings-plugins"]}},"scripts":{"build":"node scripts/build-typert.mjs && tsc -p tsconfig.build.json && tsdown","prepare":"node scripts/build-typert.mjs && tsc -p tsconfig.build.json && tsdown","typecheck":"tsc --noEmit","test":"node scripts/check-typert.mjs && vitest run","test:unit":"vitest run","check:typert":"node scripts/check-typert.mjs","regen:typert":"node scripts/regen-typert.mjs","build:typert":"node scripts/build-typert.mjs"},"peerDependencies":{"@deepseek-ai/cordis":"*","@deepseek-ai/dsh-agent":"*","@deepseek-ai/dsh-credentials":"*","@deepseek-ai/dsh-llm":"*","@deepseek-ai/dsh-session":"*","@deepseek-ai/dsh-settings":"*","@deepseek-ai/dsh-system-prompt":"*","@deepseek-ai/dsh-tools":"*","@deepseek-ai/dsh-typert-protocol":"*","@deepseek-ai/schemastery":"*"},"dependencies":{"@duckdb/node-api":"^1.5.5-r.4","zod":"^4.4.3"},"devDependencies":{"@deepseek-ai/cordis":"link:../../deepseek-harness/vendor/cordis","@deepseek-ai/dsh-agent":"link:../../deepseek-harness/packages/core/agent","@deepseek-ai/dsh-api-remotes":"link:../../deepseek-harness/packages/api/remotes","@deepseek-ai/dsh-brand":"link:../../deepseek-harness/packages/util/brand","@deepseek-ai/dsh-client-locale":"link:../../deepseek-harness/packages/client/locale","@deepseek-ai/dsh-client-runtime":"link:../../deepseek-harness/packages/client/runtime","@deepseek-ai/dsh-client-ui-conversation":"link:../../deepseek-harness/packages/client/ui-conversation","@deepseek-ai/dsh-client-ui-primitives":"link:../../deepseek-harness/packages/client/ui-primitives","@deepseek-ai/dsh-client-ui-settings":"link:../../deepseek-harness/packages/client/ui-settings","@deepseek-ai/dsh-client-ui-settings-plugins":"link:../../deepseek-harness/packages/client/ui-settings-plugins","@deepseek-ai/dsh-client-ui-slots":"link:../../deepseek-harness/packages/client/ui-slots","@deepseek-ai/dsh-credentials":"link:../../deepseek-harness/packages/credentials/credentials","@deepseek-ai/dsh-llm":"link:../../deepseek-harness/packages/llm/llm","@deepseek-ai/dsh-session":"link:../../deepseek-harness/packages/core/session","@deepseek-ai/dsh-settings":"link:../../deepseek-harness/packages/settings/settings","@deepseek-ai/dsh-system-prompt":"link:../../deepseek-harness/packages/core/system-prompt","@deepseek-ai/dsh-tools":"link:../../deepseek-harness/packages/core/tools","@deepseek-ai/dsh-typert-loader":"link:../../deepseek-harness/packages/typert/loader","@deepseek-ai/dsh-typert-protocol":"link:../../deepseek-harness/packages/typert/protocol","@deepseek-ai/schemastery":"link:../../deepseek-harness/vendor/schemastery","@types/node":"^22.20.1","@types/react":"~18.3.1","@types/react-dom":"~18.3.1","happy-dom":"^15.11.7","lightningcss":"^1.30.1","react":"^18.2.0","react-dom":"^18.2.0","tsdown":"^0.15.6","typescript":"^5.9.2","vitest":"^3.2.7"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/navid-kianfar/dsh-memory.git"},"keywords":["deepseek-harness","dsh","dsh-plugin","memory","duckdb","semantic-search","rules","agent-memory","project-memory","cordis"],"engines":{"node":"^22.19 || >=24"},"gitHead":"0b49a35e5fbb5c881f3aa8b41f042cec0a4a5578","_id":"@achasoft/dsh-memory@0.2.0","bugs":{"url":"https://github.com/navid-kianfar/dsh-memory/issues"},"homepage":"https://github.com/navid-kianfar/dsh-memory#readme","_nodeVersion":"25.2.1","_npmVersion":"11.19.1","dist":{"integrity":"sha512-5eKt+rFOEsozxVzRreAdpE5iADcsE2TsvgO6dFVyWWga249wdQfekKXZcVnEfSn1BBZSasQAd095jIaRwAsdcA==","shasum":"d4383d6be9f948786ac887637ebe724046be2bd8","tarball":"https://registry.npmjs.org/@achasoft/dsh-memory/-/dsh-memory-0.2.0.tgz","fileCount":58,"unpackedSize":1265981,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIH4BNCjSlrjF0CYXnCIB0JbM0h+L0FU30z7rLgbLDL2dAiBvVFpXaz6b9/W2a9QZnawSS3WXFIO+VHFIw3NAMmB9Mw=="}]},"_npmUser":{"name":"navid.kianfar","email":"navid.kianfar@outlook.com"},"directories":{},"maintainers":[{"name":"navid.kianfar","email":"navid.kianfar@outlook.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-memory_0.2.0_1788119144651_0.2113541734646851"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-30T19:45:44.480Z","0.2.0":"2026-08-30T19:45:44.798Z","modified":"2026-08-30T19:45:45.024Z"},"maintainers":[{"name":"navid.kianfar","email":"navid.kianfar@outlook.com"}],"description":"Persistent, searchable, per-project memory for the DeepSeek Harness: decisions, rules, and sprint context in a queryable DuckDB file, rules enforced on every model request, with a full management UI in the Web Client","homepage":"https://github.com/navid-kianfar/dsh-memory#readme","keywords":["deepseek-harness","dsh","dsh-plugin","memory","duckdb","semantic-search","rules","agent-memory","project-memory","cordis"],"repository":{"type":"git","url":"git+https://github.com/navid-kianfar/dsh-memory.git"},"bugs":{"url":"https://github.com/navid-kianfar/dsh-memory/issues"},"license":"MIT","readme":"# @achasoft/dsh-memory\n\n**Persistent, searchable, per-project memory for the [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness).**\n\nAn agent forgets everything between sessions. You re-explain the same decisions, the same conventions get missed, and the context you built up disappears the moment the window fills. This plugin gives each project its own memory — decisions, rules, architecture notes, and sprint goals — stored in a DuckDB file inside the project, retrieved by keyword and by meaning, and **injected into every model request** so a rule cannot be compacted away.\n\nIt is the [Claude Memory MCP](https://github.com/navid-kianfar/claude-memory-mcp) idea rebuilt as a first-class harness plugin: no daemon, no separate server, no second process owning your data.\n\n---\n\n## What you get\n\n- **Per-project memory.** One DuckDB file at `<project>/.dsh/memory.db`. Two workspaces open in one client never share a rule set, and nothing follows you to another checkout.\n- **Rules that actually bind.** Mandatory and forbidden rules are a system-prompt section, re-read at *every* prompt assembly — so they survive context compaction, and an edit in the UI binds the very next request without restarting anything.\n- **Hybrid search.** BM25F over title, entities, tags, summary, and body, blended with recency and how often a memory has proved useful. Add an embeddings endpoint and vector similarity joins the ranking; without one everything still works, keyword-only.\n- **A management UI.** A **Memory** tab beside Chat in every project session — browse, search, add, edit, archive, and delete memories and rules, read each one's audit trail, and see the exact text the model is being given. The tab is a view of the session's own project, so it is always the memory the conversation beside it is bound by.\n- **Model-facing tools.** `memory_search`, `memory_store`, `memory_recall`, `memory_rules`, `memory_add_rule`, `memory_session_end` by default; listing, editing, archiving, and provenance when you opt into the full set.\n- **Session continuity.** Each session opens with the last session's summary, the current sprint goals, and recent decisions, and is reminded to file a summary before it ends.\n- **Retention.** A sprint note is not a decision. Each category carries a lifetime, priority extends it, and rules never expire.\n- **Queryable by hand.** `duckdb .dsh/memory.db \"select * from rules\"` is a supported way to use this, not a debugging trick.\n- **Import and export.** Turn an existing `CLAUDE.md` or `AGENTS.md` into structured rules, or export everything as JSON to commit and share.\n\n## Install\n\n```bash\ndsh plugin --profile <name> add @achasoft/dsh-memory\n```\n\nThen add it to your profile's `dsh.profile.bundles`. The plugin composes itself: the capability, the tools, and the browser surface all mount from its own `cordis.patch.yml`.\n\n## How it works\n\n```\nyour project/\n  .dsh/memory.db            ← DuckDB: memories, rules, sessions, provenance\n\nagent session starts  ──►  open the project's memory\n                           register a rules section in THAT agent's scope\n                           inject the last summary, sprint goals, decisions\n\nevery model request   ──►  the section re-reads the rule block  ← survives compaction\n\nthe agent works       ──►  memory_search / memory_store / memory_add_rule\n\nsession ends          ──►  memory_session_end files the summary\n```\n\nRules go through the **system prompt**, not a per-turn message: the prompt is reassembled before every request, so the rules are always present and always current. Session context — history rather than obligation — is injected once at session start instead, so you do not pay for it on every turn.\n\n## Configuration\n\nEvery field is a validated setting, changeable from your profile's `cordis.patch.yml` or from **Settings → Plugins → Memory** in the Web Client.\n\n| Setting | Default | What it does |\n| --- | --- | --- |\n| `databasePath` | `.dsh/memory.db` | Relative to each project's directory. |\n| `injectRules` | `true` | Put the rule block in every model request. Off keeps rules stored but unenforced. |\n| `injectSessionContext` | `true` | Seed a starting session with the last summary, sprint goals, and recent decisions. |\n| `autoSession` | `true` | Open and close a memory session alongside each agent session. |\n| `remind` | `once` | When to remind the model to file a summary: `never`, `once`, `every-turn`. |\n| `vectorWeight` | `0.6` | The semantic signal's share of a blended ranking. Ignored without embeddings. |\n| `minSimilarity` | `0.05` | Similarity floor for a search that does not name one. |\n| `searchLimit` | `10` | Hits returned when the caller does not say. |\n| `candidateLimit` | `1000` | Rows either search probe considers. |\n| `embedBatch` | `64` | Memories embedded per background pass. |\n| `toolset` | `core` | `core` or `full` — see below. |\n| `retentionDays` | per category | Days per category; `0` means never. Rules never expire regardless. |\n\n### Semantic recall (optional)\n\nEnable the embeddings row and point it at any endpoint speaking OpenAI's `/v1/embeddings` — a hosted API, a local inference server, or Ollama:\n\n```yaml\n- id: memory-embeddings-openai\n  disabled: false\n  config:\n    baseUrl: https://api.openai.com/v1\n    model: text-embedding-3-small\n    apiKeyEnv: OPENAI_API_KEY\n    timeoutMs: 30000\n    batchSize: 64\n```\n\nThe key is addressed by reference, never stored: `apiKeyEnv` names an environment variable resolved through the harness credential seam at the start of every call.\n\nMemories are embedded in the background and vectors are stored as DuckDB `FLOAT[]`. Changing model strands the old vectors — they are excluded from comparison rather than compared — and **Rebuild vectors** in the UI re-embeds everything.\n\n## Tools\n\n`toolset: core` registers six:\n\n| Tool | For |\n| --- | --- |\n| `memory_search` | Find what the project already knows, by meaning and by keyword. |\n| `memory_store` | Record a decision, architecture note, devops fact, sprint goal, or feedback. |\n| `memory_recall` | Read one memory in full, by id or exact title. |\n| `memory_rules` | Read the complete binding rule set. |\n| `memory_add_rule` | State something the agent must always or must never do. |\n| `memory_session_end` | File the summary the next session opens with. |\n\n`toolset: full` adds `memory_list`, `memory_update`, `memory_archive`, and `memory_provenance` for deployments where the agent, rather than a person, curates the memory.\n\n## The database\n\nTwo views exist for reading the file by hand:\n\n```bash\nduckdb .dsh/memory.db \"select kind, title, content from rules\"\nduckdb .dsh/memory.db \"select category, title, updated, expires from memory\"\n```\n\nDuckDB allows a single writer, so the running harness owns the file; close it before opening the database read-write elsewhere.\n\n`.dsh/memory.db` is a normal file — commit it to share a team's rules, or add it to `.gitignore` to keep memory local.\n\n## Categories\n\n`decision` · `architecture` · `devops` · `sprint` · `project_plan` · `developer_docs` · `feedback` · `reference` · `session` · `mandatory_rules` · `forbidden_rules`\n\nCategory decides retention and whether an entry is enforced. Rules are enforced verbatim and completely — never ranked, never truncated.\n\n## Development\n\n```bash\npnpm install\npnpm run typecheck\npnpm test          # checks the RPC artifact, then runs the suite\npnpm run build     # emits generated/, then tsc → tsdown (node + browser halves)\n```\n\n`generated/` is the Typert RPC contract, emitted by `scripts/build-typert.mjs` from the endpoint table in `scripts/typert-endpoints.mjs`. `pnpm test` fails if it drifts from `src/host/`, and `tests/typert.spec.ts` runs the emitted manifest through the harness's own validator.\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-594bf61c23a3c6d63878d9308d21a86c"}