commuter 0.1.0__tar.gz

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.
@@ -0,0 +1,13 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(head:*)",
5
+ "Bash(tail:*)",
6
+ "Bash(pip install:*)",
7
+ "Bash(python:*)",
8
+ "Bash(python3:*)",
9
+ "Bash(/home/ljubomir/uhidef/bin/pip install:*)",
10
+ "Bash(/home/ljubomir/uhidef/bin/python3:*)"
11
+ ]
12
+ }
13
+ }
@@ -0,0 +1,207 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+ #poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ #pdm.lock
116
+ #pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ #pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # SageMath parsed files
135
+ *.sage.py
136
+
137
+ # Environments
138
+ .env
139
+ .envrc
140
+ .venv
141
+ env/
142
+ venv/
143
+ ENV/
144
+ env.bak/
145
+ venv.bak/
146
+
147
+ # Spyder project settings
148
+ .spyderproject
149
+ .spyproject
150
+
151
+ # Rope project settings
152
+ .ropeproject
153
+
154
+ # mkdocs documentation
155
+ /site
156
+
157
+ # mypy
158
+ .mypy_cache/
159
+ .dmypy.json
160
+ dmypy.json
161
+
162
+ # Pyre type checker
163
+ .pyre/
164
+
165
+ # pytype static type analyzer
166
+ .pytype/
167
+
168
+ # Cython debug symbols
169
+ cython_debug/
170
+
171
+ # PyCharm
172
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
173
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
174
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
175
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
176
+ #.idea/
177
+
178
+ # Abstra
179
+ # Abstra is an AI-powered process automation framework.
180
+ # Ignore directories containing user credentials, local state, and settings.
181
+ # Learn more at https://abstra.io/docs
182
+ .abstra/
183
+
184
+ # Visual Studio Code
185
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
188
+ # you could uncomment the following to ignore the entire vscode folder
189
+ # .vscode/
190
+
191
+ # Ruff stuff:
192
+ .ruff_cache/
193
+
194
+ # PyPI configuration file
195
+ .pypirc
196
+
197
+ # Cursor
198
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
199
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
200
+ # refer to https://docs.cursor.com/context/ignore-files
201
+ .cursorignore
202
+ .cursorindexingignore
203
+
204
+ # Marimo
205
+ marimo/_static/
206
+ marimo/_lsp/
207
+ __marimo__/
commuter-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ljbuturovic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,9 @@
1
+ Metadata-Version: 2.4
2
+ Name: commuter
3
+ Version: 0.1.0
4
+ Summary: Portable AI coding session transfer between machines
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: click>=8.0
9
+ Requires-Dist: rich>=13.0
File without changes
@@ -0,0 +1,409 @@
1
+ # commuter: Portable AI Coding Session Transfer
2
+
3
+ ## Problem
4
+
5
+ Claude Code's Remote Control feature lets you view a session from another device, but the session always runs on the original host machine. If that machine sleeps, loses network, or you want to work with local files on a different machine, you're stuck.
6
+
7
+ **Goal:** Enable true session migration between machines that share a synced filesystem (via Git, Dropbox, Syncthing, etc.). Export a coding session on Machine A, import it on Machine B, and continue working with full local file access on Machine B.
8
+
9
+ The initial implementation targets Claude Code. The architecture should be tool-agnostic so that future backends can support Codex CLI, Gemini CLI, and other AI coding tools.
10
+
11
+ ## User Experience Walkthrough
12
+
13
+ ### First-time setup (once per machine pair)
14
+
15
+ ```bash
16
+ # Install on BOTH machines
17
+ pip install commuter
18
+
19
+ # On each machine, tell it where your projects live
20
+ # Machine A (home desktop, Linux):
21
+ commuter config set path-map "/home/ljubomir/projects" "/Users/ljubomir/projects"
22
+
23
+ # Machine B (work laptop, macOS): same command
24
+ commuter config set path-map "/home/ljubomir/projects" "/Users/ljubomir/projects"
25
+ ```
26
+
27
+ That's it for setup. The path map tells the tool how to translate paths between your machines. If your paths are identical on both machines, you can skip this step entirely.
28
+
29
+ ### Daily workflow: Morning at home
30
+
31
+ You start working on your project at home:
32
+
33
+ ```bash
34
+ cd ~/projects/trivertiy-ml
35
+ claude
36
+
37
+ # ... work with Claude Code for an hour, build a new feature,
38
+ # debug a test failure, get deep into a conversation ...
39
+ ```
40
+
41
+ Time to leave for work. You want to continue this session on your office laptop.
42
+
43
+ ```bash
44
+ # See what sessions are available
45
+ commuter list
46
+
47
+ ID PROJECT LAST ACTIVE SUMMARY
48
+ a1b2c3d ~/projects/trivertiy-ml 2 min ago "Debug failing test in classifier module"
49
+ e4f5g6h ~/projects/learnio 3 days ago "Add new math lesson generator"
50
+
51
+ # Export the session you want to take with you
52
+ commuter export a1b2c3d -o ~/Dropbox/session.json
53
+
54
+ ✓ Exported session a1b2c3d (47 messages, 12KB)
55
+ ✓ Git snapshot: branch feature/new-classifier @ a1b2c3d (2 dirty files)
56
+ ✓ Saved to /home/ljubomir/Dropbox/session.json
57
+ ```
58
+
59
+ ### Commute
60
+
61
+ Your session file syncs to Dropbox automatically. You can check on your phone that it arrived if you're anxious, but there's nothing to do.
62
+
63
+ ### Arrive at office
64
+
65
+ ```bash
66
+ # Dropbox has already synced the file. Import it:
67
+ commuter import ~/Dropbox/session.json
68
+
69
+ ✓ Detected project: /home/ljubomir/projects/trivertiy-ml
70
+ ✓ Mapped to local path: /Users/ljubomir/projects/trivertiy-ml
71
+ ✓ Git check: branch feature/new-classifier @ a1b2c3d ✓ (matches export)
72
+ ⚠ 2 dirty files in export not present locally — did you commit before leaving?
73
+ - src/model.py
74
+ - tests/test_model.py
75
+ ✓ Restored conversation (47 messages)
76
+ ✓ Restored project config (.claude/settings.json, CLAUDE.md)
77
+
78
+ Launching Claude Code with restored session...
79
+ ```
80
+
81
+ Claude Code opens. It has the full conversation context — it remembers everything you discussed, the files you edited, the decisions you made. But now it's running locally on your office laptop, reading and writing your local files.
82
+
83
+ You pick up exactly where you left off:
84
+
85
+ ```
86
+ You: Let's continue with the test fix. What was the last error we saw?
87
+ Claude: We were debugging the assertion failure in test_classifier.py line 42...
88
+ ```
89
+
90
+ ### End of day: Back home (round-trip)
91
+
92
+ You worked all day at the office. Now you want to continue at home tonight.
93
+
94
+ ```bash
95
+ # At office, leaving:
96
+ commuter export --latest -o ~/Dropbox/session.json
97
+
98
+ ✓ Exported session a1b2c3d (112 messages, 28KB)
99
+ ✓ Saved to /Users/ljubomir/Dropbox/session.json
100
+ ```
101
+
102
+ Commute home. At your home desktop:
103
+
104
+ ```bash
105
+ commuter import ~/Dropbox/session.json
106
+
107
+ ✓ Detected project: /Users/ljubomir/projects/trivertiy-ml
108
+ ✓ Mapped to local path: /home/ljubomir/projects/trivertiy-ml
109
+ ✓ Session continuity: imported session is a continuation of local session a1b2c3d
110
+ Local: 47 messages (exported 10h ago)
111
+ Imported: 112 messages (last active 20 min ago)
112
+ ✓ Replacing local session with imported version
113
+ ✓ Restored conversation (112 messages)
114
+
115
+ Launching Claude Code with restored session...
116
+ ```
117
+
118
+ When the imported session is a **continuation** of an existing local session (the imported conversation starts with the same messages as the local one, just has more), the tool replaces it automatically without prompting. This is the expected round-trip case.
119
+
120
+ Use `--replace` to force replacement when continuity can't be auto-detected:
121
+
122
+ ```bash
123
+ commuter import ~/Dropbox/session.json --replace
124
+ ```
125
+
126
+ ### Shortcut version (stretch goal)
127
+
128
+ If you configure a shared transfer directory:
129
+
130
+ ```bash
131
+ commuter config set transfer-dir ~/Dropbox/.commuter/
132
+
133
+ # Then every day:
134
+ commuter push # exports latest session to transfer dir
135
+ commuter pull # imports from transfer dir, replaces if continuation
136
+ ```
137
+
138
+ Push/pull defaults to `--replace` behavior since the entire point is frictionless round-trips.
139
+
140
+ ### Error cases the user might hit
141
+
142
+ **Git state mismatch:**
143
+ ```bash
144
+ commuter import ~/Dropbox/session.json
145
+
146
+ ⚠ WARNING: Git state differs from export
147
+ Export: feature/new-classifier @ a1b2c3d
148
+ Local: main @ f7g8h9i
149
+ Continue anyway? Claude will have context from a different branch. [y/N]
150
+ ```
151
+
152
+ **Project not found:**
153
+ ```bash
154
+ commuter import ~/Dropbox/session.json
155
+
156
+ ✗ Project path /home/ljubomir/projects/trivertiy-ml not found
157
+ ✗ No path mapping matched
158
+ Specify local project directory:
159
+ commuter import ~/Dropbox/session.json --project-dir /path/to/project
160
+ ```
161
+
162
+ **Unrelated session already exists (NOT a continuation):**
163
+ ```bash
164
+ commuter import ~/Dropbox/session.json
165
+
166
+ ⚠ A different session already exists for this project (last active 15 min ago)
167
+ Local session has divergent conversation history — this is not a continuation.
168
+ Overwrite local session with imported one? [y/N]
169
+ ```
170
+
171
+ ## Assumptions
172
+
173
+ - The project filesystem is already replicated across machines (Git, Dropbox, or similar). The tool does NOT handle file sync.
174
+ - Claude Code is installed on both machines.
175
+ - The user has the same Claude Code authentication on both machines.
176
+ - Paths to the project directory may differ between machines (e.g., `/home/user/projects/foo` on Linux vs `/Users/user/projects/foo` on macOS).
177
+
178
+ ## Architecture
179
+
180
+ A standalone Python CLI tool distributed via PyPI. No dependency on Claude Code internals beyond the session storage format. The tool operates in three phases: discover, export, import.
181
+
182
+ The session discovery, export, and import logic should be isolated behind a **backend interface** so that future backends (Codex CLI, Gemini CLI, etc.) can be added without changing the CLI or bundle format. The initial implementation provides only the Claude Code backend.
183
+
184
+ ## Core Features
185
+
186
+ ### 1. Session Discovery
187
+
188
+ ```bash
189
+ commuter list
190
+ ```
191
+
192
+ - Discover and list all Claude Code sessions on the current machine.
193
+ - Show: session ID, project directory, last activity timestamp, conversation summary (first/last message preview).
194
+ - Research where Claude Code stores session data. Likely locations:
195
+ - `~/.claude/` or `~/.config/claude-code/`
196
+ - Project-local `.claude/` directory
197
+ - Check both, document findings.
198
+
199
+ ### 2. Session Export
200
+
201
+ ```bash
202
+ commuter export [session-id] -o session-bundle.json
203
+ commuter export --latest -o session-bundle.json
204
+ ```
205
+
206
+ Export a session into a portable JSON bundle containing:
207
+
208
+ - **Conversation history**: The full message log (user messages, assistant responses, tool calls and results).
209
+ - **Project path**: The original absolute path to the working directory.
210
+ - **Project config**: Contents of relevant config files (`.claude/settings.json`, `CLAUDE.md`, `.claude/commands/` if present).
211
+ - **Git state** (if applicable): Current branch, commit hash, dirty file list (as a reference snapshot, not the files themselves).
212
+ - **Environment metadata**: OS, Claude Code version, timestamp, hostname.
213
+ - **Session config**: Any session-specific settings (model, permissions, MCP server configs).
214
+ - **Lineage info**: A hash of the first N messages in the conversation, used to detect whether an imported session is a continuation of a local one (see Session Continuity below).
215
+
216
+ The bundle should be a single JSON file, human-readable, reasonably compact. Use gzip compression as an option for large sessions.
217
+
218
+ ```bash
219
+ commuter export --latest -o session-bundle.json.gz --compress
220
+ ```
221
+
222
+ ### 3. Session Import
223
+
224
+ ```bash
225
+ commuter import session-bundle.json [--project-dir /path/to/local/project]
226
+ ```
227
+
228
+ - Reconstruct the session on the target machine.
229
+ - If `--project-dir` is not specified, attempt to auto-detect: check if the original path exists, then try common path substitutions (see Path Mapping below).
230
+ - Inject the conversation history so Claude Code can resume with full context.
231
+ - Restore project config files to the local `.claude/` directory (with confirmation prompt if files already exist).
232
+ - Validate that the local project state is compatible: warn if the git branch or commit differs from the export snapshot.
233
+ - Launch Claude Code with the restored session using `--resume` or `--continue` (determine which flag is appropriate).
234
+
235
+ **Flags:**
236
+ - `--replace`: Force replacement of an existing local session without prompting.
237
+ - `--no-launch`: Import the session but don't launch Claude Code.
238
+ - `--dry-run`: Show what would happen without making changes.
239
+
240
+ ### 4. Session Continuity Detection
241
+
242
+ When importing, the tool checks whether a session for the same project already exists locally. If it does, it computes whether the imported session is a **continuation** of the local one:
243
+
244
+ - Compute a hash of the first N messages (e.g., first 10) in both the local and imported conversations.
245
+ - If the hashes match and the imported session has MORE messages, it's a continuation → replace automatically.
246
+ - If the hashes don't match, the sessions have diverged → prompt for confirmation (unless `--replace` is set).
247
+ - If no local session exists for that project → import directly, no prompt needed.
248
+
249
+ This makes the daily home → office → home round-trip seamless: no confirmation prompts, no flags needed.
250
+
251
+ ### 5. Path Mapping
252
+
253
+ ```bash
254
+ commuter config set path-map "/home/ljubomir/projects" "/Users/ljubomir/projects"
255
+ commuter config set path-map "/home/ljubomir/Dropbox" "/Users/ljubomir/Dropbox"
256
+ ```
257
+
258
+ - Store path mappings in `~/.config/commuter/config.json`.
259
+ - Applied automatically during import to translate paths in the session bundle.
260
+ - Bidirectional: the tool infers direction based on which side matches the imported path.
261
+ - Support multiple mappings, applied in order of specificity (longest prefix first).
262
+
263
+ ### 6. Session Transfer Shortcut (stretch goal)
264
+
265
+ ```bash
266
+ # On source machine:
267
+ commuter push # exports latest to configured transfer dir
268
+
269
+ # On target machine:
270
+ commuter pull # imports from transfer dir, auto-replaces continuations
271
+ ```
272
+
273
+ - Requires `transfer-dir` to be configured: `commuter config set transfer-dir ~/Dropbox/.commuter/`
274
+ - `push` exports the most recent session to `<transfer-dir>/pending/`.
275
+ - `pull` imports from `<transfer-dir>/pending/` and moves the bundle to `<transfer-dir>/history/` after successful import.
276
+ - `pull` defaults to `--replace` behavior for continuations.
277
+ - History directory provides an audit trail and rollback capability.
278
+
279
+ ## CLI Design
280
+
281
+ - Built with `click` or `argparse` (prefer `click`).
282
+ - Colored terminal output using `rich` for session listings and status messages.
283
+ - Confirmation prompts before overwriting existing config or sessions (unless auto-detected as continuation).
284
+ - `--dry-run` flag on import to show what would be changed without doing it.
285
+ - `--verbose` / `-v` flag for debug output.
286
+ - `--quiet` / `-q` flag for script-friendly output.
287
+
288
+ ## Session Bundle Schema
289
+
290
+ ```json
291
+ {
292
+ "version": "1.0",
293
+ "tool": "commuter",
294
+ "backend": "claude-code",
295
+ "exported_at": "2026-03-03T10:30:00Z",
296
+ "source": {
297
+ "hostname": "home-desktop",
298
+ "os": "Linux",
299
+ "backend_version": "1.x.x",
300
+ "username": "ljubomir"
301
+ },
302
+ "session": {
303
+ "id": "abc123",
304
+ "project_dir": "/home/ljubomir/projects/trivertiy-ml",
305
+ "started_at": "2026-03-03T09:00:00Z",
306
+ "last_activity": "2026-03-03T10:25:00Z",
307
+ "message_count": 47,
308
+ "lineage_hash": "sha256:abcdef1234...",
309
+ "conversation": [
310
+ // Full conversation history array
311
+ ],
312
+ "config": {
313
+ "settings_json": {},
314
+ "claude_md": "contents of CLAUDE.md",
315
+ "commands": {}
316
+ }
317
+ },
318
+ "git_snapshot": {
319
+ "branch": "feature/new-classifier",
320
+ "commit": "a1b2c3d",
321
+ "dirty_files": ["src/model.py", "tests/test_model.py"]
322
+ }
323
+ }
324
+ ```
325
+
326
+ ## Research Tasks (Do First)
327
+
328
+ Before writing code, investigate and document:
329
+
330
+ 1. **Where does Claude Code store session/conversation data?** Check `~/.claude/`, `~/.config/claude-code/`, project `.claude/` dirs, and any SQLite databases or JSON files.
331
+ 2. **What format is the conversation history in?** Need to understand the schema to export/import it correctly.
332
+ 3. **What CLI flags does Claude Code support for resuming sessions?** Test `--resume`, `--continue`, and any other relevant flags. Determine if there's a way to inject conversation history programmatically.
333
+ 4. **Is the session data self-contained or does it reference external state?** (e.g., API-side session IDs that can't be transferred)
334
+
335
+ If Claude Code stores sessions server-side and there's no local conversation log, the approach needs to change: we'd capture the conversation via a wrapper/proxy instead. Document findings before proceeding with implementation.
336
+
337
+ ## Tech Stack
338
+
339
+ - Python 3.10+
340
+ - `click` for CLI
341
+ - `rich` for terminal formatting
342
+ - No other heavy dependencies
343
+ - Standard library for JSON, gzip, pathlib, hashlib, etc.
344
+
345
+ ## Distribution
346
+
347
+ - Package name: `commuter`
348
+ - Published to PyPI
349
+ - Installable via: `pip install commuter`
350
+ - Entry point: `commuter` command
351
+ - License: MIT
352
+
353
+ ## Project Structure
354
+
355
+ ```
356
+ commuter/
357
+ ├── pyproject.toml
358
+ ├── README.md
359
+ ├── LICENSE
360
+ ├── src/
361
+ │ └── commuter/
362
+ │ ├── __init__.py
363
+ │ ├── cli.py # Click CLI entry point
364
+ │ ├── config.py # User config management
365
+ │ ├── bundle.py # Bundle schema, validation, versioning
366
+ │ ├── pathmap.py # Path mapping config and translation
367
+ │ ├── lineage.py # Session continuity detection
368
+ │ ├── git_utils.py # Git state snapshot
369
+ │ └── backends/
370
+ │ ├── __init__.py # Backend interface / base class
371
+ │ └── claude_code.py # Claude Code: discover, export, import
372
+ ├── tests/
373
+ │ ├── test_cli.py
374
+ │ ├── test_bundle.py
375
+ │ ├── test_pathmap.py
376
+ │ ├── test_lineage.py
377
+ │ ├── test_claude_code.py
378
+ │ └── fixtures/ # Sample session data for testing
379
+ └── .claude/
380
+ └── CLAUDE.md # This file, for Claude Code context
381
+ ```
382
+
383
+ ## Testing
384
+
385
+ - Use `pytest`.
386
+ - Mock Claude Code session data in fixtures (based on findings from Research Tasks).
387
+ - Test path mapping with Linux ↔ macOS path patterns.
388
+ - Test path mapping bidirectionality (A→B and B→A with same config).
389
+ - Test git snapshot validation (matching vs. diverged states).
390
+ - Test bundle schema validation and version compatibility.
391
+ - Test export → import round-trip preserves all data.
392
+ - Test session continuity detection: continuation (auto-replace), divergence (prompt), no existing session (direct import).
393
+ - Test push/pull with mock transfer directory.
394
+
395
+ ## Out of Scope (for now)
396
+
397
+ - File synchronization between machines (user's responsibility).
398
+ - Multi-user session sharing.
399
+ - Running process migration (only conversation + config state).
400
+ - MCP server auto-configuration on the target machine (document what MCP servers were active; user sets them up).
401
+ - Non-Claude-Code backends (architecture supports them; implementation is future work).
402
+
403
+ ## Success Criteria
404
+
405
+ 1. Export a session on Machine A where I've been working for 30+ minutes with Claude Code.
406
+ 2. Import it on Machine B (which has the same project via Git/Dropbox).
407
+ 3. Claude Code on Machine B has full conversation context and continues working seamlessly, with local file access on Machine B.
408
+ 4. Export from Machine B at end of day, import back on Machine A — round-trip works without prompts.
409
+ 5. The whole transfer takes under 30 seconds.
@@ -0,0 +1,24 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "commuter"
7
+ version = "0.1.0"
8
+ description = "Portable AI coding session transfer between machines"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.10"
12
+ dependencies = [
13
+ "click>=8.0",
14
+ "rich>=13.0",
15
+ ]
16
+
17
+ [project.scripts]
18
+ commuter = "commuter.cli:cli"
19
+
20
+ [tool.hatch.build.targets.wheel]
21
+ packages = ["src/commuter"]
22
+
23
+ [tool.pytest.ini_options]
24
+ testpaths = ["tests"]
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"