teammate-sync 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,151 @@
1
+ Metadata-Version: 2.4
2
+ Name: teammate-sync
3
+ Version: 0.1.0
4
+ Summary: Cross-engineer Claude Code context sharing — type /share, your teammate queries your context.
5
+ Author-email: Om Divyatej <om@turgon.ai>
6
+ License: MIT
7
+ Project-URL: Homepage, https://omdivyatej.github.io/teammate-sync-site/
8
+ Project-URL: Source, https://github.com/omdivyatej/teammate-sync
9
+ Keywords: claude,claude-code,mcp,team,context,sharing
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development
18
+ Requires-Python: >=3.11
19
+ Description-Content-Type: text/markdown
20
+ Requires-Dist: mcp>=1.0.0
21
+ Requires-Dist: anthropic>=0.40.0
22
+ Requires-Dist: watchdog>=4.0.0
23
+ Requires-Dist: httpx>=0.27
24
+
25
+ # teammate-sync
26
+
27
+ **Cross-engineer Claude Code context sharing.** Your teammate types `/share`
28
+ in their Claude Code session. From your own terminal, your Claude can ask
29
+ theirs anything and gets back a cited answer in seconds.
30
+
31
+ No pasted transcripts. No GitHub pushes. No shared bucket setup.
32
+
33
+ - Landing: https://omdivyatej.github.io/teammate-sync-site/
34
+ - Source: https://github.com/omdivyatej/teammate-sync
35
+
36
+ ---
37
+
38
+ ## The problem
39
+
40
+ You and your teammate are both using Claude Code on the same project. You
41
+ need to know what they decided about the database schema, or which file
42
+ they touched, or why they picked one library over another.
43
+
44
+ Today, two bad options:
45
+
46
+ 1. **Ping them on Slack and wait.** Forty-five minutes of context-switching.
47
+ 2. **Get them to send their session transcript.** Their `.jsonl` is 50k
48
+ lines. You paste it into your Claude and immediately blow past the
49
+ 200k token context window.
50
+
51
+ `teammate-sync` is the third option: their Claude becomes a queryable
52
+ context server. Your Claude calls it, gets back a cited synthesis, your
53
+ context window stays clean.
54
+
55
+ ## Install
56
+
57
+ ```
58
+ pip install teammate-sync
59
+ teammate-sync init
60
+ teammate-sync daemon
61
+ ```
62
+
63
+ That's it. Full setup walkthrough: [INSTALL.md](INSTALL.md).
64
+
65
+ `init` opens GitHub OAuth (your workspace = your GitHub org, no separate
66
+ account), installs the `/share` slash commands into `~/.claude/commands/`,
67
+ wires session lifecycle hooks into `~/.claude/settings.json`, and registers
68
+ the MCP server. `daemon` runs in the foreground in a terminal you leave open.
69
+
70
+ ## How sharing works
71
+
72
+ ```
73
+ /share in any Claude Code session
74
+ ```
75
+
76
+ Daemon log immediately prints `share-mode ACTIVATED -> uploading`. That
77
+ session's `.jsonl` plus your `CLAUDE.md` start syncing to your team's
78
+ backend in real time as you work.
79
+
80
+ ```
81
+ /unshare same session
82
+ ```
83
+
84
+ Daemon wipes that session's content from the backend immediately.
85
+
86
+ ```
87
+ /shared any session
88
+ ```
89
+
90
+ Lists which sessions are currently shared.
91
+
92
+ ## How teammates query you
93
+
94
+ From any Claude Code session in your org, your teammate types:
95
+
96
+ > Use `mcp__teammate-sync__query_teammate_context` with
97
+ > `teammate=<your-github-handle>` and `question="..."`
98
+
99
+ The MCP server pulls your active-session state + your shared session
100
+ transcripts, hands them to a Claude Sonnet synthesis call, and returns a
101
+ cited answer. Citations point to specific session IDs and file names so
102
+ they can verify.
103
+
104
+ ## Privacy model
105
+
106
+ Default: **nothing is shared.** The daemon is running but idle.
107
+
108
+ - **Sessions** are opted in one at a time via `/share`. Unshared sessions
109
+ never leave your machine, no matter how many you have running.
110
+ - **Your GitHub OAuth token** sits in `~/.teammate-sync/auth.json` (mode
111
+ 0600) and is **never** in the synced tree.
112
+ - **Your org** is the unit of trust. Only members of your GitHub org can
113
+ query you. Discovery happens via the GitHub API, no manual invites.
114
+
115
+ ## What syncs where
116
+
117
+ | Path | What it holds | Synced to cloud? |
118
+ | ---- | ------------- | --------------- |
119
+ | `~/.teammate-sync/auth.json` | Your GitHub OAuth token | **NEVER** (local only) |
120
+ | `~/.teammate-sync/state/.shared-sessions.json` | List of currently-shared session IDs | No (local gate) |
121
+ | `~/.teammate-sync/state/.active-sessions.json` | Which sessions are active right now (cwd, last activity) | Yes |
122
+ | `~/.claude/projects/<encoded-cwd>/<sid>.jsonl` | Claude Code session transcripts | Only `/share`'d ones |
123
+
124
+ ## CLI
125
+
126
+ | | |
127
+ |---|---|
128
+ | `teammate-sync init` | First-run setup. Re-runnable to refresh hooks / slash commands. |
129
+ | `teammate-sync daemon` | Run the sync daemon (foreground). |
130
+ | `teammate-sync share` / `unshare` / `shared` | Same as the slash commands, from any shell. |
131
+ | `teammate-sync whoami` | Show your identity + workspace. |
132
+ | `teammate-sync teammates` | List members of your workspace org. |
133
+ | `teammate-sync logout` | Delete `~/.teammate-sync/auth.json`. |
134
+
135
+ ## Requirements
136
+
137
+ - Python 3.11+
138
+ - [Claude Code](https://docs.claude.com/en/docs/claude-code) CLI
139
+ - `ANTHROPIC_API_KEY` exported in your shell (used by the MCP server's
140
+ synthesis calls)
141
+
142
+ ## Status
143
+
144
+ Public beta. Backend runs on Fly.io (Singapore region, single-region by
145
+ design — synthesis latency is dominated by Anthropic API not by storage).
146
+ Per-session opt-in (`/share` / `/unshare`) is the privacy model; there is
147
+ no "everything sync" mode and there won't be.
148
+
149
+ ## License
150
+
151
+ MIT — see [LICENSE](LICENSE) if present, or `pyproject.toml`.
@@ -0,0 +1,127 @@
1
+ # teammate-sync
2
+
3
+ **Cross-engineer Claude Code context sharing.** Your teammate types `/share`
4
+ in their Claude Code session. From your own terminal, your Claude can ask
5
+ theirs anything and gets back a cited answer in seconds.
6
+
7
+ No pasted transcripts. No GitHub pushes. No shared bucket setup.
8
+
9
+ - Landing: https://omdivyatej.github.io/teammate-sync-site/
10
+ - Source: https://github.com/omdivyatej/teammate-sync
11
+
12
+ ---
13
+
14
+ ## The problem
15
+
16
+ You and your teammate are both using Claude Code on the same project. You
17
+ need to know what they decided about the database schema, or which file
18
+ they touched, or why they picked one library over another.
19
+
20
+ Today, two bad options:
21
+
22
+ 1. **Ping them on Slack and wait.** Forty-five minutes of context-switching.
23
+ 2. **Get them to send their session transcript.** Their `.jsonl` is 50k
24
+ lines. You paste it into your Claude and immediately blow past the
25
+ 200k token context window.
26
+
27
+ `teammate-sync` is the third option: their Claude becomes a queryable
28
+ context server. Your Claude calls it, gets back a cited synthesis, your
29
+ context window stays clean.
30
+
31
+ ## Install
32
+
33
+ ```
34
+ pip install teammate-sync
35
+ teammate-sync init
36
+ teammate-sync daemon
37
+ ```
38
+
39
+ That's it. Full setup walkthrough: [INSTALL.md](INSTALL.md).
40
+
41
+ `init` opens GitHub OAuth (your workspace = your GitHub org, no separate
42
+ account), installs the `/share` slash commands into `~/.claude/commands/`,
43
+ wires session lifecycle hooks into `~/.claude/settings.json`, and registers
44
+ the MCP server. `daemon` runs in the foreground in a terminal you leave open.
45
+
46
+ ## How sharing works
47
+
48
+ ```
49
+ /share in any Claude Code session
50
+ ```
51
+
52
+ Daemon log immediately prints `share-mode ACTIVATED -> uploading`. That
53
+ session's `.jsonl` plus your `CLAUDE.md` start syncing to your team's
54
+ backend in real time as you work.
55
+
56
+ ```
57
+ /unshare same session
58
+ ```
59
+
60
+ Daemon wipes that session's content from the backend immediately.
61
+
62
+ ```
63
+ /shared any session
64
+ ```
65
+
66
+ Lists which sessions are currently shared.
67
+
68
+ ## How teammates query you
69
+
70
+ From any Claude Code session in your org, your teammate types:
71
+
72
+ > Use `mcp__teammate-sync__query_teammate_context` with
73
+ > `teammate=<your-github-handle>` and `question="..."`
74
+
75
+ The MCP server pulls your active-session state + your shared session
76
+ transcripts, hands them to a Claude Sonnet synthesis call, and returns a
77
+ cited answer. Citations point to specific session IDs and file names so
78
+ they can verify.
79
+
80
+ ## Privacy model
81
+
82
+ Default: **nothing is shared.** The daemon is running but idle.
83
+
84
+ - **Sessions** are opted in one at a time via `/share`. Unshared sessions
85
+ never leave your machine, no matter how many you have running.
86
+ - **Your GitHub OAuth token** sits in `~/.teammate-sync/auth.json` (mode
87
+ 0600) and is **never** in the synced tree.
88
+ - **Your org** is the unit of trust. Only members of your GitHub org can
89
+ query you. Discovery happens via the GitHub API, no manual invites.
90
+
91
+ ## What syncs where
92
+
93
+ | Path | What it holds | Synced to cloud? |
94
+ | ---- | ------------- | --------------- |
95
+ | `~/.teammate-sync/auth.json` | Your GitHub OAuth token | **NEVER** (local only) |
96
+ | `~/.teammate-sync/state/.shared-sessions.json` | List of currently-shared session IDs | No (local gate) |
97
+ | `~/.teammate-sync/state/.active-sessions.json` | Which sessions are active right now (cwd, last activity) | Yes |
98
+ | `~/.claude/projects/<encoded-cwd>/<sid>.jsonl` | Claude Code session transcripts | Only `/share`'d ones |
99
+
100
+ ## CLI
101
+
102
+ | | |
103
+ |---|---|
104
+ | `teammate-sync init` | First-run setup. Re-runnable to refresh hooks / slash commands. |
105
+ | `teammate-sync daemon` | Run the sync daemon (foreground). |
106
+ | `teammate-sync share` / `unshare` / `shared` | Same as the slash commands, from any shell. |
107
+ | `teammate-sync whoami` | Show your identity + workspace. |
108
+ | `teammate-sync teammates` | List members of your workspace org. |
109
+ | `teammate-sync logout` | Delete `~/.teammate-sync/auth.json`. |
110
+
111
+ ## Requirements
112
+
113
+ - Python 3.11+
114
+ - [Claude Code](https://docs.claude.com/en/docs/claude-code) CLI
115
+ - `ANTHROPIC_API_KEY` exported in your shell (used by the MCP server's
116
+ synthesis calls)
117
+
118
+ ## Status
119
+
120
+ Public beta. Backend runs on Fly.io (Singapore region, single-region by
121
+ design — synthesis latency is dominated by Anthropic API not by storage).
122
+ Per-session opt-in (`/share` / `/unshare`) is the privacy model; there is
123
+ no "everything sync" mode and there won't be.
124
+
125
+ ## License
126
+
127
+ MIT — see [LICENSE](LICENSE) if present, or `pyproject.toml`.
@@ -0,0 +1,48 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "teammate-sync"
7
+ version = "0.1.0"
8
+ description = "Cross-engineer Claude Code context sharing — type /share, your teammate queries your context."
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Om Divyatej", email = "om@turgon.ai" },
14
+ ]
15
+ keywords = ["claude", "claude-code", "mcp", "team", "context", "sharing"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Software Development",
25
+ ]
26
+ dependencies = [
27
+ "mcp>=1.0.0",
28
+ "anthropic>=0.40.0",
29
+ "watchdog>=4.0.0",
30
+ "httpx>=0.27",
31
+ ]
32
+
33
+ [project.urls]
34
+ Homepage = "https://omdivyatej.github.io/teammate-sync-site/"
35
+ Source = "https://github.com/omdivyatej/teammate-sync"
36
+
37
+ [project.scripts]
38
+ # `pip install` puts this on the user's PATH. All functionality is reachable
39
+ # via subcommands: init, daemon, share, unshare, shared, whoami, teammates,
40
+ # install-commands, logout.
41
+ teammate-sync = "teammate_sync.cli:main"
42
+
43
+ [tool.setuptools]
44
+ # Single flat module layout under teammate_sync/.
45
+ packages = ["teammate_sync"]
46
+
47
+ [tool.setuptools.package-dir]
48
+ teammate_sync = "teammate_sync"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,51 @@
1
+ """
2
+ Auth helper for teammate-sync clients (daemon + MCP).
3
+
4
+ Reads ~/.teammate-sync/auth.json, written by `teammate-sync init` (Phase 5c).
5
+ Format:
6
+ {
7
+ "token": "gho_...", # GitHub OAuth access token
8
+ "org": "SolarCheckr", # workspace = GitHub org name
9
+ "backend_url": "https://teammate-sync-backend.fly.dev"
10
+ }
11
+ """
12
+ import json
13
+ import os
14
+ from pathlib import Path
15
+
16
+
17
+ DEFAULT_AUTH_FILE = "~/.teammate-sync/auth.json"
18
+ DEFAULT_BACKEND_URL = "https://teammate-sync-backend.fly.dev"
19
+
20
+
21
+ def auth_file_path() -> Path:
22
+ return Path(os.environ.get("TEAMMATE_AUTH_FILE", DEFAULT_AUTH_FILE)).expanduser()
23
+
24
+
25
+ def read_auth() -> dict:
26
+ """Read the auth file. Raises with a clear message if missing or malformed."""
27
+ path = auth_file_path()
28
+ if not path.exists():
29
+ raise FileNotFoundError(
30
+ f"teammate-sync auth file not found at {path}.\n"
31
+ f"Run `teammate-sync init` to sign in with GitHub and create it."
32
+ )
33
+ try:
34
+ data = json.loads(path.read_text())
35
+ except json.JSONDecodeError as e:
36
+ raise ValueError(f"Auth file {path} is not valid JSON: {e}")
37
+ for required in ("token", "org"):
38
+ if not data.get(required):
39
+ raise ValueError(f"Auth file {path} missing required field: {required!r}")
40
+ data.setdefault("backend_url", DEFAULT_BACKEND_URL)
41
+ return data
42
+
43
+
44
+ def write_auth(token: str, org: str, backend_url: str = DEFAULT_BACKEND_URL) -> Path:
45
+ """Persist the auth file with restrictive permissions (0600)."""
46
+ path = auth_file_path()
47
+ path.parent.mkdir(parents=True, exist_ok=True)
48
+ payload = {"token": token, "org": org, "backend_url": backend_url}
49
+ path.write_text(json.dumps(payload, indent=2))
50
+ path.chmod(0o600)
51
+ return path