pi-obsidian-memory 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +173 -7
- package/package.json +41 -11
- package/skills/obsidian-memory/SKILL.md +101 -0
- package/src/domain/capture/constants.ts +5 -0
- package/src/domain/capture/index.ts +6 -0
- package/src/domain/capture/input-problems.ts +9 -0
- package/src/domain/capture/schemas.ts +92 -0
- package/src/domain/capture/tally.ts +26 -0
- package/src/domain/capture/types.ts +49 -0
- package/src/domain/capture/validate.ts +75 -0
- package/src/domain/command-flags/constants.ts +141 -0
- package/src/domain/command-flags/index.ts +1 -0
- package/src/domain/config/change.ts +105 -0
- package/src/domain/config/constants.ts +25 -0
- package/src/domain/config/diagnostics.ts +35 -0
- package/src/domain/config/disclosures.ts +8 -0
- package/src/domain/config/fields.ts +7 -0
- package/src/domain/config/index.ts +11 -0
- package/src/domain/config/inspection.ts +43 -0
- package/src/domain/config/invariants.ts +68 -0
- package/src/domain/config/legacy-capture.ts +17 -0
- package/src/domain/config/observations.ts +109 -0
- package/src/domain/config/parse.ts +25 -0
- package/src/domain/config/paths.ts +61 -0
- package/src/domain/config/registration.ts +34 -0
- package/src/domain/config/repair.ts +36 -0
- package/src/domain/config/resources.ts +65 -0
- package/src/domain/config/rules.ts +49 -0
- package/src/domain/config/schemas.ts +155 -0
- package/src/domain/config/settings.ts +23 -0
- package/src/domain/config/types.ts +239 -0
- package/src/domain/decision-model/constants.ts +7 -0
- package/src/domain/decision-model/cutoffs.ts +8 -0
- package/src/domain/decision-model/endpoint.ts +11 -0
- package/src/domain/decision-model/failure-detail.ts +8 -0
- package/src/domain/decision-model/index.ts +6 -0
- package/src/domain/decision-model/rank.ts +36 -0
- package/src/domain/decision-model/types.ts +77 -0
- package/src/domain/embeddings/constants.ts +55 -0
- package/src/domain/embeddings/identity.ts +30 -0
- package/src/domain/embeddings/index.ts +5 -0
- package/src/domain/embeddings/schemas.ts +25 -0
- package/src/domain/embeddings/types.ts +52 -0
- package/src/domain/embeddings/vectors.ts +53 -0
- package/src/domain/folder-index/constants.ts +9 -0
- package/src/domain/folder-index/display.ts +22 -0
- package/src/domain/folder-index/index.ts +5 -0
- package/src/domain/folder-index/listing.ts +58 -0
- package/src/domain/folder-index/render.ts +114 -0
- package/src/domain/folder-index/types.ts +41 -0
- package/src/domain/index.ts +22 -0
- package/src/domain/lifecycle/index.ts +2 -0
- package/src/domain/lifecycle/lifecycle.ts +39 -0
- package/src/domain/lifecycle/types.ts +17 -0
- package/src/domain/loaded-memory/budget.ts +14 -0
- package/src/domain/loaded-memory/constants.ts +9 -0
- package/src/domain/loaded-memory/index.ts +4 -0
- package/src/domain/loaded-memory/render.ts +30 -0
- package/src/domain/loaded-memory/types.ts +19 -0
- package/src/domain/memory/draft.ts +12 -0
- package/src/domain/memory/index.ts +4 -0
- package/src/domain/memory/schemas.ts +15 -0
- package/src/domain/memory/target.ts +27 -0
- package/src/domain/memory/types.ts +20 -0
- package/src/domain/memory-agent/index.ts +5 -0
- package/src/domain/memory-agent/input-problems.ts +9 -0
- package/src/domain/memory-agent/refusal.ts +6 -0
- package/src/domain/memory-agent/schemas.ts +112 -0
- package/src/domain/memory-agent/types.ts +25 -0
- package/src/domain/memory-agent/validate.ts +67 -0
- package/src/domain/names/constants.ts +32 -0
- package/src/domain/names/index.ts +2 -0
- package/src/domain/names/names.ts +83 -0
- package/src/domain/note/check.ts +68 -0
- package/src/domain/note/constants.ts +15 -0
- package/src/domain/note/frontmatter-fields.ts +175 -0
- package/src/domain/note/frontmatter.ts +138 -0
- package/src/domain/note/index.ts +9 -0
- package/src/domain/note/parse.ts +41 -0
- package/src/domain/note/render.ts +27 -0
- package/src/domain/note/schema-errors.ts +41 -0
- package/src/domain/note/schemas.ts +38 -0
- package/src/domain/note/types.ts +53 -0
- package/src/domain/note/validate.ts +19 -0
- package/src/domain/path-platform/index.ts +2 -0
- package/src/domain/path-platform/path-module.ts +11 -0
- package/src/domain/path-platform/types.ts +1 -0
- package/src/domain/search-catalog/constants.ts +1 -0
- package/src/domain/search-catalog/coverage.ts +35 -0
- package/src/domain/search-catalog/dont-forget.ts +10 -0
- package/src/domain/search-catalog/fingerprint.ts +9 -0
- package/src/domain/search-catalog/index.ts +10 -0
- package/src/domain/search-catalog/inspection.ts +47 -0
- package/src/domain/search-catalog/plan.ts +68 -0
- package/src/domain/search-catalog/ranking.ts +27 -0
- package/src/domain/search-catalog/schemas.ts +49 -0
- package/src/domain/search-catalog/types.ts +103 -0
- package/src/domain/search-catalog/vector-refresh.ts +22 -0
- package/src/domain/shell-edit/command-segments.ts +28 -0
- package/src/domain/shell-edit/command-words.ts +22 -0
- package/src/domain/shell-edit/constants.ts +125 -0
- package/src/domain/shell-edit/executed-files.ts +154 -0
- package/src/domain/shell-edit/index.ts +6 -0
- package/src/domain/shell-edit/powershell-files.ts +38 -0
- package/src/domain/shell-edit/rules.ts +19 -0
- package/src/domain/shell-edit/types.ts +75 -0
- package/src/domain/tool-flags/constants.ts +178 -0
- package/src/domain/tool-flags/index.ts +2 -0
- package/src/domain/tool-flags/types.ts +7 -0
- package/src/domain/validation/constants.ts +1 -0
- package/src/domain/validation/describe.ts +137 -0
- package/src/domain/validation/index.ts +3 -0
- package/src/domain/validation/types.ts +3 -0
- package/src/domain/vault-access/absolute-candidate.ts +81 -0
- package/src/domain/vault-access/argument-tokens.ts +22 -0
- package/src/domain/vault-access/command-mentions-vault.ts +115 -0
- package/src/domain/vault-access/constants.ts +54 -0
- package/src/domain/vault-access/index.ts +7 -0
- package/src/domain/vault-access/types.ts +18 -0
- package/src/domain/vault-access/vault-access-refusal.ts +36 -0
- package/src/domain/vault-access/vault-location.ts +22 -0
- package/src/domain/vault-assets/index.ts +2 -0
- package/src/domain/vault-assets/render.ts +51 -0
- package/src/domain/vault-assets/types.ts +36 -0
- package/src/domain/vault-catalog/analyze.ts +37 -0
- package/src/domain/vault-catalog/classify.ts +37 -0
- package/src/domain/vault-catalog/dont-forget.ts +6 -0
- package/src/domain/vault-catalog/export-entries.ts +10 -0
- package/src/domain/vault-catalog/index.ts +5 -0
- package/src/domain/vault-catalog/types.ts +114 -0
- package/src/domain/vault-diagnosis/diagnose.ts +79 -0
- package/src/domain/vault-diagnosis/index.ts +2 -0
- package/src/domain/vault-diagnosis/types.ts +31 -0
- package/src/domain/vault-path/constants.ts +13 -0
- package/src/domain/vault-path/index.ts +2 -0
- package/src/domain/vault-path/vault-path.ts +65 -0
- package/src/pi/capture/cadence.ts +49 -0
- package/src/pi/capture/completion.ts +26 -0
- package/src/pi/capture/constants.ts +5 -0
- package/src/pi/capture/handlers.ts +30 -0
- package/src/pi/capture/index.ts +8 -0
- package/src/pi/capture/runtime.ts +83 -0
- package/src/pi/capture/schemas.ts +8 -0
- package/src/pi/capture/tool-calls.ts +6 -0
- package/src/pi/capture/transcript.ts +55 -0
- package/src/pi/capture/types.ts +46 -0
- package/src/pi/change-report/constants.ts +15 -0
- package/src/pi/change-report/index.ts +3 -0
- package/src/pi/change-report/report.ts +54 -0
- package/src/pi/change-report/types.ts +8 -0
- package/src/pi/context/constants.ts +5 -0
- package/src/pi/context/index.ts +3 -0
- package/src/pi/context/status.ts +15 -0
- package/src/pi/context/types.ts +98 -0
- package/src/pi/extension.ts +100 -0
- package/src/pi/index.ts +26 -0
- package/src/pi/memory-add/constants.ts +13 -0
- package/src/pi/memory-add/index.ts +5 -0
- package/src/pi/memory-add/memory-add.ts +31 -0
- package/src/pi/memory-add/respond.ts +55 -0
- package/src/pi/memory-add/schemas.ts +29 -0
- package/src/pi/memory-add/types.ts +15 -0
- package/src/pi/memory-archive/constants.ts +8 -0
- package/src/pi/memory-archive/index.ts +4 -0
- package/src/pi/memory-archive/memory-archive.ts +29 -0
- package/src/pi/memory-archive/schemas.ts +15 -0
- package/src/pi/memory-archive/types.ts +8 -0
- package/src/pi/memory-block/block.ts +75 -0
- package/src/pi/memory-block/constants.ts +24 -0
- package/src/pi/memory-block/index.ts +4 -0
- package/src/pi/memory-block/render.ts +54 -0
- package/src/pi/memory-block/types.ts +24 -0
- package/src/pi/memory-doctor/constants.ts +43 -0
- package/src/pi/memory-doctor/index.ts +4 -0
- package/src/pi/memory-doctor/memory-doctor.ts +135 -0
- package/src/pi/memory-doctor/report.ts +101 -0
- package/src/pi/memory-doctor/types.ts +13 -0
- package/src/pi/memory-export/constants.ts +15 -0
- package/src/pi/memory-export/index.ts +4 -0
- package/src/pi/memory-export/memory-export.ts +57 -0
- package/src/pi/memory-export/name.ts +9 -0
- package/src/pi/memory-export/types.ts +4 -0
- package/src/pi/memory-get/constants.ts +12 -0
- package/src/pi/memory-get/index.ts +5 -0
- package/src/pi/memory-get/memory-get.ts +23 -0
- package/src/pi/memory-get/respond.ts +38 -0
- package/src/pi/memory-get/schemas.ts +13 -0
- package/src/pi/memory-get/types.ts +10 -0
- package/src/pi/memory-init/constants.ts +17 -0
- package/src/pi/memory-init/index.ts +2 -0
- package/src/pi/memory-init/memory-init.ts +63 -0
- package/src/pi/memory-search/constants.ts +16 -0
- package/src/pi/memory-search/index.ts +5 -0
- package/src/pi/memory-search/memory-search.ts +22 -0
- package/src/pi/memory-search/respond.ts +62 -0
- package/src/pi/memory-search/schemas.ts +11 -0
- package/src/pi/memory-search/types.ts +10 -0
- package/src/pi/memory-session/constants.ts +7 -0
- package/src/pi/memory-session/index.ts +4 -0
- package/src/pi/memory-session/keeper.ts +101 -0
- package/src/pi/memory-session/respond.ts +6 -0
- package/src/pi/memory-session/types.ts +23 -0
- package/src/pi/memory-settings/constants.ts +69 -0
- package/src/pi/memory-settings/edits.ts +46 -0
- package/src/pi/memory-settings/index.ts +9 -0
- package/src/pi/memory-settings/lines.ts +119 -0
- package/src/pi/memory-settings/models.ts +81 -0
- package/src/pi/memory-settings/projects.ts +46 -0
- package/src/pi/memory-settings/providers.ts +77 -0
- package/src/pi/memory-settings/save.ts +16 -0
- package/src/pi/memory-settings/screen.ts +27 -0
- package/src/pi/memory-settings/types.ts +87 -0
- package/src/pi/memory-setup/constants.ts +33 -0
- package/src/pi/memory-setup/disclosure.ts +22 -0
- package/src/pi/memory-setup/index.ts +4 -0
- package/src/pi/memory-setup/memory-setup.ts +153 -0
- package/src/pi/memory-setup/types.ts +6 -0
- package/src/pi/memory-succeed/constants.ts +10 -0
- package/src/pi/memory-succeed/index.ts +4 -0
- package/src/pi/memory-succeed/memory-succeed.ts +34 -0
- package/src/pi/memory-succeed/schemas.ts +30 -0
- package/src/pi/memory-succeed/types.ts +8 -0
- package/src/pi/memory-update/constants.ts +8 -0
- package/src/pi/memory-update/index.ts +4 -0
- package/src/pi/memory-update/memory-update.ts +29 -0
- package/src/pi/memory-update/schemas.ts +24 -0
- package/src/pi/memory-update/types.ts +8 -0
- package/src/pi/paths/constants.ts +7 -0
- package/src/pi/paths/index.ts +2 -0
- package/src/pi/paths/paths.ts +15 -0
- package/src/pi/paths/platform.ts +7 -0
- package/src/pi/registrar.ts +25 -0
- package/src/pi/registration-report/constants.ts +13 -0
- package/src/pi/registration-report/index.ts +2 -0
- package/src/pi/registration-report/report.ts +26 -0
- package/src/pi/relevant-memory/constants.ts +3 -0
- package/src/pi/relevant-memory/index.ts +4 -0
- package/src/pi/relevant-memory/prompt.ts +23 -0
- package/src/pi/relevant-memory/runtime.ts +88 -0
- package/src/pi/relevant-memory/types.ts +14 -0
- package/src/pi/semantic/constants.ts +3 -0
- package/src/pi/semantic/index.ts +2 -0
- package/src/pi/semantic/runtime.ts +59 -0
- package/src/pi/session-start/constants.ts +7 -0
- package/src/pi/session-start/index.ts +3 -0
- package/src/pi/session-start/session-start.ts +48 -0
- package/src/pi/session-start/types.ts +5 -0
- package/src/pi/shell-edit-guard/guard.ts +41 -0
- package/src/pi/shell-edit-guard/index.ts +3 -0
- package/src/pi/shell-edit-guard/prompt.ts +30 -0
- package/src/pi/shell-edit-guard/types.ts +13 -0
- package/src/pi/types.ts +44 -0
- package/src/pi/vault-guard/constants.ts +1 -0
- package/src/pi/vault-guard/index.ts +4 -0
- package/src/pi/vault-guard/request.ts +39 -0
- package/src/pi/vault-guard/types.ts +5 -0
- package/src/pi/vault-guard/vault-guard.ts +21 -0
- package/src/services/capture-cadence/domain-rules.ts +8 -0
- package/src/services/capture-cadence/index.ts +1 -0
- package/src/services/clock/clock.ts +7 -0
- package/src/services/clock/index.ts +1 -0
- package/src/services/config/canonicalize.ts +163 -0
- package/src/services/config/constants.ts +1 -0
- package/src/services/config/fully-qualified-path.ts +14 -0
- package/src/services/config/index.ts +12 -0
- package/src/services/config/path-identity.ts +65 -0
- package/src/services/config/publication.ts +75 -0
- package/src/services/config/read.ts +47 -0
- package/src/services/config/registration.ts +26 -0
- package/src/services/config/resolve-input.ts +27 -0
- package/src/services/config/snapshot.ts +26 -0
- package/src/services/config/target.ts +2 -0
- package/src/services/config/types.ts +97 -0
- package/src/services/config/vault-access.ts +2 -0
- package/src/services/config/volume-namespace.ts +5 -0
- package/src/services/config/write.ts +63 -0
- package/src/services/decision-model/constants.ts +16 -0
- package/src/services/decision-model/decide.ts +42 -0
- package/src/services/decision-model/diagnostics.ts +6 -0
- package/src/services/decision-model/endpoint.ts +1 -0
- package/src/services/decision-model/failure-detail.ts +1 -0
- package/src/services/decision-model/index.ts +7 -0
- package/src/services/decision-model/interruption.ts +29 -0
- package/src/services/decision-model/jev.ts +61 -0
- package/src/services/decision-model/laya-batch.ts +64 -0
- package/src/services/decision-model/laya-http-failure.ts +41 -0
- package/src/services/decision-model/laya-response.ts +95 -0
- package/src/services/decision-model/laya.ts +35 -0
- package/src/services/decision-model/preflight.ts +24 -0
- package/src/services/decision-model/prompts.ts +36 -0
- package/src/services/decision-model/schemas.ts +43 -0
- package/src/services/decision-model/score-candidates.ts +41 -0
- package/src/services/decision-model/types.ts +182 -0
- package/src/services/embeddings/asset-download.ts +45 -0
- package/src/services/embeddings/asset-fetch.ts +39 -0
- package/src/services/embeddings/asset-inspection.ts +36 -0
- package/src/services/embeddings/batch.ts +32 -0
- package/src/services/embeddings/chunks.ts +80 -0
- package/src/services/embeddings/configuration.ts +8 -0
- package/src/services/embeddings/constants.ts +24 -0
- package/src/services/embeddings/errors.ts +11 -0
- package/src/services/embeddings/google.ts +90 -0
- package/src/services/embeddings/http.ts +64 -0
- package/src/services/embeddings/index.ts +17 -0
- package/src/services/embeddings/inference.ts +35 -0
- package/src/services/embeddings/local.ts +138 -0
- package/src/services/embeddings/model-asset.ts +68 -0
- package/src/services/embeddings/model-cache.ts +30 -0
- package/src/services/embeddings/openai.ts +64 -0
- package/src/services/embeddings/operation.ts +31 -0
- package/src/services/embeddings/responses.ts +41 -0
- package/src/services/embeddings/runtime.ts +13 -0
- package/src/services/embeddings/schemas.ts +53 -0
- package/src/services/embeddings/types.ts +116 -0
- package/src/services/id/id.ts +5 -0
- package/src/services/id/index.ts +1 -0
- package/src/services/index.ts +11 -0
- package/src/services/llm/capture.ts +19 -0
- package/src/services/llm/check-chat-models.ts +38 -0
- package/src/services/llm/complete.ts +57 -0
- package/src/services/llm/constants.ts +32 -0
- package/src/services/llm/domain-rules.ts +2 -0
- package/src/services/llm/index.ts +6 -0
- package/src/services/llm/lifetime.ts +16 -0
- package/src/services/llm/retrieve.ts +19 -0
- package/src/services/llm/schemas.ts +9 -0
- package/src/services/llm/types.ts +94 -0
- package/src/services/search-index/catalog-query.ts +34 -0
- package/src/services/search-index/catalog-statements.ts +33 -0
- package/src/services/search-index/catalog.ts +19 -0
- package/src/services/search-index/cleanup.ts +13 -0
- package/src/services/search-index/close.ts +5 -0
- package/src/services/search-index/constants.ts +102 -0
- package/src/services/search-index/dont-forget.ts +1 -0
- package/src/services/search-index/fingerprint.ts +17 -0
- package/src/services/search-index/folder-index-statements.ts +17 -0
- package/src/services/search-index/folder-index-storage.ts +54 -0
- package/src/services/search-index/folder-indexes.ts +13 -0
- package/src/services/search-index/index.ts +14 -0
- package/src/services/search-index/inspection.ts +1 -0
- package/src/services/search-index/inventory.ts +67 -0
- package/src/services/search-index/legacy.ts +64 -0
- package/src/services/search-index/location.ts +12 -0
- package/src/services/search-index/open.ts +46 -0
- package/src/services/search-index/query.ts +39 -0
- package/src/services/search-index/ranking.ts +12 -0
- package/src/services/search-index/reconcile.ts +93 -0
- package/src/services/search-index/recovery.ts +56 -0
- package/src/services/search-index/refusals.ts +21 -0
- package/src/services/search-index/schema.ts +42 -0
- package/src/services/search-index/schemas.ts +181 -0
- package/src/services/search-index/search.ts +5 -0
- package/src/services/search-index/statements.ts +18 -0
- package/src/services/search-index/storage.ts +207 -0
- package/src/services/search-index/types.ts +113 -0
- package/src/services/search-index/vector-statements.ts +18 -0
- package/src/services/search-index/vector-storage.ts +169 -0
- package/src/services/search-index/vectors.ts +18 -0
- package/src/services/search-index/write.ts +9 -0
- package/src/services/shell-edit/ask.ts +53 -0
- package/src/services/shell-edit/domain-rules.ts +2 -0
- package/src/services/shell-edit/index.ts +4 -0
- package/src/services/shell-edit/schemas.ts +23 -0
- package/src/services/shell-edit/types.ts +61 -0
- package/src/services/shell-scripts/constants.ts +1 -0
- package/src/services/shell-scripts/files.ts +16 -0
- package/src/services/shell-scripts/index.ts +5 -0
- package/src/services/shell-scripts/package-scripts.ts +74 -0
- package/src/services/shell-scripts/schemas.ts +3 -0
- package/src/services/shell-scripts/scripts.ts +27 -0
- package/src/services/shell-scripts/types.ts +11 -0
- package/src/services/vault/archive.ts +31 -0
- package/src/services/vault/bootstrap/ensure.ts +50 -0
- package/src/services/vault/bootstrap/index.ts +2 -0
- package/src/services/vault/bootstrap/paths.ts +57 -0
- package/src/services/vault/bootstrap/types.ts +17 -0
- package/src/services/vault/bootstrap/write.ts +47 -0
- package/src/services/vault/catalog/bytes.ts +51 -0
- package/src/services/vault/catalog/dont-forget.ts +1 -0
- package/src/services/vault/catalog/enumerate.ts +69 -0
- package/src/services/vault/catalog/export.ts +21 -0
- package/src/services/vault/catalog/failures.ts +16 -0
- package/src/services/vault/catalog/index.ts +10 -0
- package/src/services/vault/catalog/inspect.ts +41 -0
- package/src/services/vault/catalog/observe.ts +35 -0
- package/src/services/vault/catalog/resolve.ts +94 -0
- package/src/services/vault/catalog/stat.ts +23 -0
- package/src/services/vault/catalog/types.ts +69 -0
- package/src/services/vault/catalog/visit.ts +58 -0
- package/src/services/vault/complete-blank.ts +66 -0
- package/src/services/vault/constants.ts +3 -0
- package/src/services/vault/context/index.ts +1 -0
- package/src/services/vault/context/types.ts +10 -0
- package/src/services/vault/create.ts +19 -0
- package/src/services/vault/display.ts +6 -0
- package/src/services/vault/domain-rules.ts +10 -0
- package/src/services/vault/draft.ts +2 -0
- package/src/services/vault/filesystem/failures.ts +53 -0
- package/src/services/vault/filesystem/hash.ts +5 -0
- package/src/services/vault/filesystem/index.ts +5 -0
- package/src/services/vault/filesystem/read.ts +61 -0
- package/src/services/vault/filesystem/types.ts +36 -0
- package/src/services/vault/filesystem/write.ts +80 -0
- package/src/services/vault/find.ts +27 -0
- package/src/services/vault/folder-contents.ts +31 -0
- package/src/services/vault/folder-index/index.ts +2 -0
- package/src/services/vault/folder-index/read.ts +87 -0
- package/src/services/vault/folder-index/types.ts +19 -0
- package/src/services/vault/folder-listing.ts +1 -0
- package/src/services/vault/index.ts +21 -0
- package/src/services/vault/inspect-folder.ts +13 -0
- package/src/services/vault/list.ts +121 -0
- package/src/services/vault/memory-folder.ts +24 -0
- package/src/services/vault/paths.ts +11 -0
- package/src/services/vault/publish.ts +52 -0
- package/src/services/vault/read.ts +46 -0
- package/src/services/vault/refresh-folders.ts +197 -0
- package/src/services/vault/refresh-plan.ts +79 -0
- package/src/services/vault/refresh.ts +8 -0
- package/src/services/vault/refusals.ts +23 -0
- package/src/services/vault/relocate.ts +131 -0
- package/src/services/vault/relocation-checks.ts +89 -0
- package/src/services/vault/resolve-stored-file.ts +43 -0
- package/src/services/vault/resolve.ts +109 -0
- package/src/services/vault/succeed.ts +45 -0
- package/src/services/vault/types.ts +199 -0
- package/src/services/vault/update-file.ts +58 -0
- package/src/services/vault/update.ts +22 -0
- package/src/services/vault/write-new-file.ts +37 -0
- package/src/shared/index.ts +1 -0
- package/src/shared/result/index.ts +1 -0
- package/src/shared/result/types.ts +17 -0
- package/src/usecases/add-memory/add-memory.ts +83 -0
- package/src/usecases/add-memory/index.ts +4 -0
- package/src/usecases/add-memory/maintenance.ts +23 -0
- package/src/usecases/add-memory/schemas.ts +12 -0
- package/src/usecases/add-memory/types.ts +47 -0
- package/src/usecases/archive-memory/archive-memory.ts +27 -0
- package/src/usecases/archive-memory/index.ts +3 -0
- package/src/usecases/archive-memory/schemas.ts +11 -0
- package/src/usecases/archive-memory/types.ts +17 -0
- package/src/usecases/capture-memory/apply.ts +73 -0
- package/src/usecases/capture-memory/capture-memory.ts +117 -0
- package/src/usecases/capture-memory/constants.ts +15 -0
- package/src/usecases/capture-memory/index.ts +5 -0
- package/src/usecases/capture-memory/observe.ts +122 -0
- package/src/usecases/capture-memory/settings.ts +20 -0
- package/src/usecases/capture-memory/types.ts +103 -0
- package/src/usecases/check-shell-edit/check-shell-edit.ts +28 -0
- package/src/usecases/check-shell-edit/index.ts +2 -0
- package/src/usecases/check-shell-edit/types.ts +30 -0
- package/src/usecases/check-vault-access/check-vault-access.ts +23 -0
- package/src/usecases/check-vault-access/constants.ts +7 -0
- package/src/usecases/check-vault-access/index.ts +4 -0
- package/src/usecases/check-vault-access/raw-device.ts +10 -0
- package/src/usecases/check-vault-access/targets.ts +49 -0
- package/src/usecases/check-vault-access/types.ts +33 -0
- package/src/usecases/complete-blank-memory/complete-blank-memory.ts +48 -0
- package/src/usecases/complete-blank-memory/constants.ts +3 -0
- package/src/usecases/complete-blank-memory/index.ts +4 -0
- package/src/usecases/complete-blank-memory/schemas.ts +14 -0
- package/src/usecases/complete-blank-memory/types.ts +28 -0
- package/src/usecases/diagnose-memory/constants.ts +3 -0
- package/src/usecases/diagnose-memory/decision.ts +36 -0
- package/src/usecases/diagnose-memory/diagnose-memory.ts +52 -0
- package/src/usecases/diagnose-memory/embeddings.ts +39 -0
- package/src/usecases/diagnose-memory/index.ts +5 -0
- package/src/usecases/diagnose-memory/types.ts +86 -0
- package/src/usecases/diagnose-memory/vault.ts +33 -0
- package/src/usecases/export-memory/collect.ts +20 -0
- package/src/usecases/export-memory/constants.ts +3 -0
- package/src/usecases/export-memory/export-memory.ts +84 -0
- package/src/usecases/export-memory/index.ts +3 -0
- package/src/usecases/export-memory/types.ts +28 -0
- package/src/usecases/get-memory/get-memory.ts +97 -0
- package/src/usecases/get-memory/index.ts +2 -0
- package/src/usecases/get-memory/types.ts +25 -0
- package/src/usecases/index.ts +25 -0
- package/src/usecases/list-memory/index.ts +2 -0
- package/src/usecases/list-memory/leased/index.ts +2 -0
- package/src/usecases/list-memory/leased/read.ts +16 -0
- package/src/usecases/list-memory/leased/types.ts +21 -0
- package/src/usecases/list-memory/list-memory.ts +33 -0
- package/src/usecases/list-memory/types.ts +8 -0
- package/src/usecases/load-dont-forget/index.ts +2 -0
- package/src/usecases/load-dont-forget/load-dont-forget.ts +111 -0
- package/src/usecases/load-dont-forget/types.ts +26 -0
- package/src/usecases/memory-change/change.ts +42 -0
- package/src/usecases/memory-change/index.ts +5 -0
- package/src/usecases/memory-change/maintenance.ts +11 -0
- package/src/usecases/memory-change/partial.ts +18 -0
- package/src/usecases/memory-change/receipt.ts +40 -0
- package/src/usecases/memory-change/types.ts +44 -0
- package/src/usecases/operation-context/context.ts +37 -0
- package/src/usecases/operation-context/index.ts +2 -0
- package/src/usecases/operation-context/types.ts +19 -0
- package/src/usecases/registration/check.ts +6 -0
- package/src/usecases/registration/entry.ts +33 -0
- package/src/usecases/registration/index.ts +8 -0
- package/src/usecases/registration/init.ts +94 -0
- package/src/usecases/registration/prepare-init.ts +43 -0
- package/src/usecases/registration/prepare.ts +35 -0
- package/src/usecases/registration/propose.ts +34 -0
- package/src/usecases/registration/publication.ts +90 -0
- package/src/usecases/registration/setup.ts +41 -0
- package/src/usecases/registration/types.ts +107 -0
- package/src/usecases/relevant-memory/agent.ts +55 -0
- package/src/usecases/relevant-memory/constants.ts +28 -0
- package/src/usecases/relevant-memory/cutoffs.ts +29 -0
- package/src/usecases/relevant-memory/decision.ts +102 -0
- package/src/usecases/relevant-memory/index.ts +11 -0
- package/src/usecases/relevant-memory/loaded.ts +31 -0
- package/src/usecases/relevant-memory/refresh.ts +30 -0
- package/src/usecases/relevant-memory/retrieve-memory.ts +62 -0
- package/src/usecases/relevant-memory/schemas.ts +20 -0
- package/src/usecases/relevant-memory/session-memory.ts +53 -0
- package/src/usecases/relevant-memory/track-dont-forget.ts +13 -0
- package/src/usecases/relevant-memory/types.ts +106 -0
- package/src/usecases/resolve-memory/index.ts +2 -0
- package/src/usecases/resolve-memory/leased/index.ts +2 -0
- package/src/usecases/resolve-memory/leased/resolve.ts +109 -0
- package/src/usecases/resolve-memory/leased/types.ts +35 -0
- package/src/usecases/resolve-memory/resolve-memory.ts +23 -0
- package/src/usecases/resolve-memory/types.ts +7 -0
- package/src/usecases/search-memory/constants.ts +1 -0
- package/src/usecases/search-memory/index.ts +3 -0
- package/src/usecases/search-memory/search-memory.ts +132 -0
- package/src/usecases/search-memory/types.ts +39 -0
- package/src/usecases/semantic/constants.ts +7 -0
- package/src/usecases/semantic/index.ts +5 -0
- package/src/usecases/semantic/prepare.ts +30 -0
- package/src/usecases/semantic/rank.ts +83 -0
- package/src/usecases/semantic/refresh-vectors.ts +95 -0
- package/src/usecases/semantic/types.ts +17 -0
- package/src/usecases/semantic-port/index.ts +1 -0
- package/src/usecases/semantic-port/types.ts +20 -0
- package/src/usecases/semantic-provider/constants.ts +6 -0
- package/src/usecases/semantic-provider/index.ts +5 -0
- package/src/usecases/semantic-provider/local.ts +33 -0
- package/src/usecases/semantic-provider/remote.ts +10 -0
- package/src/usecases/semantic-provider/size.ts +10 -0
- package/src/usecases/semantic-provider/types.ts +19 -0
- package/src/usecases/session/index.ts +2 -0
- package/src/usecases/session/lease.ts +70 -0
- package/src/usecases/session/receipts.ts +46 -0
- package/src/usecases/session/state.ts +106 -0
- package/src/usecases/session/types.ts +45 -0
- package/src/usecases/settings/change.ts +142 -0
- package/src/usecases/settings/index.ts +3 -0
- package/src/usecases/settings/prepare.ts +24 -0
- package/src/usecases/settings/types.ts +32 -0
- package/src/usecases/succeed-memory/index.ts +3 -0
- package/src/usecases/succeed-memory/schemas.ts +13 -0
- package/src/usecases/succeed-memory/succeed-memory.ts +34 -0
- package/src/usecases/succeed-memory/types.ts +18 -0
- package/src/usecases/synchronize-memory/index.ts +2 -0
- package/src/usecases/synchronize-memory/leased/aliases.ts +55 -0
- package/src/usecases/synchronize-memory/leased/folder-states.ts +58 -0
- package/src/usecases/synchronize-memory/leased/index.ts +2 -0
- package/src/usecases/synchronize-memory/leased/inspection.ts +32 -0
- package/src/usecases/synchronize-memory/leased/maintenance.ts +41 -0
- package/src/usecases/synchronize-memory/leased/publication.ts +55 -0
- package/src/usecases/synchronize-memory/leased/scan.ts +37 -0
- package/src/usecases/synchronize-memory/leased/synchronize.ts +102 -0
- package/src/usecases/synchronize-memory/leased/types.ts +60 -0
- package/src/usecases/synchronize-memory/synchronize-memory.ts +26 -0
- package/src/usecases/synchronize-memory/types.ts +5 -0
- package/src/usecases/update-memory/index.ts +3 -0
- package/src/usecases/update-memory/schemas.ts +14 -0
- package/src/usecases/update-memory/types.ts +16 -0
- package/src/usecases/update-memory/update-memory.ts +31 -0
- package/CHANGELOG.md +0 -21
package/README.md
CHANGED
|
@@ -1,15 +1,181 @@
|
|
|
1
1
|
# pi-obsidian-memory
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Long-term memory for the [pi coding agent](https://pi.dev), stored in [Obsidian](https://obsidian.md) vaults.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Coding agents forget everything between sessions. This extension gives pi durable memory that changes its future
|
|
6
|
+
behavior, that you can read and edit in Obsidian, and that lives in any folder you choose. Memory is two layers of
|
|
7
|
+
dedicated vaults: one global vault about you (how to address you, preferences, patterns, lessons) and one vault per
|
|
8
|
+
project. Notes are plain Markdown, written in English whatever language you speak, and never deleted: retired notes
|
|
9
|
+
move to `archive/`. See [docs/VISION.md](docs/VISION.md) for the decisions behind it.
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- Tudo configurável, com onboarding (`/memory-setup` e `/memory-init`).
|
|
11
|
+
> **Status:** runs on Windows, macOS and Linux; CI runs the unit tests on all three and the end-to-end suite runs on
|
|
12
|
+
> Windows. Requires Node 22.19 or later.
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
## Install
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
From git:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pi install git:github.com/DavyMassoneto/pi-obsidian-memory
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
From a local clone (loaded from that path, not copied; pi does not install its dependencies, so do it first):
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install --omit=dev --prefix ./pi-obsidian-memory
|
|
26
|
+
pi install ./pi-obsidian-memory
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Both write the package to `~/.pi/agent/settings.json`; add `--local` to write `.pi/settings.json` instead (pi reads it
|
|
30
|
+
only after project trust is granted). You can also add the source yourself:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"packages": ["git:github.com/DavyMassoneto/pi-obsidian-memory"]
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`pi list` shows installed packages. To try it for one run without installing:
|
|
39
|
+
`pi -e git:github.com/DavyMassoneto/pi-obsidian-memory`. Pi's own docs cover every option (`docs/packages.md`).
|
|
40
|
+
|
|
41
|
+
## Quick start
|
|
42
|
+
|
|
43
|
+
1. `/memory-setup` chooses where the global vault lives (create a new one or attach an existing folder), asks which
|
|
44
|
+
chat model to use for capture (the model in use is the default) and for the memory agent (a small, cheap one is
|
|
45
|
+
enough; the list is sorted by price, cheapest first), shows the
|
|
46
|
+
warnings that apply and writes the config. Run again, it is the settings screen: every setting, and the projects,
|
|
47
|
+
one select at a time.
|
|
48
|
+
2. In a project folder, `/memory-init` registers it with its own vault (created when missing). An unregistered folder
|
|
49
|
+
gets the global vault only.
|
|
50
|
+
|
|
51
|
+
Both commands need pi's UI. Until `/memory-setup` is done there is no memory, and session start says so. The config is
|
|
52
|
+
`pi-obsidian-memory/config.json` in the pi agent directory, outside the vaults; every key is described in
|
|
53
|
+
[docs/config.md](docs/config.md). Nothing needs editing by hand. Changing a vault leaves the old one as it was.
|
|
54
|
+
|
|
55
|
+
## What works
|
|
56
|
+
|
|
57
|
+
### Tools
|
|
58
|
+
|
|
59
|
+
The LLM uses these; the ones that write act only on your explicit request ("remember this"), and nothing in the prompt
|
|
60
|
+
nudges it to save on its own.
|
|
61
|
+
|
|
62
|
+
| Tool | Does |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `memory_search` | Finds notes in the global vault, the project vault or both (words and meaning together) |
|
|
65
|
+
| `memory_get` | Reads a note in full with its problems, a folder's index, or anything under `archive/` |
|
|
66
|
+
| `memory_add` | Saves a new note when you ask to remember something |
|
|
67
|
+
| `memory_update` | Changes a note you asked to change; keeps its identity |
|
|
68
|
+
| `memory_archive` | Moves a note to `archive/` |
|
|
69
|
+
| `memory_succeed` | Replaces a note with a successor; the two link to each other |
|
|
70
|
+
|
|
71
|
+
`memory_update`, `memory_archive` and `memory_succeed` first need a `memory_get` of the same note in the session, and
|
|
72
|
+
refuse a note that changed on disk since (an edit you made in Obsidian is never overwritten). A shipped skill,
|
|
73
|
+
`obsidian-memory`, teaches the agent the layout, note types and these rules; it is never written to a vault.
|
|
74
|
+
|
|
75
|
+
### Commands
|
|
76
|
+
|
|
77
|
+
| Command | Does |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `/memory-setup` | First setup (vault and models); afterwards the settings screen for every setting and the projects |
|
|
80
|
+
| `/memory-init` | Registers the working folder as a project with its own vault |
|
|
81
|
+
| `/memory-doctor` | Reports problems in the vaults and the config; offers to complete blank notes after you confirm |
|
|
82
|
+
| `/memory-export` | Writes both vaults to a new `.zip` (never overwrites; refuses a folder inside a vault) |
|
|
83
|
+
|
|
84
|
+
`/memory-doctor` lists invalid notes, blank notes, duplicate ids, leftover temporary files and folders over the
|
|
85
|
+
notes-per-folder limit, then checks the chat model, the embeddings and the decision model. Every other problem is left
|
|
86
|
+
as it is on disk.
|
|
87
|
+
|
|
88
|
+
### Memory in the conversation
|
|
89
|
+
|
|
90
|
+
- **Don't forget.** Mark a note with `dontForget: true` in its frontmatter. Every such note, in both vaults, is loaded
|
|
91
|
+
in full at session start, with no limit.
|
|
92
|
+
- **Relevant memory per message.** On each message, a fast decision model (a classifier that answers yes/no
|
|
93
|
+
probabilities; it never searches or generates) decides whether memory is needed. If so, the memory agent (a chat model)
|
|
94
|
+
searches and reads, the decision model scores each candidate note, and the relevant ones are added after your message. Earlier
|
|
95
|
+
messages are never rewritten, so the prompt cache holds; a loaded note that changed is added again, marked as
|
|
96
|
+
replacing the earlier copy. A loaded note that is gone is reported as "the note was archived or deleted"; one still
|
|
97
|
+
there but unusable, as "the note is still there but cannot be used (<problem>)"; one whose state is unknown, an
|
|
98
|
+
invalid config included, as "the note cannot be read (<problem>)". Session start also loads relevant notes within
|
|
99
|
+
`context.budgetChars` (12,000 by default). The decision model is Jev by default (by API; it needs `TYPESAFE_API_KEY`;
|
|
100
|
+
$0.042 per million input tokens, per docs.typesafe.ai), working from TypeSafe's starting cutoffs (0.5/0.5). Laya,
|
|
101
|
+
run locally, is an optional choice that needs explicit `gateThreshold` and `relevanceThreshold`: it ships none
|
|
102
|
+
because its gate measured at chance (see [decision-thresholds](docs/decision-thresholds.md)), so with Laya and no
|
|
103
|
+
cutoffs per-message memory is off and each session tells you. Setup steps are in
|
|
104
|
+
[Running the decision model](docs/config.md#running-the-decision-model). If the decision model is unavailable
|
|
105
|
+
nothing is added and you are told once per session; no other model takes over.
|
|
106
|
+
- **Automatic capture.** As in pi-hermes-memory, a background review of the conversation saves, updates, archives and
|
|
107
|
+
succeeds notes every `capture.nudgeInterval` assistant turns (10) or `capture.nudgeToolCalls` tool calls (15), once
|
|
108
|
+
the session has three user messages. What was not yet reviewed is also reviewed before compaction and when the
|
|
109
|
+
session ends, once it has `capture.flushMinTurns` user messages (6). It never asks you anything: what it is unsure
|
|
110
|
+
of is not saved. Its judgement quality is not yet proven against a real model.
|
|
111
|
+
- **Semantic search.** `memory_search` fuses words and meaning. The default is a local multilingual model (about
|
|
112
|
+
135 MB), downloaded when needed, without asking; OpenAI and Google are the alternatives. The index lives outside the
|
|
113
|
+
vaults and is rebuilt from the notes whenever needed.
|
|
114
|
+
|
|
115
|
+
### Vault guard
|
|
116
|
+
|
|
117
|
+
The LLM reaches vault files only through the memory tools. The extension refuses `read`, `write`, `edit`, `grep`, `find`
|
|
118
|
+
and `ls` on a vault, `bash`/`powershell` commands that write a vault path out, and junctions and symlinks into a vault.
|
|
119
|
+
You, and Obsidian, are not the LLM and stay free.
|
|
120
|
+
|
|
121
|
+
Accepted as they are (your decision, 2026-10-17): reading a vault through a path the shell builds indirectly
|
|
122
|
+
(variables, globs, scripts), tools of other extensions, and foreground subagents, which load no extensions. Creating
|
|
123
|
+
hardlinks through the shell is refused by the shell-edit guard. Details in
|
|
124
|
+
[docs/ROADMAP.md](docs/ROADMAP.md#2-memory-the-agent-can-read-vault-access-only).
|
|
125
|
+
|
|
126
|
+
Paths are compared ignoring case on Windows and macOS and with case on Linux, whatever the volume: a case-sensitive
|
|
127
|
+
macOS volume is still compared ignoring case, and a case-insensitive mount on Linux is still compared with case.
|
|
128
|
+
|
|
129
|
+
### Shell-edit guard
|
|
130
|
+
|
|
131
|
+
Before every `bash`/`powershell` call, Jev (`jev-latest`, which needs `TYPESAFE_API_KEY`) scores whether the command
|
|
132
|
+
edits a file through a redirection, an in-place edit, inline code, a script that writes, a copy or download that
|
|
133
|
+
creates a file, or a hardlink. A score at or above its cutoff refuses the call and points to `edit` and `write`;
|
|
134
|
+
when Jev cannot answer, the call is refused. The cutoffs and how they were measured are in
|
|
135
|
+
[docs/shell-edit-cutoffs.md](docs/shell-edit-cutoffs.md).
|
|
136
|
+
|
|
137
|
+
### Dashboard
|
|
138
|
+
|
|
139
|
+
Setup and init write `Memory.base` at each vault root when it is missing, with views for all notes, Don't forget and
|
|
140
|
+
Archive (file name, folder, type, Don't forget, updated). Your edits to it are kept. It only displays.
|
|
141
|
+
|
|
142
|
+
## Privacy
|
|
143
|
+
|
|
144
|
+
- Capture and the memory agent send conversation and note content to the chat model you choose.
|
|
145
|
+
- Jev, the default decision model, sends your messages and candidate notes to TypeSafe; Laya, the optional local choice, runs on your machine.
|
|
146
|
+
- Choosing a remote embeddings provider (OpenAI, Google) sends note content and queries to it.
|
|
147
|
+
- `/memory-setup` warns about each of these before writing, as a plain warning with no question; nothing is asked at
|
|
148
|
+
runtime, and no other provider ever takes the place of the one you chose.
|
|
149
|
+
- Secrets are saved as written: the vault is yours, with no masking or blocking.
|
|
150
|
+
- Credentials come from pi or the environment; `config.json` never holds a key.
|
|
151
|
+
|
|
152
|
+
## Development
|
|
153
|
+
|
|
154
|
+
Tested with pi `1.3.0` and TypeBox `1.3.27`, pinned as development dependencies. Pi provides both at runtime;
|
|
155
|
+
following its package contract, they are wildcard peers, not bundled runtime dependencies.
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
npm install
|
|
159
|
+
npm run lint
|
|
160
|
+
npm run typecheck
|
|
161
|
+
npm test # offline: pure tests and tests on a real temporary disk
|
|
162
|
+
npm run test:e2e # the real pi over RPC, with a temporary agent folder and vaults
|
|
163
|
+
npm run test:model # live tests: real models and network
|
|
164
|
+
pi -e ./src/pi/extension.ts
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`npm test` needs no model and no network. `npm run test:e2e` uses the real Haiku (`cc/claude-haiku-5-5`) through
|
|
168
|
+
OmniRoute, loaded in pi by `pi-omniroute-sync`, and the real Jev. It reads `OMNIROUTE_URL`, `OMNIROUTE_API_KEY` and
|
|
169
|
+
`TYPESAFE_API_KEY` from the environment and runs one test file at a time. CI runs it on windows-latest (the secrets
|
|
170
|
+
have the same names). The Laya tests use a real `laya-serve` from `tmp/laya-venv` and run only on request:
|
|
171
|
+
`npx vitest run --project e2e-laya`.
|
|
172
|
+
|
|
173
|
+
`npm run test:model` downloads the local embedding model (about 135 MB) to a cache folder outside the repository
|
|
174
|
+
(`%LOCALAPPDATA%\pi-obsidian-memory-bench\models`) and is not part of `npm test`.
|
|
175
|
+
|
|
176
|
+
The roadmap is in [docs/ROADMAP.md](docs/ROADMAP.md); the note format is in
|
|
177
|
+
[docs/vault-format.md](docs/vault-format.md).
|
|
178
|
+
|
|
179
|
+
## License
|
|
14
180
|
|
|
15
181
|
[MIT](LICENSE)
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-obsidian-memory",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Long-term memory for the pi coding agent, stored in Obsidian vaults",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi",
|
|
7
7
|
"pi-coding-agent",
|
|
8
|
+
"pi-package",
|
|
8
9
|
"obsidian",
|
|
9
10
|
"memory",
|
|
10
11
|
"agent-memory"
|
|
@@ -20,24 +21,53 @@
|
|
|
20
21
|
"url": "https://github.com/DavyMassoneto/pi-obsidian-memory/issues"
|
|
21
22
|
},
|
|
22
23
|
"type": "module",
|
|
24
|
+
"imports": {
|
|
25
|
+
"#src/*": "./src/*/index.ts",
|
|
26
|
+
"#test-helpers": "./tests/helpers/index.ts"
|
|
27
|
+
},
|
|
23
28
|
"engines": {
|
|
24
|
-
"node": ">=
|
|
29
|
+
"node": ">=22.19.0"
|
|
25
30
|
},
|
|
26
31
|
"files": [
|
|
27
|
-
"
|
|
32
|
+
"src",
|
|
33
|
+
"skills"
|
|
28
34
|
],
|
|
29
35
|
"scripts": {
|
|
30
|
-
"
|
|
31
|
-
"
|
|
36
|
+
"format": "biome check --write .",
|
|
37
|
+
"lint": "biome check .",
|
|
38
|
+
"test": "vitest run --project unit",
|
|
39
|
+
"test:model": "vitest run --project model",
|
|
40
|
+
"test:e2e": "vitest run --project e2e",
|
|
32
41
|
"typecheck": "tsc --noEmit"
|
|
33
42
|
},
|
|
34
|
-
"
|
|
35
|
-
"
|
|
43
|
+
"pi": {
|
|
44
|
+
"extensions": [
|
|
45
|
+
"./src/pi/extension.ts"
|
|
46
|
+
],
|
|
47
|
+
"skills": [
|
|
48
|
+
"./skills"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
53
|
+
"typebox": "*"
|
|
36
54
|
},
|
|
37
55
|
"devDependencies": {
|
|
38
|
-
"@
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
56
|
+
"@biomejs/biome": "2.5.15",
|
|
57
|
+
"@earendil-works/pi-coding-agent": "1.3.0",
|
|
58
|
+
"@types/node": "24.19.1",
|
|
59
|
+
"@types/stopword": "2.0.3",
|
|
60
|
+
"git-cliff": "2.14.2",
|
|
61
|
+
"pi-omniroute-sync": "1.2.1",
|
|
62
|
+
"typebox": "1.3.27",
|
|
63
|
+
"typescript": "7.0.2",
|
|
64
|
+
"vitest": "5.0.3"
|
|
65
|
+
},
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"@huggingface/transformers": "4.3.1",
|
|
68
|
+
"fflate": "0.8.3",
|
|
69
|
+
"stopword": "3.1.5",
|
|
70
|
+
"ulid": "3.0.2",
|
|
71
|
+
"yaml": "2.9.1"
|
|
42
72
|
}
|
|
43
73
|
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: obsidian-memory
|
|
3
|
+
description: How to use the Obsidian long-term memory (global and project vaults) - where notes go, note types, what is not memory, and the memory tools. Load before searching or reading memory, before saving something the user asked to remember, or when a memory block appears in the context.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Obsidian memory
|
|
7
|
+
|
|
8
|
+
Long-term memory lives in Obsidian vaults. Notes are in English, whatever language the user speaks.
|
|
9
|
+
|
|
10
|
+
## Two layers
|
|
11
|
+
|
|
12
|
+
- Global vault: about the user (how to address them, preferences, patterns, global lessons).
|
|
13
|
+
- Project vault: everything else about the current project.
|
|
14
|
+
- Classify each memory. When unsure which vault, ask the user.
|
|
15
|
+
- A folder with no registered project has the global vault only.
|
|
16
|
+
|
|
17
|
+
## Layout and placement
|
|
18
|
+
|
|
19
|
+
- One folder per subject. Each folder holds short notes, one point per note. Subjects nest with no depth limit.
|
|
20
|
+
- Place a note from general to specific: `typescript/testing/`, not `testing/typescript/`.
|
|
21
|
+
- Reuse before creating: walk the existing tree (read folder indexes level by level) and use the path that already covers the subject.
|
|
22
|
+
- When two paths fit, ask the user.
|
|
23
|
+
- Every folder has an `index.md` listing its subfolders and its notes (type and don't forget mark). The system keeps it up to date; never write it by hand.
|
|
24
|
+
- Not subjects: hidden folders, and at the vault root `archive/` and `_templates/`.
|
|
25
|
+
- `index` (any case) is reserved: no note can use it as its statement.
|
|
26
|
+
|
|
27
|
+
## Notes
|
|
28
|
+
|
|
29
|
+
- The file name is the statement: reading the name tells exactly what the note says. The body holds the detail.
|
|
30
|
+
- Keep notes short, one point each. A new point in the same subject is a new note in that folder.
|
|
31
|
+
- Name: at most 100 characters by default. It must be a valid Windows file name and must not contain `< > : " / \ | ? * [ ] # ^`, control characters, a leading or trailing space, or a trailing dot. No Windows reserved names (`CON`, `NUL`, `COM1`...).
|
|
32
|
+
- Body: never empty, at most 1,000 characters by default. Record the detail even when the name says it all.
|
|
33
|
+
- An invalid note is refused with every reason. Rewrite it or split it into smaller notes.
|
|
34
|
+
- A note can be marked Don't forget: it is loaded in full at session start.
|
|
35
|
+
|
|
36
|
+
## Types
|
|
37
|
+
|
|
38
|
+
Pick exactly one. The list is closed. When unsure which type fits, ask the user.
|
|
39
|
+
|
|
40
|
+
- `rule`: how to do things; a user preference or a project convention.
|
|
41
|
+
- `procedure`: steps to do something in this project.
|
|
42
|
+
- `constraint`: a limit imposed from outside (platform, deadline, client).
|
|
43
|
+
- `fact`: how things are, about the user or the project.
|
|
44
|
+
- `issue`: a known problem that is still open, with its workaround.
|
|
45
|
+
- `question`: something still undecided or unknown.
|
|
46
|
+
- `decision`: a choice that was made, with its why.
|
|
47
|
+
- `lesson`: something learned from a mistake or a bug.
|
|
48
|
+
- `goal`: a committed objective for the future.
|
|
49
|
+
- `risk`: a problem that may happen.
|
|
50
|
+
- `idea`: a possibility not committed to yet.
|
|
51
|
+
- `reference`: where to find something external.
|
|
52
|
+
|
|
53
|
+
## Not memory
|
|
54
|
+
|
|
55
|
+
- Tasks and TODOs.
|
|
56
|
+
- Session logs.
|
|
57
|
+
- Anything the code or git history already records.
|
|
58
|
+
|
|
59
|
+
Secrets (keys, passwords, tokens) are memory: the vault is the user's own safe. Save them like any other note, with no masking. When unsure whether something is memory at all, ask the user.
|
|
60
|
+
|
|
61
|
+
## Reading
|
|
62
|
+
|
|
63
|
+
The memory block at session start, and the relevant notes added to a message, are only part of the memory. A note added again as replacing an earlier copy supersedes it; a note marked no longer valid must not be relied on. Search and read more when you need it.
|
|
64
|
+
|
|
65
|
+
- `memory_search`: search by words and, when semantic search is on, by meaning, over one or both vaults. When it says semantic search is off, try other words too. Each result gives the vault, the path, the type, the Don't forget mark and whether the note needs fixing. Archived notes and notes with invalid frontmatter are not searched.
|
|
66
|
+
- `memory_get`: takes a vault and a path.
|
|
67
|
+
- A note path returns the note in full, with every problem if it breaks any rule.
|
|
68
|
+
- A folder path returns its index. `""` is the vault root.
|
|
69
|
+
- Paths under `archive/` can be read.
|
|
70
|
+
- To place a note, read the root index and walk down the folder indexes with `memory_get`.
|
|
71
|
+
|
|
72
|
+
## Saving
|
|
73
|
+
|
|
74
|
+
- Memory is captured, updated and retired automatically by a background review of the conversation; you don't need to save anything for it.
|
|
75
|
+
- Use `memory_add` only when the user explicitly asks you to remember something. Never save on your own initiative, and never nudge the user to save.
|
|
76
|
+
- Choose the vault, the folder and the type as described above. Ask when unsure.
|
|
77
|
+
- A name already taken (in any case) is refused with the existing note. If it is the same point, read it with `memory_get` and, only if the user asked for a change, use `memory_update`; otherwise choose a statement that says what is new.
|
|
78
|
+
- Do not save skills or instructions to a vault. Vaults hold only memory.
|
|
79
|
+
|
|
80
|
+
## Changing and retiring
|
|
81
|
+
|
|
82
|
+
Use these only when the user explicitly asks. Always read the note with `memory_get` in this session first, with the exact vault and path; a note not read, or changed on disk since it was read, is refused.
|
|
83
|
+
|
|
84
|
+
- `memory_update`: changes the body, type or Don't forget mark of a note. It never renames: a different statement is a new note that replaces the old one.
|
|
85
|
+
- `memory_archive`: retires a note that stopped being true and has no successor. It moves to `archive/`; nothing is ever deleted.
|
|
86
|
+
- `memory_succeed`: replaces a note with a new one (new statement, folder, type and body). The old note moves to `archive/` and both are linked.
|
|
87
|
+
- Notes under `archive/` cannot be changed.
|
|
88
|
+
- After a partial result, do not call again: tell the user what was done and ask them to check the vault.
|
|
89
|
+
|
|
90
|
+
## Vault access
|
|
91
|
+
|
|
92
|
+
- Never read or write vault files with file tools (`read`, `write`, `edit`, `grep`, `find`, `ls`) or with the shell, however the path is reached.
|
|
93
|
+
- Use only the memory tools. Files outside the vaults are unaffected.
|
|
94
|
+
- The user edits the vault freely in Obsidian; a note can change between sessions.
|
|
95
|
+
|
|
96
|
+
## Setup
|
|
97
|
+
|
|
98
|
+
- With no global vault registered there is no memory: tell the user to run `/memory-setup`.
|
|
99
|
+
- A folder not registered as a project has global memory only: the user can run `/memory-init` to register it.
|
|
100
|
+
- Notes listed under Needs fixing, blank notes and duplicate ids: suggest the user run `/memory-doctor`.
|
|
101
|
+
- A copy of the memory as a zip: the user can run `/memory-export`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Value } from "typebox/value"
|
|
2
|
+
|
|
3
|
+
import { describeSchemaErrors } from "#src/domain/validation"
|
|
4
|
+
import { CaptureInputSchema } from "./schemas.ts"
|
|
5
|
+
import type { CaptureInput } from "./types.ts"
|
|
6
|
+
|
|
7
|
+
export function captureInputProblems(input: CaptureInput): string[] {
|
|
8
|
+
return describeSchemaErrors(Value.Errors(CaptureInputSchema, input), "capture input")
|
|
9
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import Type from "typebox"
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
AgentContextSchema,
|
|
5
|
+
HashSchema,
|
|
6
|
+
ObservationSchema,
|
|
7
|
+
PathSchema,
|
|
8
|
+
ReadActionSchema,
|
|
9
|
+
ReadObservationSchema,
|
|
10
|
+
TextSchema,
|
|
11
|
+
VaultSchema,
|
|
12
|
+
} from "#src/domain/memory-agent"
|
|
13
|
+
import { NoteIdSchema, NoteTypeSchema } from "#src/domain/note"
|
|
14
|
+
|
|
15
|
+
export const CaptureDraftSchema = Type.Object(
|
|
16
|
+
{ folder: PathSchema, statement: TextSchema, body: TextSchema, type: NoteTypeSchema, dontForget: Type.Boolean() },
|
|
17
|
+
{ additionalProperties: false },
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
export const CaptureActionSchema = Type.Union([
|
|
21
|
+
ReadActionSchema,
|
|
22
|
+
Type.Object(
|
|
23
|
+
{ action: Type.Literal("add"), vault: VaultSchema, note: CaptureDraftSchema },
|
|
24
|
+
{ additionalProperties: false },
|
|
25
|
+
),
|
|
26
|
+
Type.Object(
|
|
27
|
+
{
|
|
28
|
+
action: Type.Enum(["update", "succeed"]),
|
|
29
|
+
vault: VaultSchema,
|
|
30
|
+
path: PathSchema,
|
|
31
|
+
id: NoteIdSchema,
|
|
32
|
+
expectedHash: HashSchema,
|
|
33
|
+
note: CaptureDraftSchema,
|
|
34
|
+
},
|
|
35
|
+
{ additionalProperties: false },
|
|
36
|
+
),
|
|
37
|
+
Type.Object(
|
|
38
|
+
{
|
|
39
|
+
action: Type.Literal("archive"),
|
|
40
|
+
vault: VaultSchema,
|
|
41
|
+
path: PathSchema,
|
|
42
|
+
id: NoteIdSchema,
|
|
43
|
+
expectedHash: HashSchema,
|
|
44
|
+
},
|
|
45
|
+
{ additionalProperties: false },
|
|
46
|
+
),
|
|
47
|
+
Type.Object({ action: Type.Literal("finish") }, { additionalProperties: false }),
|
|
48
|
+
])
|
|
49
|
+
|
|
50
|
+
export const WriteObservationSchema = Type.Object(
|
|
51
|
+
{
|
|
52
|
+
kind: Type.Literal("write"),
|
|
53
|
+
operation: Type.Enum(["add", "update", "archive", "succeed"]),
|
|
54
|
+
status: Type.Enum(["applied", "conflict", "refused"]),
|
|
55
|
+
vault: VaultSchema,
|
|
56
|
+
path: PathSchema,
|
|
57
|
+
detail: TextSchema,
|
|
58
|
+
},
|
|
59
|
+
{ additionalProperties: false },
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
export const RefusedObservationSchema = Type.Object(
|
|
63
|
+
{
|
|
64
|
+
kind: Type.Literal("refused"),
|
|
65
|
+
action: Type.Enum(["search", "get", "list", "add", "update", "archive", "succeed", "finish", "unparseable"]),
|
|
66
|
+
problems: Type.Array(TextSchema),
|
|
67
|
+
},
|
|
68
|
+
{ additionalProperties: false },
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
export const CaptureObservationSchema = Type.Union([
|
|
72
|
+
ObservationSchema,
|
|
73
|
+
WriteObservationSchema,
|
|
74
|
+
RefusedObservationSchema,
|
|
75
|
+
])
|
|
76
|
+
|
|
77
|
+
export const CaptureInputSchema = Type.Object(
|
|
78
|
+
{
|
|
79
|
+
context: AgentContextSchema,
|
|
80
|
+
transcriptDelta: Type.Array(
|
|
81
|
+
Type.Object({ role: Type.Enum(["user", "assistant"]), text: TextSchema }, { additionalProperties: false }),
|
|
82
|
+
{ minItems: 1 },
|
|
83
|
+
),
|
|
84
|
+
observations: Type.Array(CaptureObservationSchema),
|
|
85
|
+
explicitSaves: Type.Array(ReadObservationSchema),
|
|
86
|
+
limits: Type.Object(
|
|
87
|
+
{ maxBodyChars: Type.Integer({ minimum: 1 }), maxStatementChars: Type.Integer({ minimum: 1 }) },
|
|
88
|
+
{ additionalProperties: false },
|
|
89
|
+
),
|
|
90
|
+
},
|
|
91
|
+
{ additionalProperties: false },
|
|
92
|
+
)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { MIN_USER_MESSAGES_BEFORE_REVIEW } from "./constants.ts"
|
|
2
|
+
import type { CaptureCadenceSettings, CaptureTally, FinishedTurn, FlushMoment, TurnOutcome } from "./types.ts"
|
|
3
|
+
|
|
4
|
+
export function tallyUserMessage(tally: CaptureTally): CaptureTally {
|
|
5
|
+
return { ...tally, userMessages: tally.userMessages + 1 }
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function tallyTurn(
|
|
9
|
+
tally: CaptureTally,
|
|
10
|
+
turn: FinishedTurn,
|
|
11
|
+
settings: CaptureCadenceSettings | null,
|
|
12
|
+
): TurnOutcome {
|
|
13
|
+
const counted = { ...tally, turnsSinceReview: tally.turnsSinceReview + 1 }
|
|
14
|
+
if (!settings?.reviewEnabled || turn.reviewActive) return { tally: counted, review: false }
|
|
15
|
+
counted.toolCallsSinceReview += turn.toolCalls
|
|
16
|
+
const reached =
|
|
17
|
+
counted.turnsSinceReview >= settings.nudgeInterval || counted.toolCallsSinceReview >= settings.nudgeToolCalls
|
|
18
|
+
if (!reached || counted.userMessages < MIN_USER_MESSAGES_BEFORE_REVIEW) return { tally: counted, review: false }
|
|
19
|
+
return { tally: { ...counted, turnsSinceReview: 0, toolCallsSinceReview: 0 }, review: true }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function shouldFlush(tally: CaptureTally, settings: CaptureCadenceSettings, moment: FlushMoment): boolean {
|
|
23
|
+
if (tally.userMessages < settings.flushMinTurns) return false
|
|
24
|
+
if (moment === "compact") return settings.flushOnCompact
|
|
25
|
+
return settings.flushOnShutdown
|
|
26
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Static } from "typebox"
|
|
2
|
+
|
|
3
|
+
import type { Failed, Succeeded } from "#src/shared"
|
|
4
|
+
import type {
|
|
5
|
+
CaptureActionSchema,
|
|
6
|
+
CaptureDraftSchema,
|
|
7
|
+
CaptureInputSchema,
|
|
8
|
+
CaptureObservationSchema,
|
|
9
|
+
} from "./schemas.ts"
|
|
10
|
+
|
|
11
|
+
export interface CaptureCadenceSettings {
|
|
12
|
+
nudgeInterval: number
|
|
13
|
+
nudgeToolCalls: number
|
|
14
|
+
flushMinTurns: number
|
|
15
|
+
reviewEnabled: boolean
|
|
16
|
+
flushOnCompact: boolean
|
|
17
|
+
flushOnShutdown: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface CaptureTally {
|
|
21
|
+
userMessages: number
|
|
22
|
+
turnsSinceReview: number
|
|
23
|
+
toolCallsSinceReview: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface FinishedTurn {
|
|
27
|
+
toolCalls: number
|
|
28
|
+
reviewActive: boolean
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface TurnOutcome {
|
|
32
|
+
tally: CaptureTally
|
|
33
|
+
review: boolean
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type FlushMoment = "compact" | "shutdown"
|
|
37
|
+
|
|
38
|
+
export type CaptureDraft = Static<typeof CaptureDraftSchema>
|
|
39
|
+
export type CaptureAction = Static<typeof CaptureActionSchema>
|
|
40
|
+
export type CaptureInput = Static<typeof CaptureInputSchema>
|
|
41
|
+
export type CaptureObservation = Static<typeof CaptureObservationSchema>
|
|
42
|
+
export type CaptureResult = Succeeded<CaptureAction> | Failed
|
|
43
|
+
export type TranscriptMessage = CaptureInput["transcriptDelta"][number]
|
|
44
|
+
|
|
45
|
+
export interface AddDiscriminant {
|
|
46
|
+
action: "add"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type CaptureAdd = Extract<CaptureAction, AddDiscriminant>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Value } from "typebox/value"
|
|
2
|
+
|
|
3
|
+
import { checkAgentVault, checkReadAction, hasReadIdentity, type MemoryIdentity } from "#src/domain/memory-agent"
|
|
4
|
+
import { checkNoteText } from "#src/domain/note"
|
|
5
|
+
import { checkMemoryFolder, checkVaultPath, joinVaultPath } from "#src/domain/vault-path"
|
|
6
|
+
import { CaptureActionSchema } from "./schemas.ts"
|
|
7
|
+
import type { CaptureAction, CaptureAdd, CaptureDraft, CaptureInput, CaptureResult } from "./types.ts"
|
|
8
|
+
|
|
9
|
+
export function parseCaptureAction(text: string, input: CaptureInput): CaptureResult {
|
|
10
|
+
try {
|
|
11
|
+
const action = JSON.parse(text)
|
|
12
|
+
if (!Value.Check(CaptureActionSchema, action)) {
|
|
13
|
+
return { succeeded: false, problems: ["Invalid capture action"] }
|
|
14
|
+
}
|
|
15
|
+
const problems = checkCaptureAction(action, input)
|
|
16
|
+
if (problems.length > 0) return { succeeded: false, problems }
|
|
17
|
+
return { succeeded: true, output: action }
|
|
18
|
+
} catch {
|
|
19
|
+
return { succeeded: false, problems: ["Invalid capture JSON"] }
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function checkCaptureAction(action: CaptureAction, input: CaptureInput): string[] {
|
|
24
|
+
if (action.action === "finish") return []
|
|
25
|
+
if (action.action === "search" || action.action === "get" || action.action === "list") {
|
|
26
|
+
return checkReadAction(action, input.context)
|
|
27
|
+
}
|
|
28
|
+
const problems = checkAgentVault(action.vault, input.context)
|
|
29
|
+
if (action.action !== "add") {
|
|
30
|
+
const identity = { vault: action.vault, path: action.path, id: action.id, hash: action.expectedHash }
|
|
31
|
+
problems.push(...checkMutation(identity, input))
|
|
32
|
+
}
|
|
33
|
+
if (action.action !== "archive") problems.push(...checkDraft(action.note, input))
|
|
34
|
+
if (action.action === "add") problems.push(...checkDuplicate(action, input))
|
|
35
|
+
if ((action.action === "add" || action.action === "succeed") && action.note.folder.length === 0) {
|
|
36
|
+
problems.push("New capture notes require a subject folder")
|
|
37
|
+
}
|
|
38
|
+
if (
|
|
39
|
+
action.action === "update" &&
|
|
40
|
+
(action.path.slice(-3).toLowerCase() !== ".md" ||
|
|
41
|
+
action.path.slice(0, -3) !== joinVaultPath(action.note.folder, action.note.statement))
|
|
42
|
+
) {
|
|
43
|
+
problems.push("Update must keep the read note's folder and statement")
|
|
44
|
+
}
|
|
45
|
+
return problems
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function checkMutation(identity: MemoryIdentity, input: CaptureInput): string[] {
|
|
49
|
+
const latest = input.observations.findLast(
|
|
50
|
+
(item) =>
|
|
51
|
+
(item.kind === "read" || item.kind === "write") && item.vault === identity.vault && item.path === identity.path,
|
|
52
|
+
)
|
|
53
|
+
const reads = input.observations.filter((item) => item.kind !== "write" && item.kind !== "refused")
|
|
54
|
+
if (latest?.kind !== "read" || !hasReadIdentity(identity, reads)) {
|
|
55
|
+
return ["Mutation requires a fresh matching read identity and hash"]
|
|
56
|
+
}
|
|
57
|
+
return checkVaultPath(identity.path)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function checkDraft(note: CaptureDraft, input: CaptureInput): string[] {
|
|
61
|
+
return [...checkNoteText(note.statement, note.body, input.limits), ...checkMemoryFolder(note.folder)]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function checkDuplicate(action: CaptureAdd, input: CaptureInput): string[] {
|
|
65
|
+
const existing = [...input.explicitSaves, ...input.observations.filter((item) => item.kind === "read")]
|
|
66
|
+
const path = joinVaultPath(action.note.folder, `${action.note.statement}.md`).toLowerCase()
|
|
67
|
+
const duplicate = existing.some(
|
|
68
|
+
(read) =>
|
|
69
|
+
read.vault === action.vault &&
|
|
70
|
+
(read.path.toLowerCase() === path ||
|
|
71
|
+
(read.statement === action.note.statement && read.body === action.note.body)),
|
|
72
|
+
)
|
|
73
|
+
if (duplicate) return ["Existing point requires an update or finish, not a duplicate add"]
|
|
74
|
+
return []
|
|
75
|
+
}
|