agent-carry 0.1.0 → 0.1.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ - `agent-carry` works as a second command name for `carry`.
6
+ - README trimmed; plugin author set.
7
+
3
8
  ## 0.1.0
4
9
 
5
10
  First release. Claude Code adapter.
package/README.md CHANGED
@@ -1,156 +1,76 @@
1
1
  # agent-carry
2
2
 
3
- Move a coding-agent session to another machine, or another folder, and keep working.
4
-
5
- **Agents:** Claude Code is supported today. Every bundle records which agent it came from (`agent` in the header),
6
- so other agents can be added as adapters without changing the format; a build that doesn't know an agent refuses
7
- its bundles with a clear error instead of guessing. Codex is the intended next adapter and is **not implemented yet**.
8
-
9
- For Claude Code: it keeps each session in `~/.claude/projects/<folder>/<id>.jsonl`, where `<folder>` is the project's
10
- absolute path with every non-alphanumeric character turned into `-`. The transcript itself is full of absolute
11
- paths (about three quarters of the lines in a typical one). Copy the file to another machine and `--resume` can't
12
- find it, and if you force it, every path in the history points at a machine that isn't there.
13
-
14
- `carry` makes a session portable:
15
-
16
- - **Path-portable.** Your project root, home directory and session-store path become tokens on export and are
17
- rewritten for the target machine on import. Object keys too: file-history snapshots are maps keyed by path.
18
- - **Merge-safe.** Records have stable `uuid`s, so import is a union, not an overwrite. Importing twice changes
19
- nothing, and a session that continued on two machines becomes a two-branch history instead of a conflict.
20
- The local file is the source of truth: its lines are kept byte for byte.
21
- - **Redacted.** Credential-shaped strings (cloud keys, tokens, JWTs, private keys, `*_SECRET=...`, URL passwords)
22
- are removed before anything is written. The export prints what it removed.
23
- - **Complete.** Subagent transcripts and offloaded tool results travel with the session, and the references to
24
- them are rewritten.
25
- - **Inspectable.** A bundle is newline-delimited JSON. `carry inspect` shows its header; `less` and `jq` show the rest.
3
+ Move a coding-agent session to another machine or folder and keep working. Supports Claude Code today.
4
+
5
+ Claude Code stores sessions per absolute project path, and the transcripts are full of absolute paths, so a
6
+ copied session can't be resumed elsewhere. `carry` fixes that:
7
+
8
+ - **Path-portable:** project, home and store paths become tokens on export and are rewritten on import.
9
+ - **Merge-safe:** import is a union by record `uuid`. Importing twice changes nothing; a session continued on two machines becomes a two-branch history.
10
+ - **Redacted:** credential-shaped strings (cloud keys, tokens, JWTs, private keys, `*_SECRET=...`, URL passwords) are removed on export, with a report.
11
+ - **Complete:** subagent transcripts and tool results travel with the session.
12
+ - **Inspectable:** a bundle is newline-delimited JSON (gzipped).
13
+
14
+ ## Usage
26
15
 
27
16
  ```
28
- npm i -g agent-carry
17
+ npm i -g agent-carry # installs `carry` (also available as `agent-carry`)
29
18
 
30
- # on machine A, in the project folder
19
+ # machine A, in the project folder
31
20
  carry list
32
21
  carry export --latest -o session.carry.gz
33
22
 
34
- # on machine B, in the same project (wherever it lives)
23
+ # machine B, in the same project (any path)
35
24
  carry import session.carry.gz
36
- claude --resume <id> # printed by import
25
+ claude --resume <id> # printed by import
37
26
  ```
38
27
 
39
- As a Claude Code plugin (`plugin/`): `/carry:share` and `/carry:pickup` wrap the same two commands.
28
+ Encrypt a bundle with `CARRY_PASSPHRASE` or `--passphrase-file FILE` (AES-256-GCM, scrypt key). Never pass the
29
+ passphrase as an argument.
40
30
 
41
- ### Keep machines in sync through any shared folder
31
+ ### Sync through a shared folder
42
32
 
43
- No server, account or key exchange: point both machines at a folder your existing sync tool already
44
- replicates (Syncthing, Dropbox, iCloud, a git working tree, a network share).
33
+ Point both machines at a folder your sync tool already replicates (Dropbox, iCloud, Syncthing, a git tree).
45
34
 
46
35
  ```
47
- export CARRY_PASSPHRASE='long passphrase' # optional: encrypts everything written
48
- carry push ~/Sync/carry # this project's sessions -> folder
49
- carry pull ~/Sync/carry # other devices' sessions -> this machine
36
+ carry push ~/Sync/carry # this project's sessions -> folder
37
+ carry pull ~/Sync/carry # other devices' sessions -> this machine
50
38
  ```
51
39
 
