feat(cli): memory export — one-way Obsidian vault export of agent memory - #296
Merged
Conversation
…y corpus Adds an `atomic-agent memory` command with an `export` subcommand that mirrors the cross-session memory corpus (notes / lessons / procedures in <stateDir>/memory.sqlite) into an existing Obsidian vault as markdown files with YAML frontmatter (type, created, updated, tags) and [[wikilinks]] along the schema's own edges: memory_links rows, consolidated_into back-pointers, and lesson/procedure parent ids. v1 design decisions: - one-way and read-only: the database is opened readonly and never migrated; older schemas degrade gracefully (missing tables => empty) - stable id-based filenames (note-<id>.md, ...) under a vault subfolder (--folder, default 'atomic-agent') so records keep their Obsidian identity and backlinks across re-exports - idempotent and overwrite-safe: content is a pure function of the rows, unchanged files are not rewritten, and pruning of stale files is restricted to the machine-owned <kind>-<n>.md name patterns inside the export subfolders — user files are never touched - soft parent pointers to evicted rows are skipped, not rendered as dangling links - --vault falls back to $OBSIDIAN_VAULT_PATH (including via <stateDir>/.env); no watch mode, no sync-back in v1 The new command implements the 0/1/2 exit-code split (usage errors return 2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A minimal v1 of the Discord-requested Obsidian integration: a new
atomic-agent memoryCLI command with anexportsubcommand that mirrors the cross-session memory corpus (<stateDir>/memory.sqlite) into an existing Obsidian vault.Each record becomes one markdown file with YAML frontmatter (
type,created,updated,tags, plusstatus/sourcewhere the row has them) under the export subfolder:notes/note-<id>.md—memoriesrows, body = content,## Linkssection frommemory_linksedges and theconsolidated_intoback-pointerlessons/lesson-<id>.md— activation + principle,## Sourceswikilinks to parent notesprocedures/procedure-<id>.md— activation + numbered steps (with tool hints),## Sourceswikilinks to parent lessons/notesDesign assumptions (the reporter never described a flow, so v1 commits to these)
readonlyand never migrated — an export cannot mutate agent state. Older schema files degrade gracefully (missinglessons/procedures/memory_linkstables ⇒ empty sets). No watch mode, no sync-back, no conflict handling: a re-export overwrites the exported files.[[note-17]]by basename.note-<n>.md/lesson-<n>.md/procedure-<n>.mdnames inside the export's three subfolders; anything else the user keeps there is never touched.--foldermust stay a subfolder of the vault (usage error otherwise). The new command implements the CLI's 0/1/2 exit-code split.Tests
src/memory/obsidian-export.test.ts(8 tests): frontmatter + body rendering, every wikilink edge kind, dangling-soft-pointer skip, byte-identical idempotency, prune-vs-user-files safety, record-update overwrite,--foldertraversal guards, missing DB/vault errors, and a hand-rolled pre-lessons legacy schema exported without migration (asserts no new tables were created).src/cli/memory-command.test.ts(7 tests): help, unknown subcommand ⇒ 2, missing vault ⇒ 2,--vaulthappy path against a seeded state dir,$OBSIDIAN_VAULT_PATHfallback +--folder, escaping folder ⇒ 2, missing DB ⇒ 1.npm run lintclean; fullsrc/memory+src/clisuites: 58 files / 696 tests passed.npx tsx src/cli/index.ts memory export --vault …against a seeded corpus: files, wikilinks, and second-run idempotency verified.Reported on Discord: https://discord.com/channels/1515649306781155428/1515649308161085612/1540448454373941361
Windows note: paths go through
node:path(join/resolve/sep) throughout and tests use tmp dirs, but this was runtime-verified on macOS only.