@foresight/memory
ForeSight: a temporal-aspect long-term memory plugin for DeepSeek Harness (dsh)
同名パッケージの別リポジトリ
インストール
npx -p @deepseek-ai/dsh dsh plugin --profile web add https://github.com/dawn-471/foresight/releases/download/v0.2.1/foresight-memory-0.2.1.tgzドキュメント
README 全文を読む ↗ForeSight
English | 中文
A temporal-aspect long-term memory plugin for DeepSeek Harness (dsh).
Every memory carries explicit temporal semantics — a linguistic aspect (进行体 / 完成体 / 未然体 / 恒常体 / 不确定兜底) paired with an anchor (time point / interval / open / none). The framework executes lifecycle mechanically: completion settlement at anchor expiry (an ended event becomes a retrievable "completed" fact, never silently dropped), TTL fallback, renewal nudge, prospective review, prediction verification, uncertain fallback for unclassifiable content, and conflict resolution by evidence with a single conservative/aggressive knob (β).
What's new in 0.2.1
- dsh tool-schema compatibility: memory tools now register raw
object-rooted JSON Schema, fixing the
memory_deleterejection (schema must be a JSON Schema of type: "object") on newer dsh releases. Upgrade the tarball in place; no data migration is needed.
What's new in 0.2.0
- Installable release tarball: the published artifact contains
lib/,templates/, the policy migration script,CHANGELOG.md, and the dsh bundle patch.scripts/check-pack.mjsasserts the tarball contents in CI. - First run works from a clean install: a missing
policy.yamlis seeded from packaged templates;SOUL.mdandIMPORTANT.mdare seeded for a new or empty data directory. Existing files are never overwritten. - Correct data-directory resolution: explicit config →
FORESIGHT_MEMORY_DIR→ platform default. Windows now defaults to%LOCALAPPDATA%/foresight; an existing%APPDATA%/foresightis kept as a legacy fallback. - v3 → v4 compatibility: v3 policies boot through an in-memory mapping and
scripts/migrate-policy.mjscan rewrite them with a backup. Legacyuser.mdis merged intoIMPORTANT.mdinstead of being shadowed. - Runtime resilience:
sqlite-vecload failure degrades to FTS + exact cosine over stored embeddings; Ollama failures trip an embedding circuit breaker. A Node add "file:/absolute/path/to/foresight-memory-0.2.1.tgz"
Do not add the six entries manually: `package.json` ships `dsh.bundle.patch`.
A profile-level `cordis.patch.yml` can override only the core config, for
example a custom data directory:
```yaml
# cordis.patch.yml (profile-level)
- id: foresight-core
config:
memoryRoot: '' # optional; default is platform-specific
A profile patch replaces the whole foresight-core config (not a deep merge),
so repeat any non-default dbFile / embedBaseUrl / embedModel values you
need.
3. Build from source (optional)
pnpm install # prepare compiles lib/
pnpm build
npm pack # tarball contains lib/, templates/, migration script, patch
Bundle and config changes hot-load, but code changes in lib/*.js require a dsh
restart or a new session. Do not validate a rebuilt plugin in an already running
session.
First run and data location
Your data lives outside the repo, in your own data directory. The plugin never ships user data; the repository is code + templates.
/
├── SOUL.md # personality (seeded from templates/SOUL.md.example)
├── IMPORTANT.md # globally-important facts, always injected (seeded)
├── policy.yaml # all tunables (seeded; edit this)
└── foresight.db # SQLite store (created automatically)
On first run ForeSight creates the directory and seeds missing starter files
from the packaged templates/: policy.yaml always (required to boot), and
SOUL.md / IMPORTANT.md when the directory is new or empty. Existing files
are never overwritten. The seed is logged explicitly.
Resolution chain
explicit options (adapter) → environment variables → platform defaults
policy.yaml lives inside memoryRoot, so it cannot supply memoryRoot itself.
| Setting | Env var | Default |
|---|---|---|
| data directory | FORESIGHT_MEMORY_DIR | %LOCALAPPDATA%/foresight (Windows; legacy %APPDATA% fallback) / ~/.local/share/foresight (Unix) |
| database file | FORESIGHT_DB_FILE | foresight.db |
| embedding URL | FORESIGHT_EMBED_URL | http://localhost:11434 |
| embedding model | FORESIGHT_EMBED_MODEL | nomic-embed-text-v2-moe |
| embedding dimension | FORESIGHT_EMBED_DIM | 768 |
| breaker failure threshold | FORESIGHT_EMBED_FAILURES | 3 |
| breaker cooldown (ms) | FORESIGHT_EMBED_COOLDOWN_MS | 30000 |
| LLM base URL | FORESIGHT_LLM_BASE_URL | https://api.deepseek.com/v1 |
| LLM model | FORESIGHT_LLM_MODEL | deepseek-flash |
Windows SQLite + WAL should not live in a roaming profile. New installs use
%LOCALAPPDATA%; an existing %APPDATA%/foresight directory is detected and
kept rather than silently moved. Back it up and set memoryRoot explicitly if
you want to relocate it.
Runtime behavior
- Ingestion: at
turn/endthe observer writes the transcript and sends each user/assistant turn through the same write gate: salience filter, aspect classification, embedding, exact-content dedup, and conflict resolution. Gate failures are logged and never block the session. Derive runs everyderive.every_n_turnsturns (and at session flush). - Retrieval: hybrid memory FTS + semantic vectors, lifecycle eligibility, structural time filtering, and the injected memories section share the same ranking path. Embedding calls use a circuit breaker: after repeated Ollama failures, calls fail fast instead of adding a 30s timeout to every turn; writes continue without vectors and are repaired by backfill.
- Scopes: dsh / tools / injection / nudge use the
globalscope. The HTTP server derives a scope fromx-foresight-peer, isolating peers from each other and from the dshglobalpool. Configureserver.peer_tokensfor per-peer credentials; otherwise the shared token is one trust boundary. Bind the server to loopback. - Derive: conversation increments are summarized into structured facts with
a durable per-session cursor, exact-content dedup, embedding, lifecycle plan,
and conflict resolution.
scripts/migrate-policy.mjshandles the v3→v4 policy rename anduser.mdmerge. - Nudge: review questions for renewals, prospective/prediction verdicts,
uncertain fallback, suppressed conflicts, and active contradictions. The
review actions are executable through
memory_update/memory_delete/memory_restore/memory_renew.
Tools
| Tool | Purpose |
|---|---|
memory_write | Write one fact through the full gate, dedup, embed and conflict path |
memory_update | Correct content (re-embeds, keeps revision audit) |
memory_delete | Soft-delete (recoverable); hard purge via root-only HTTP API |
memory_restore | Restore a soft-deleted or suppressed memory |
memory_renew | Extend a progressive / prospective window |
memory_query | Semantic + lexical retrieval |
memory_reason | Dialectic answer over retrieved evidence, with conflicts surfaced |
HTTP API
Enabled only when policy.server.enabled is true.
| Endpoint | Purpose |
|---|---|
GET /v1/health | Liveness (no auth) |
POST /v1/memories | Write through the full gate |
POST /v1/memories/search | Hybrid retrieval |
GET /v1/memories/:id | Read one memory (scope-checked) |
PATCH /v1/memories/:id | Update content / aspect / anchor / activation |
DELETE /v1/memories/:id | Soft delete; ?purge=1 root-only hard delete |
POST /v1/memories/:id/restore | Restore |
POST /v1/memories/:id/renew | Renew a window |
POST /v1/reason | Dialectic reasoning |
Auth uses X-ForeSight-Token; peer identity uses X-ForeSight-Peer.
Policy file
policy.yaml is the single source of truth for implemented tunables: permission
matrix, aspect lifecycle (TTL / renewal / anchor rendering), gate categories and
salience, activation β and decay constants, retrieval factor weights (frozen:
0.40 / 0.20 / 0.25 / 0.15), injection budgets, nudge cadence, server port/token,
and derive routes. Fields without an executor are explicitly listed as reserved
in eval/DECISIONS.md
§13. Your assistant's personality, profile and memory policy are yours to
decide; none of it is baked into the code.
Upgrading from 0.1.x (policy v3)
v0.2.0 ships policy_version: 4. A v3 policy still boots: the loader maps it in
memory, logs a warning, and fills v4-only keys (uncertain, transitions,
gate.fallback_write) from the packaged template. To rewrite the file
explicitly (with a backup) and merge a legacy user.md into IMPORTANT.md:
# from a repo checkout
node scripts/migrate-policy.mjs # dry run: writes policy.yaml.v4- only
node scripts/migrate-policy.mjs --write # backup + replace + merge user.md
# from an installed package inside the dsh profile
node node_modules/@foresight/memory/scripts/migrate-policy.mjs --write
The runtime also merges IMPORTANT.md and user.md during the transition, so
creating the new file never hides the old profile. v4 changes gnomic storage
from the old doc/always behavior to memory/conditional — review the generated
policy rather than assuming the defaults are your intent.
Data-directory change: the package bundle patch no longer ships
memoryRoot: './memory'. If an existing install relied on that cwd-relative
directory, set memoryRoot to its absolute path in the profile patch before
upgrading; otherwise the platform default is used. On Windows, an existing
%APPDATA%/foresight is kept as a legacy fallback (Roaming is not auto-migrated
because SQLite WAL can be corrupted by profile sync).
Uninstall
dsh plugin --profile remove @foresight/memory(orpnpm removein the profile), which updatespackage.jsonand the lockfile.- Remove the package from the profile's
dsh.profile.bundleslist and delete theforesight-coreentry from the profile-levelcordis.patch.yml. - Remove any
FORESIGHT_*environment variables and the data directory you configured (%LOCALAPPDATA%/foresight, legacy%APPDATA%/foresight,$XDG_DATA_HOME/foresight, or a custom absolutememoryRoot). It containsforesight.db,-wal/-shm, and the audit log if enabled. - If you used
dsh plugin allow-version, remove that entry from the profile'scompatibility.json.
Keeping the data directory is safe; deleting it is a hard purge.
Layout
src/
├── types.ts # domain types (aspect