52
- Layout: `<dir>/<project>/<session-id>/<device>.carry.gz` (or `.carry.enc`). Every file has exactly one writer,
53
- so a sync tool never sees a conflict; `pull` unions the other devices' files into your local session. The
54
- project is identified by its git remote, not its path, so `~/work/app` and `D:\code\app` find each other. Push
55
- skips sessions that haven't changed, so the folder doesn't churn.
40
+ Projects are matched by git remote, not path. Each file has one writer, so there are no sync conflicts.
41
+
42
+ ### Claude Code plugin
43
+
44
+ `plugin/` adds `/carry:share` and `/carry:pickup`. With `CARRY_SYNC_DIR` set, bundled hooks pull on session
45
+ start and push on session end (hooks not yet exercised in a live Claude Code).
56
46
 
57
- With the plugin installed, set `CARRY_SYNC_DIR` and the bundled hooks pull on session start and push on session
58
- end. (Hooks are written to the plugin spec but I have not exercised them inside a live Claude Code yet.)
47
+ ## Commands
59
48
 
60
49
  | command | |
61
50
  |---|---|
62
- | `carry list [--all]` | sessions for this folder (or every folder) |
63
- | `carry export <id\|--latest> [-o FILE]` | build a bundle. `--no-redact`, `--redact-emails`, `--strip-thinking`, `--project-root DIR` |
64
- | `carry inspect FILE` | header: parts, redaction counts, warnings |
51
+ | `carry list [--all]` | sessions for this folder, or all |
52
+ | `carry export <id\|--latest> [-o FILE]` | `--no-redact`, `--redact-emails`, `--strip-thinking`, `--allow-thinking-secrets`, `--project-root DIR` |
53
+ | `carry inspect FILE` | header, parts, redaction counts |
65
54
  | `carry import FILE [--project-root DIR] [--dry-run]` | write into the target folder's session store |
