Skip to content

WIP allow syncing of claude memories - #258

Open
dbmikus wants to merge 5 commits into
mainfrom
pr-255-secure-memory-merge
Open

dbmikus wants to merge 5 commits into
mainfrom
pr-255-secure-memory-merge

Conversation

@dbmikus

@dbmikus dbmikus commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

No description provided.

Neolithic and others added 5 commits June 23, 2026 16:51
beta:push now uploads the Claude memory files
(~/.claude/projects/<project>/memory/*.md) of every project amikalog has
captured Claude sessions for, under the same "<repo>/" key prefix as that
project's sessions ("<repo>/memory/<file>.md").

Memory files are edited in place, unlike append-only session JSONL, so they
can diverge between this machine and the cloud copy other machines pushed. A
dedicated manifest records each file's last-synced content hash and a 3-way
rule decides per file: no cloud copy or only-local change uploads, only-cloud
change pulls the cloud copy down, identical skips, and a file changed on both
sides is merged with the host claude CLI, written back locally, and uploaded.
A failed or unavailable merge never clobbers either side; if claude is not
installed, diverged files are skipped with a warning while the rest upload.

Adds eventlog.Downloader, apiclient.GetObjectByKey for single-object reads,
and a --skip-memories flag.
Uploading Claude memory files is now off by default: beta:push uploads only
captured events unless --memories is passed. This keeps memory upload behind an
explicit flag while it is being tested, before considering it as a default.

Add --all-projects (requires --memories) to also upload memory for projects
that have no captured amikalog session. The repository prefix for such a project
is recovered from its own Claude transcript working directory and that
directory's git repo, falling back to "unknown-repo".

Replaces the previous --skip-memories flag.
GetObjectByKey listed the downloads endpoint with the full object key as
the `prefix`, then exact-matched. The storage backend treats a listing
prefix as a folder path, so a prefix that includes the filename matches
nothing and the lookup always reported found=false.

That made `amikalog beta:push --memories` re-upload every memory file on
every run: reconcileMemory always took the "no cloud copy yet" branch
because the cloud read-back never found the object, regardless of the
local push manifest. Session/event uploads were unaffected because they
dedup via the byte-size manifest and never call GetObjectByKey.

List the object's parent folder (up to and including the final "/") and
exact-match within it. Add regression tests that fake the downloads
endpoint with folder-prefix semantics; they fail against the old
full-key listing and pass with the fix.
Reworks the memory-sync path added in this PR so a divergence never runs an
agent or clobbers data unless the operator opts in.

- Object keys gain the source segment, matching the sessions layout:
  <repo>/claude/memory/<relpath> instead of <repo>/memory/<relpath>, so a
  repo's memory sits under the same <repo>/claude/ prefix as its events.

- beta:push --memories now skips a file that changed on both sides and warns,
  leaving both copies intact, instead of auto-merging. The new --merge flag
  opts into reconciliation; reconcileMemory returns ErrMergeRequired when a
  both-sides divergence is hit without it, which PushMemories reports as a
  skipped-with-warning file.

- The claude merge runs with --permission-mode dontAsk by default, so any tool
  call the model attempts (e.g. coaxed by hostile memory content) is denied
  rather than executed. NewClaudeMerger takes an explicit
  dangerouslySkipPermissions; the new --dangerously-skip-permissions flag
  (requires --merge) restores the old bypass behavior as a documented opt-in.

Tests updated for the new signatures and key layout, plus a case asserting a
both-sides divergence without --merge skips without invoking the merger or
touching either copy.
@dbmikus

dbmikus commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Note, this PR forked from #255

@dbmikus

dbmikus commented Jun 26, 2026 •

Copy link
Copy Markdown
Contributor Author

@jdc123 I don't think we need to do any --dangerously-skip-permissions

You should be able to just do

--permission-mode <mode>              Permission mode to use for the session
                                        (choices: "acceptEdits", "auto",
                                        "bypassPermissions", "default",
                                        "dontAsk", "plan")

Set to --permission-mode acceptEdits

Also, I think Claude has some sandboxing stuff that stop it from editing files outside of the cwd, so depending on that might have to either cd to the directory being modified, or create a tmp directory with both the version A and version B memories and make the merge there. The tmpdir is probably cleaner, so it doesn't leave behind broken stuff

(if we already turned off --dangerously-skip-permissions, then my bad for missing it; I was just reading the commit message)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8947660715

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +123 to +126
case r >= 'a' && r <= 'z', r >= 'A' && r <= 'Z', r >= '0' && r <= '9':
return r
default:
return '-'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve dots and underscores in Claude project slugs

For captured projects whose cwd contains characters Claude leaves in the ~/.claude/projects slug, such as /work/my_app or /work/api.v2, this maps _ and . to - and then scans a directory Claude never writes. In the default --memories mode that makes those projects silently skip memory sync even though amikalog has captured sessions for them; the slug computation should match Claude's path encoding instead of replacing every non-alnum character.

Useful? React with 👍 / 👎.

// scanned; a project with no captured session has its repository prefix recovered
// from its own Claude transcript (see repoSegmentForProjectDir).
func collectMemoryUnits(stateDir, home string, allProjects bool) ([]memoryUnit, error) {
projectsRoot := filepath.Join(home, ".claude", "projects")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Respect CLAUDE_CONFIG_DIR for memory sync

When a user runs Claude Code with CLAUDE_CONFIG_DIR set, Claude stores projects/<project>/memory under that directory rather than under ~/.claude (the Claude docs say every ~/.claude path moves there). This hard-coded root makes amikalog beta:push --memories scan the wrong tree, so those users upload nothing or stale files from the default location; derive the Claude config root from CLAUDE_CONFIG_DIR before falling back to home/.claude.

Useful? React with 👍 / 👎.

dbmikus pushed a commit that referenced this pull request Oct 23, 2026
Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 5.0.0 to 6.1.0.

## Release notes

Sourced from pnpm/action-setup's releases.

### v6.1.0

### What's Changed
- feat: support pnpm v12 by `@zkochan` in pnpm/action-setup#288

Full Changelog: pnpm/action-setup@v6.0.10...v6.1.0

### v6.0.10

### What's Changed
- docs(README): point users to the successor pnpm/setup action by `@BlackHole1` in pnpm/action-setup#282
- refactor: introduce restore keys for cache by `@SukkaW` in pnpm/action-setup#280
- ci: use pnpm 11 for `pr-check` by `@jamietanna` in pnpm/action-setup#284
- fix: update pnpm to v11.19.0 by `@jamietanna` in pnpm/action-setup#283
- docs: update README to include devEngines.packageManager by `@nemchik` in pnpm/action-setup#273

### New Contributors
- `@jamietanna` made their first contribution in pnpm/action-setup#284
- `@nemchik` made their first contribution in pnpm/action-setup#273

Full Changelog: pnpm/action-setup@v6...v6.0.10

### v6.0.9

### What's Changed
- fix: update pnpm to v11.7.0 by `@zkochan` in pnpm/action-setup#267

Full Changelog: pnpm/action-setup@v6...v6.0.9

### v6.0.8

### What's Changed
- docs(README): fix `cache_dependency_path` type by `@haines` in pnpm/action-setup#257
- fix: drop patchPnpmEnv so standalone+self-update works on Windows by `@zkochan` in pnpm/action-setup#258
- fix: update pnpm to 11.1.1 by `@mungodewar` in pnpm/action-setup#248

### New Contributors
- `@mungodewar` made their first contribution in pnpm/action-setup#248

Full Changelog: pnpm/action-setup@v6.0.7...v6.0.8

### v6.0.7

### What's Changed
- fix: honor devEngines.packageManager.onFail=error (#252) by `@zkochan` in pnpm/action-setup#254
- fix: restore inputs from state in post by `@haines` in pnpm/action-setup#255
- fix: self-update bootstrap to packageManager-pinned version (#233) by `@zkochan` in pnpm/action-setup#256

### New Contributors
- `@haines` made their first contribution in pnpm/action-setup#255

Full Changelog: pnpm/action-setup@v6.0.6...v6.0.7

... (truncated)

## Commits
- `ea17c68` feat: support pnpm v12 (#288)
- `0977fd9` docs: Update README to include devEngines.packageManager (#273)
- `48261ac` fix: update pnpm to v11.19.0 (#283)
- `75677f7` ci: use pnpm 11 for `pr-check` (#284)
- `769ae71` refactor: introduce restore keys for cache (#280)
- `6fed91f` docs(README): point users to the successor pnpm/setup action (#282)
- `0ebf471` fix: update pnpm to v11.7.0 (#267)
- `0e279bb` fix: update pnpm to 11.1.1 (#248)
- `3e83581` fix: drop patchPnpmEnv so standalone+self-update works on Windows (#258)
- `551b42e` docs(README): fix `cache_dependency_path` type (#257)
- Additional commits viewable in compare view

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants