diff --git a/packages/agent-memory-sync/docs/machine-setup.md b/packages/agent-memory-sync/docs/machine-setup.md index a3970b5..3947814 100644 --- a/packages/agent-memory-sync/docs/machine-setup.md +++ b/packages/agent-memory-sync/docs/machine-setup.md @@ -77,7 +77,8 @@ This document wires together the pieces already documented individually must be running on every fallback machine. Machine-specific values (paths, SSH alias) are committed as profile files -under `profiles/`: `profiles/macbook.json`, `profiles/mac-mini.json`, and a +under `profiles/`: `profiles/macbook.json`, `profiles/mac-mini.json`, +`profiles/linux.json` (the Linux desktop set up via (c) below), and a template for further machines, `profiles/linux.example.json`. Each profile file documents its own placeholders and the namespace-divergence gotcha in its `"//"` field — read the profile you're activating before copying @@ -331,7 +332,8 @@ bullet at the top of this document. ## e) machine-state payload (toolchain snapshots) -Every committed profile (`profiles/mac-mini.json`, `profiles/macbook.json`) +Every committed machine profile (`profiles/mac-mini.json`, +`profiles/macbook.json`, `profiles/linux.json`) carries a **second, independent** `syncPaths` entry alongside the `memory` one described at the top of this document: @@ -399,11 +401,11 @@ exist ahead of any sync. ## f) frictions payload (friction-log exports) Every committed profile (`profiles/mac-mini.json`, `profiles/macbook.json`, -`profiles/linux.example.json`) also carries an **independent** `syncPaths` -entry pointing at `~/.harness/frictions` — the third entry in -`mac-mini.json`/`macbook.json` (after `memory` and `machine-state`), and -the second in `linux.example.json` (that template does not yet include a -`machine-state` entry): +`profiles/linux.json`, `profiles/linux.example.json`) also carries an +**independent** `syncPaths` entry pointing at `~/.harness/frictions` — the +third entry in `mac-mini.json`/`macbook.json`/`linux.json` (after `memory` +and `machine-state`), and the second in `linux.example.json` (that template +does not yet include a `machine-state` entry): ```json { "source": "/Users//.harness/frictions", "destination": "frictions", "kind": "directory" } diff --git a/packages/agent-memory-sync/profiles/linux.json b/packages/agent-memory-sync/profiles/linux.json new file mode 100644 index 0000000..274f6a8 --- /dev/null +++ b/packages/agent-memory-sync/profiles/linux.json @@ -0,0 +1,51 @@ +{ + "//": [ + "Machine profile: Linux desktop (WSL2, DESKTOP-9TDLGAR) — fallback", + "machine. The Mac mini is the single source of truth (see mac-mini.json);", + "this machine pulls via the periodic sync timer and pushes debounced", + "snapshots via `watch`. Filled in from linux.example.json — read that", + "template's '//' field for the full rationale; the load-bearing invariants", + "restated inline: the memory entry's destination must be the literal", + "'memory', never '.' (a '.' destination is silently unmappable on", + "pull/restore); stateDir must stay OUTSIDE rootDir (the '.' walk would", + "otherwise sync the tool's own state); rootDir/stateDir are absolute,", + "the loader performs no tilde expansion. reachabilityTimeoutMs is 10000", + "like macbook.json (ssh-reached spoke), not the template's 5000.", + "", + "repositorySubdir MUST stay the fixed literal 'pandora', identical on", + "every machine sharing the remote — a per-machine value silently", + "partitions the bare repo into disjoint trees (happened before, caught by", + "a live cross-machine E2E test). See the template / machine-setup.md.", + "", + "rootDir is this machine's own Claude Code slug, read off", + "`ls ~/.claude/projects/` HERE (encodes OS user 'lan' + checkout path", + "/home/lan/git/pandora) — never copied from another machine's profile.", + "", + "Deviation from linux.example.json, deliberate: a third syncPaths entry", + "for machine-state (absolute source ~/.harness/machine-state), which the", + "template does not yet carry (noted in machine-setup.md section f) —", + "without it this machine is invisible to the toolchain-parity check.", + "Producer: `harness session-start toolchain-parity`; convention is", + "owner-writes-only, one file per machine (machine-state/linux.json).", + "", + "frictions producer: friction-log sync_export in", + "~/.config/friction-log/config.yml writes ~/.harness/frictions/linux.json.", + "", + "Activation: pass BOTH --config (this file) and the profile name", + "positionally:", + " agent-memory-sync run linux --config profiles/linux.json" + ], + "profile": "linux", + "rootDir": "/home/lan/.claude/projects/-home-lan-git-pandora/memory", + "remoteUrl": "mini:~/memory-sync/pandora-memory.git", + "branch": "main", + "repositorySubdir": "pandora", + "stateDir": "/home/lan/.agent-memory-sync/linux", + "conflictStrategy": "inline-markers", + "reachabilityTimeoutMs": 10000, + "syncPaths": [ + { "source": ".", "destination": "memory", "kind": "directory" }, + { "source": "/home/lan/.harness/machine-state", "destination": "machine-state", "kind": "directory" }, + { "source": "/home/lan/.harness/frictions", "destination": "frictions", "kind": "directory" } + ] +} diff --git a/packages/agent-memory-sync/tests/integration/cross-machine-profiles.test.ts b/packages/agent-memory-sync/tests/integration/cross-machine-profiles.test.ts index c06bfc9..a725393 100644 --- a/packages/agent-memory-sync/tests/integration/cross-machine-profiles.test.ts +++ b/packages/agent-memory-sync/tests/integration/cross-machine-profiles.test.ts @@ -126,16 +126,16 @@ test("macbook and mac-mini profiles share one remote tree and see each other's p ); }); -test("profiles/macbook.json, profiles/mac-mini.json, and profiles/linux.example.json all declare the same repositorySubdir", () => { +test("all committed profiles (macbook, mac-mini, linux, linux.example) declare the same repositorySubdir", () => { // A narrower, faster companion to the end-to-end test above: pins the // specific config field that caused the divergence directly against the // committed files, independent of any CLI/git plumbing. Includes // linux.example.json — the copy-paste source for any new machine — so a // future template edit that reintroduces a per-machine placeholder (as // this template originally had, mirroring the pre-fix macbook/mac-mini - // profiles) is caught here too, not just on the two profiles already in + // profiles) is caught here too, not just on the profiles already in // active use. - const profileFiles = ["macbook.json", "mac-mini.json", "linux.example.json"]; + const profileFiles = ["macbook.json", "mac-mini.json", "linux.json", "linux.example.json"]; const settingsByFile = Object.fromEntries( profileFiles.map((file) => [file, JSON.parse(readText(path.join(PROFILES_DIR, file)))]) ); @@ -196,9 +196,10 @@ test("profiles/macbook.json, profiles/mac-mini.json, and profiles/linux.example. } // Same pin for the pre-existing machine-state entry, closing the identical - // #64 coverage gap — macbook.json and mac-mini.json only, since - // linux.example.json's template has never carried a machine-state entry. - for (const file of ["macbook.json", "mac-mini.json"]) { + // #64 coverage gap — every committed machine profile, but not + // linux.example.json, since the template has never carried a machine-state + // entry (linux.json adds it deliberately; see machine-setup.md section f). + for (const file of ["macbook.json", "mac-mini.json", "linux.json"]) { const machineStateEntries = findEntriesByDestination(settingsByFile[file].syncPaths, "machine-state"); assert.equal( machineStateEntries.length,