66
- | `carry push DIR` / `carry pull DIR [--name P] [--dry-run] [--quiet]` | folder sync, described above |
67
-
68
- Passphrase: `CARRY_PASSPHRASE` or `--passphrase-file`. AES-256-GCM with a scrypt-derived key (node:crypto), header
69
- authenticated. Never pass a passphrase as an argument; it would land in shell history.
70
-
71
- `--claude-home` and `--home` override `~/.claude` and the home directory, which is how the tests run two
72
- machines in one process.
73
-
74
- ## Compared with ctxhop
75
-
76
- [ctxhop](https://github.com/CCCCY-ci/ctxhop) is the larger, more mature tool and solves a wider problem. If you
77
- want a continuously syncing, multi-device product with its own encrypted store, use it. Where the two differ
78
- (from reading its README and adapter source, not from running it):
79
-
80
- | | agent-carry | ctxhop |
81
- |---|---|---|
82
- | Scope | Claude Code sessions; share one, or sync a project through a folder | Claude Code + Codex, cross-agent switch, workspace and Git handoff, device authorisation, key rotation |
83
- | Setup | none for a file; a shared folder for sync | `init` with an S3/R2/directory backend, passphrase, device invites |
84
- | Runtime | Node, zero dependencies | Go binary, installers |
85
- | Paths inside commands, prose and tool output | rewritten (boundary-aware); 0 leaks on 1,150 real sessions | left alone by design (only known path fields and bare paths are tokenised), so source paths and usernames stay in the history |
86
- | Secrets inside transcript content | redacted before leaving the machine, with a report | not scanned; protected by encryption in transit and at rest |
87
- | Sharing with someone else | a single inspectable file | designed for your own authorised devices |
88
- | Inspectability | newline-delimited JSON, readable with `jq` | encrypted objects in a remote |
89
- | Platforms | macOS, Linux | adds Windows |
90
-
91
- So: carry is better when you want to *hand a session to someone*, keep secrets out of it, or sync with
92
- nothing but a folder. ctxhop is better for an always-on personal sync across many devices and agents.
93
-
94
- ## What is verified
95
-
96
- - `npm test`: 36 tests on synthetic two-machine setups: planted secrets and paths, merge, tampering, encryption, folder sync convergence.
97
- - `npm run check:real` round-trips every session in your own `~/.claude` into a temp store under a different
98
- root, read-only on the real one. On the author's 1,150 sessions (58k records): no record lost, no dangling
99
- parent that wasn't already dangling, no source path left outside thinking blocks, re-import byte-identical.
100
- The same run redacted 200+ credential-shaped strings, so the problem the redactor solves is not hypothetical.
101
-
102
- ## What is not verified, or not handled
103
-
104
- - **`claude --resume` on an imported session** is verified on one real session (900 KB, 418 paths rewritten,
105
- Claude Code 2.1.299): resumed from a folder it never ran in, it recalled its first request and reported the new
106
- working directory. That is one session on one version. Run `scripts/verify-resume.sh` on yours. The transcript
107
- format is internal and undocumented and can change; carry parses tolerantly and carries unknown lines through.
108
- - **Thinking blocks are signed**, so they are carried verbatim: not path-rewritten, not redacted. If one contains
109
- a credential-like string, export **refuses** unless you pass `--strip-thinking` (drop thinking blocks; resume
110
- with stripped thinking is untested) or `--allow-thinking-secrets`. `carry push` skips those sessions.
111
- - **Redaction is pattern-based and best effort.** It will not find a password that looks like a sentence, or a
112
- letters-only lower-case `password=correcthorse` (lower-case names need a digit in the value, to avoid mangling
113
- code like `token = parseToken(x)`). ALL_CAPS names like `DB_PASSWORD=` are always redacted. Base64 is only
114
- caught when it decodes to something the other rules catch. A bundle
115
- is not encrypted. Don't commit one to a public repo, and read `carry inspect` before sharing.
116
- - **Cowork / desktop**: not checked. If it stores sessions somewhere else, it needs its own adapter.
117
- - **Push re-uploads sessions you pulled** (one file per device, merged on pull), so folder size grows with devices x sessions.
118
- - **Windows paths** (drive letters, backslashes) are not handled. Folder names longer than ~200 characters may
119
- be shortened differently by Claude Code; import warns.
120
- - **File-history backups** (`~/.claude/file-history`, used for rewind) are not carried.
121
- - Relative traversal text like `../../Users/x` is tokenised for privacy, so it is cosmetically wrong after import.
122
-
123
- ## Verify resume yourself
55
+ | `carry push DIR` / `carry pull DIR` | folder sync (`--name`, `--dry-run`, `--quiet`) |
124
56
 
125
- ```
126
- node src/cli.js list --all # pick a session with real content
127
- sh scripts/verify-resume.sh <session-id-prefix>
128
- ```
129
-
130
- Exports the session, imports it into a throwaway folder, runs `claude -p --resume` there, and deletes both the
131
- folder and the imported copy. The original is only read. PASS means the answer matches that session's first
132
- request and names the new folder.
57
+ ## Limits
133
58
 
134
- ## Adding another agent
59
+ - **Resume** is verified on one real session (Claude Code 2.1.299); the transcript format is internal and can change. Run `scripts/verify-resume.sh <id>` to check yours.
60
+ - **Thinking blocks are signed**, so they travel verbatim. If one contains a credential-like string, export refuses unless you pass `--strip-thinking` (resume with stripped thinking is untested) or `--allow-thinking-secrets`. `push` skips such sessions.
61
+ - **Redaction is best effort.** It misses passwords that read like sentences and letters-only lowercase `password=word`. Read `carry inspect` before sharing, and encrypt anything you send to someone else.
62
+ - Not handled: Windows paths, Cowork/desktop sessions, file-history (rewind) backups.
63
+ - `push` re-uploads pulled sessions, so a sync folder grows with devices × sessions.
135
64
 
136
- Everything Claude-specific is in four small places: how a project maps to a session folder (`src/paths.js`), how a
137
- session and its sidecar files are found and read (`src/store.js`), how a transcript line is identified and
138
- summarised (`src/transcript.js`), and the `AGENT` constant stamped into bundles (`src/bundle.js`). Path rewriting,
139
- redaction, merging, encryption and folder sync work on parsed JSON and don't care which agent produced it.
140
- An adapter for Codex would supply those four pieces for its own session format.
141
-
142
- ## Layout
65
+ ## Development
143
66
 
144
67
  ```
145
- src/paths.js folder-key mangling, claude home
146
- src/portable.js path <-> token rewriting (boundary-aware, keys included, thinking skipped)
147
- src/redact.js secret patterns
148
- src/merge.js uuid union; local lines kept first
149
- src/store.js list / read a session and its sidecar files
150
- src/bundle.js build, read, import; integrity hash; path-traversal guard
151
- src/crypto.js passphrase encryption (scrypt + AES-256-GCM)
152
- src/sync.js push / pull over a shared folder
153
- src/cli.js carry
68
+ npm test # 36 tests, synthetic two-machine setups
69
+ npm run check:real # read-only round trip of your own ~/.claude sessions
154
70
  ```
155
71
 
156
- MIT.
72
+ To add an agent, supply its session-folder mapping (`src/paths.js`), session reader (`src/store.js`), transcript
73
+ record identity (`src/transcript.js`) and the `AGENT` constant (`src/bundle.js`). Path rewriting, redaction,
74
+ merging, encryption and sync are agent-independent. Codex is not implemented yet.
75
+
76
+ MIT
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "agent-carry",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Move coding-agent sessions between machines and folders: path-portable, redacted, encrypted, merge-safe bundles. Claude Code today; adapter-ready for Codex and others.",
5
5
  "type": "module",
6
6
  "bin": {
7
- "carry": "src/cli.js"
7
+ "carry": "src/cli.js",
8
+ "agent-carry": "src/cli.js"
8
9
  },
9
10
  "files": [
10
11
  "src",
@@ -2,6 +2,6 @@
2
2
  "name": "carry",
3
3
  "version": "0.1.0",
4
4
  "description": "Move coding-agent sessions between machines and folders: /carry:share exports a redacted, path-portable bundle, /carry:pickup imports one.",
5
- "author": { "name": "agent-carry contributors" },
5
+ "author": { "name": "Harsh Gajjar", "email": "harshgajjar2812@gmail.com" },
6
6
  "license": "MIT"
7
7
  }