tribalmemory 0.1.0__tar.gz → 0.1.1__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.
Files changed (75) hide show
  1. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/PKG-INFO +61 -8
  2. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/README.md +60 -7
  3. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/pyproject.toml +1 -1
  4. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/cli.py +53 -32
  5. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory.egg-info/PKG-INFO +61 -8
  6. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_cli.py +49 -3
  7. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/LICENSE +0 -0
  8. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/setup.cfg +0 -0
  9. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/__init__.py +0 -0
  10. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/__init__.py +0 -0
  11. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/config/__init__.py +0 -0
  12. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/config/providers.py +0 -0
  13. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/config/system.py +0 -0
  14. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/container/__init__.py +0 -0
  15. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/container/container.py +0 -0
  16. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/providers/__init__.py +0 -0
  17. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/providers/base.py +0 -0
  18. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/providers/deduplication.py +0 -0
  19. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/providers/lancedb.py +0 -0
  20. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/providers/memory.py +0 -0
  21. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/providers/mock.py +0 -0
  22. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/providers/openai.py +0 -0
  23. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/providers/timestamp.py +0 -0
  24. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/a21/system.py +0 -0
  25. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/interfaces.py +0 -0
  26. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/mcp/__init__.py +0 -0
  27. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/mcp/__main__.py +0 -0
  28. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/mcp/server.py +0 -0
  29. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/performance/__init__.py +0 -0
  30. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/performance/benchmarks.py +0 -0
  31. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/performance/corpus_generator.py +0 -0
  32. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/portability/__init__.py +0 -0
  33. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/portability/embedding_metadata.py +0 -0
  34. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/server/__init__.py +0 -0
  35. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/server/__main__.py +0 -0
  36. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/server/app.py +0 -0
  37. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/server/config.py +0 -0
  38. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/server/models.py +0 -0
  39. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/server/routes.py +0 -0
  40. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/services/__init__.py +0 -0
  41. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/services/deduplication.py +0 -0
  42. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/services/embeddings.py +0 -0
  43. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/services/import_export.py +0 -0
  44. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/services/memory.py +0 -0
  45. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/services/vector_store.py +0 -0
  46. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/testing/__init__.py +0 -0
  47. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/testing/embedding_utils.py +0 -0
  48. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/testing/fixtures.py +0 -0
  49. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/testing/metrics.py +0 -0
  50. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/testing/mocks.py +0 -0
  51. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/testing/semantic_expansions.py +0 -0
  52. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory/utils.py +0 -0
  53. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory.egg-info/SOURCES.txt +0 -0
  54. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory.egg-info/dependency_links.txt +0 -0
  55. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory.egg-info/entry_points.txt +0 -0
  56. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory.egg-info/requires.txt +0 -0
  57. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/src/tribalmemory.egg-info/top_level.txt +0 -0
  58. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_a21_config.py +0 -0
  59. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_a21_container.py +0 -0
  60. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_a21_providers.py +0 -0
  61. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_a21_system.py +0 -0
  62. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_benchmarks.py +0 -0
  63. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_embedding_portability.py +0 -0
  64. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_import_export.py +0 -0
  65. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_local_embeddings.py +0 -0
  66. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_mcp_integration.py +0 -0
  67. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_mcp_server.py +0 -0
  68. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_memory_harness.py +0 -0
  69. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_negative_security.py +0 -0
  70. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_performance.py +0 -0
  71. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_server.py +0 -0
  72. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_services.py +0 -0
  73. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_tier1_functional.py +0 -0
  74. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_tier2_capability.py +0 -0
  75. {tribalmemory-0.1.0 → tribalmemory-0.1.1}/tests/test_tier3_emergence.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tribalmemory
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Shared memory infrastructure for multi-instance AI agents
5
5
  Author-email: Joe <joe@example.com>
6
6
  License: Apache-2.0
@@ -48,12 +48,48 @@ Dynamic: license-file
48
48
 
49
49
  One memory store, many agents. Teach Claude Code something — Codex already knows it. That's not just persistence — it's **cross-agent intelligence**.
50
50
 
51
+ <p align="center">
52
+ <img src="docs/assets/one-brain-two-agents.gif" alt="One Brain, Two Agents — Claude Code stores memories, Codex recalls them" width="700">
53
+ <br>
54
+ <em>Claude Code stores architecture decisions → Codex recalls them instantly</em>
55
+ </p>
56
+
57
+ [![asciinema demo](https://img.shields.io/badge/demo-asciinema-d40000)](https://asciinema.org/a/ZM74iIXzM07SV21P)
58
+ [![PyPI](https://img.shields.io/pypi/v/tribalmemory)](https://pypi.org/project/tribalmemory/)
59
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue)](LICENSE)
60
+
51
61
  ## Why
52
62
 
53
63
  Every AI coding assistant starts fresh. Claude Code doesn't know what you told Codex. Codex doesn't know what you told Claude. You repeat yourself constantly.
54
64
 
55
65
  Tribal Memory is a shared memory server that any AI agent can connect to. Store a memory from one agent, recall it from another. It just works.
56
66
 
67
+ ## Install
68
+
69
+ **macOS:**
70
+ ```bash
71
+ # Install uv (https://docs.astral.sh/uv/)
72
+ curl -LsSf https://astral.sh/uv/install.sh | sh
73
+
74
+ # Restart your terminal, or run:
75
+ source ~/.zshrc
76
+
77
+ # Install tribalmemory
78
+ uv tool install tribalmemory
79
+ ```
80
+
81
+ > **Why uv?** macOS blocks `pip install` into the system Python with "externally-managed-environment" errors. `uv tool install` handles isolated environments automatically.
82
+
83
+ **Linux:**
84
+ ```bash
85
+ pip install tribalmemory
86
+
87
+ # Or with uv:
88
+ # curl -LsSf https://astral.sh/uv/install.sh | sh
89
+ # source ~/.bashrc
90
+ # uv tool install tribalmemory
91
+ ```
92
+
57
93
  ## Quick Start
58
94
 
59
95
  ### Option A: Local Mode (Zero Cloud, Zero Cost)
@@ -61,8 +97,6 @@ Tribal Memory is a shared memory server that any AI agent can connect to. Store
61
97
  No API keys. No cloud. Everything runs on your machine.
62
98
 
63
99
  ```bash
64
- pip install tribalmemory
65
-
66
100
  # Set up with local Ollama embeddings
67
101
  tribalmemory init --local
68
102
 
@@ -76,8 +110,6 @@ tribalmemory serve
76
110
  ### Option B: OpenAI Embeddings
77
111
 
78
112
  ```bash
79
- pip install tribalmemory
80
-
81
113
  # Set up with OpenAI
82
114
  export OPENAI_API_KEY=sk-...
83
115
  tribalmemory init
@@ -224,19 +256,40 @@ await service.correct(
224
256
  )
225
257
  ```
226
258
 
259
+ ## Demo
260
+
261
+ See cross-agent memory sharing in action:
262
+
263
+ ```bash
264
+ # Start the server
265
+ tribalmemory serve
266
+
267
+ # Run the interactive demo
268
+ ./demo.sh
269
+ ```
270
+
271
+ See [docs/demo-output.md](docs/demo-output.md) for example output.
272
+
227
273
  ## HTTP API
228
274
 
275
+ All endpoints are under the `/v1` prefix.
276
+
229
277
  ```bash
230
278
  # Store a memory
231
- curl -X POST http://localhost:18790/memories \
279
+ curl -X POST http://localhost:18790/v1/remember \
232
280
  -H "Content-Type: application/json" \
233
281
  -d '{"content": "The database uses Postgres 16", "tags": ["infra"]}'
234
282
 
235
283
  # Search memories
236
- curl "http://localhost:18790/memories/search?query=what+database&limit=5"
284
+ curl -X POST http://localhost:18790/v1/recall \
285
+ -H "Content-Type: application/json" \
286
+ -d '{"query": "what database", "limit": 5}'
237
287
 
238
288
  # Get stats
239
- curl http://localhost:18790/stats
289
+ curl http://localhost:18790/v1/stats
290
+
291
+ # Health check
292
+ curl http://localhost:18790/v1/health
240
293
  ```
241
294
 
242
295
  ## OpenClaw Integration
@@ -4,12 +4,48 @@
4
4
 
5
5
  One memory store, many agents. Teach Claude Code something — Codex already knows it. That's not just persistence — it's **cross-agent intelligence**.
6
6
 
7
+ <p align="center">
8
+ <img src="docs/assets/one-brain-two-agents.gif" alt="One Brain, Two Agents — Claude Code stores memories, Codex recalls them" width="700">
9
+ <br>
10
+ <em>Claude Code stores architecture decisions → Codex recalls them instantly</em>
11
+ </p>
12
+
13
+ [![asciinema demo](https://img.shields.io/badge/demo-asciinema-d40000)](https://asciinema.org/a/ZM74iIXzM07SV21P)
14
+ [![PyPI](https://img.shields.io/pypi/v/tribalmemory)](https://pypi.org/project/tribalmemory/)
15
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue)](LICENSE)
16
+
7
17
  ## Why
8
18
 
9
19
  Every AI coding assistant starts fresh. Claude Code doesn't know what you told Codex. Codex doesn't know what you told Claude. You repeat yourself constantly.
10
20
 
11
21
  Tribal Memory is a shared memory server that any AI agent can connect to. Store a memory from one agent, recall it from another. It just works.
12
22
 
23
+ ## Install
24
+
25
+ **macOS:**
26
+ ```bash
27
+ # Install uv (https://docs.astral.sh/uv/)
28
+ curl -LsSf https://astral.sh/uv/install.sh | sh
29
+
30
+ # Restart your terminal, or run:
31
+ source ~/.zshrc
32
+
33
+ # Install tribalmemory
34
+ uv tool install tribalmemory
35
+ ```
36
+
37
+ > **Why uv?** macOS blocks `pip install` into the system Python with "externally-managed-environment" errors. `uv tool install` handles isolated environments automatically.
38
+
39
+ **Linux:**
40
+ ```bash
41
+ pip install tribalmemory
42
+
43
+ # Or with uv:
44
+ # curl -LsSf https://astral.sh/uv/install.sh | sh
45
+ # source ~/.bashrc
46
+ # uv tool install tribalmemory
47
+ ```
48
+
13
49
  ## Quick Start
14
50
 
15
51
  ### Option A: Local Mode (Zero Cloud, Zero Cost)
@@ -17,8 +53,6 @@ Tribal Memory is a shared memory server that any AI agent can connect to. Store
17
53
  No API keys. No cloud. Everything runs on your machine.
18
54
 
19
55
  ```bash
20
- pip install tribalmemory
21
-
22
56
  # Set up with local Ollama embeddings
23
57
  tribalmemory init --local
24
58
 
@@ -32,8 +66,6 @@ tribalmemory serve
32
66
  ### Option B: OpenAI Embeddings
33
67
 
34
68
  ```bash
35
- pip install tribalmemory
36
-
37
69
  # Set up with OpenAI
38
70
  export OPENAI_API_KEY=sk-...
39
71
  tribalmemory init
@@ -180,19 +212,40 @@ await service.correct(
180
212
  )
181
213
  ```
182
214
 
215
+ ## Demo
216
+
217
+ See cross-agent memory sharing in action:
218
+
219
+ ```bash
220
+ # Start the server
221
+ tribalmemory serve
222
+
223
+ # Run the interactive demo
224
+ ./demo.sh
225
+ ```
226
+
227
+ See [docs/demo-output.md](docs/demo-output.md) for example output.
228
+
183
229
  ## HTTP API
184
230
 
231
+ All endpoints are under the `/v1` prefix.
232
+
185
233
  ```bash
186
234
  # Store a memory
187
- curl -X POST http://localhost:18790/memories \
235
+ curl -X POST http://localhost:18790/v1/remember \
188
236
  -H "Content-Type: application/json" \
189
237
  -d '{"content": "The database uses Postgres 16", "tags": ["infra"]}'
190
238
 
191
239
  # Search memories
192
- curl "http://localhost:18790/memories/search?query=what+database&limit=5"
240
+ curl -X POST http://localhost:18790/v1/recall \
241
+ -H "Content-Type: application/json" \
242
+ -d '{"query": "what database", "limit": 5}'
193
243
 
194
244
  # Get stats
195
- curl http://localhost:18790/stats
245
+ curl http://localhost:18790/v1/stats
246
+
247
+ # Health check
248
+ curl http://localhost:18790/v1/health
196
249
  ```
197
250
 
198
251
  ## OpenClaw Integration
@@ -7,7 +7,7 @@ where = ["src"]
7
7
 
8
8
  [project]
9
9
  name = "tribalmemory"
10
- version = "0.1.0"
10
+ version = "0.1.1"
11
11
  description = "Shared memory infrastructure for multi-instance AI agents"
12
12
  readme = "README.md"
13
13
  license = {text = "Apache-2.0"}
@@ -26,7 +26,7 @@ TRIBAL_DIR = Path.home() / ".tribal-memory"
26
26
  CONFIG_FILE = TRIBAL_DIR / "config.yaml"
27
27
  DEFAULT_INSTANCE_ID = "default"
28
28
 
29
- # MCP config for Claude Code (claude_desktop_config.json)
29
+ # MCP config for Claude Code CLI and Claude Desktop
30
30
  CLAUDE_CODE_MCP_CONFIG = {
31
31
  "mcpServers": {
32
32
  "tribal-memory": {
@@ -135,54 +135,75 @@ def cmd_init(args: argparse.Namespace) -> int:
135
135
 
136
136
 
137
137
  def _setup_claude_code_mcp(is_local: bool) -> None:
138
- """Add Tribal Memory to Claude Code's MCP configuration."""
139
- # Claude Code MCP config paths by platform
140
- claude_config_paths = [
141
- Path.home() / ".claude" / "claude_desktop_config.json", # Claude Code CLI (all platforms)
142
- Path.home() / "Library" / "Application Support" / "Claude" / "claude_desktop_config.json", # Claude Desktop (macOS)
143
- Path.home() / "AppData" / "Roaming" / "Claude" / "claude_desktop_config.json", # Claude Desktop (Windows)
138
+ """Add Tribal Memory to Claude Code's MCP configuration.
139
+
140
+ Claude Code CLI reads MCP servers from ~/.claude.json (user scope).
141
+ Claude Desktop reads from platform-specific claude_desktop_config.json.
142
+ We update both if they exist, and always ensure ~/.claude.json is set.
143
+ """
144
+ # Claude Code CLI config (primary — this is what `claude` CLI reads)
145
+ claude_cli_config = Path.home() / ".claude.json"
146
+
147
+ # Claude Desktop config paths (secondary — update if they exist)
148
+ claude_desktop_paths = [
149
+ Path.home() / "Library" / "Application Support" / "Claude" / "claude_desktop_config.json", # macOS
150
+ Path.home() / "AppData" / "Roaming" / "Claude" / "claude_desktop_config.json", # Windows
151
+ Path.home() / ".claude" / "claude_desktop_config.json", # Legacy / Linux
144
152
  ]
145
153
 
146
- config_path = None
147
- for p in claude_config_paths:
148
- if p.exists():
149
- config_path = p
150
- break
154
+ mcp_entry = {
155
+ "command": "tribalmemory-mcp",
156
+ "env": {},
157
+ }
158
+
159
+ if is_local:
160
+ mcp_entry["env"]["TRIBAL_MEMORY_EMBEDDING_API_BASE"] = "http://localhost:11434/v1"
161
+
162
+ # Always update Claude Code CLI config (~/.claude.json)
163
+ _update_mcp_config(claude_cli_config, mcp_entry, create_if_missing=True)
164
+ print(f"✅ Claude Code CLI config updated: {claude_cli_config}")
151
165
 
152
- if config_path is None:
153
- # Create default location
154
- config_path = claude_config_paths[0]
155
- config_path.parent.mkdir(parents=True, exist_ok=True)
166
+ # Also update Claude Desktop config (create platform-appropriate path)
167
+ desktop_path = _get_claude_desktop_config_path()
168
+ _update_mcp_config(desktop_path, mcp_entry, create_if_missing=True)
169
+ print(f"✅ Claude Desktop config updated: {desktop_path}")
170
+
171
+
172
+ def _get_claude_desktop_config_path() -> Path:
173
+ """Get the platform-appropriate Claude Desktop config path."""
174
+ if sys.platform == "darwin":
175
+ return Path.home() / "Library" / "Application Support" / "Claude" / "claude_desktop_config.json"
176
+ elif sys.platform == "win32":
177
+ return Path.home() / "AppData" / "Roaming" / "Claude" / "claude_desktop_config.json"
178
+ else:
179
+ return Path.home() / ".claude" / "claude_desktop_config.json"
156
180
 
157
- # Read existing config or start fresh
181
+
182
+ def _update_mcp_config(
183
+ config_path: Path, mcp_entry: dict, create_if_missing: bool = False
184
+ ) -> None:
185
+ """Update an MCP config file with the tribal-memory server entry."""
158
186
  if config_path.exists():
159
187
  try:
160
188
  existing = json.loads(config_path.read_text())
161
189
  except json.JSONDecodeError as e:
162
- print(
163
- f"⚠️ Existing config has invalid JSON: {e}"
164
- )
190
+ backup_path = config_path.with_suffix(".json.bak")
191
+ config_path.rename(backup_path)
192
+ print(f"⚠️ Existing config has invalid JSON: {e}")
193
+ print(f" Backed up to {backup_path}")
165
194
  print(f" Creating fresh config at {config_path}")
166
195
  existing = {}
167
- else:
196
+ elif create_if_missing:
197
+ config_path.parent.mkdir(parents=True, exist_ok=True)
168
198
  existing = {}
199
+ else:
200
+ return
169
201
 
170
- # Merge MCP server config
171
202
  if "mcpServers" not in existing:
172
203
  existing["mcpServers"] = {}
173
204
 
174
- mcp_entry = {
175
- "command": "tribalmemory-mcp",
176
- "env": {},
177
- }
178
-
179
- if is_local:
180
- mcp_entry["env"]["TRIBAL_MEMORY_EMBEDDING_API_BASE"] = "http://localhost:11434/v1"
181
-
182
205
  existing["mcpServers"]["tribal-memory"] = mcp_entry
183
-
184
206
  config_path.write_text(json.dumps(existing, indent=2) + "\n")
185
- print(f"✅ Claude Code MCP config updated: {config_path}")
186
207
 
187
208
 
188
209
  def _setup_codex_mcp(is_local: bool) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tribalmemory
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Shared memory infrastructure for multi-instance AI agents
5
5
  Author-email: Joe <joe@example.com>
6
6
  License: Apache-2.0
@@ -48,12 +48,48 @@ Dynamic: license-file
48
48
 
49
49
  One memory store, many agents. Teach Claude Code something — Codex already knows it. That's not just persistence — it's **cross-agent intelligence**.
50
50
 
51
+ <p align="center">
52
+ <img src="docs/assets/one-brain-two-agents.gif" alt="One Brain, Two Agents — Claude Code stores memories, Codex recalls them" width="700">
53
+ <br>
54
+ <em>Claude Code stores architecture decisions → Codex recalls them instantly</em>
55
+ </p>
56
+
57
+ [![asciinema demo](https://img.shields.io/badge/demo-asciinema-d40000)](https://asciinema.org/a/ZM74iIXzM07SV21P)
58
+ [![PyPI](https://img.shields.io/pypi/v/tribalmemory)](https://pypi.org/project/tribalmemory/)
59
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue)](LICENSE)
60
+
51
61
  ## Why
52
62
 
53
63
  Every AI coding assistant starts fresh. Claude Code doesn't know what you told Codex. Codex doesn't know what you told Claude. You repeat yourself constantly.
54
64
 
55
65
  Tribal Memory is a shared memory server that any AI agent can connect to. Store a memory from one agent, recall it from another. It just works.
56
66
 
67
+ ## Install
68
+
69
+ **macOS:**
70
+ ```bash
71
+ # Install uv (https://docs.astral.sh/uv/)
72
+ curl -LsSf https://astral.sh/uv/install.sh | sh
73
+
74
+ # Restart your terminal, or run:
75
+ source ~/.zshrc
76
+
77
+ # Install tribalmemory
78
+ uv tool install tribalmemory
79
+ ```
80
+
81
+ > **Why uv?** macOS blocks `pip install` into the system Python with "externally-managed-environment" errors. `uv tool install` handles isolated environments automatically.
82
+
83
+ **Linux:**
84
+ ```bash
85
+ pip install tribalmemory
86
+
87
+ # Or with uv:
88
+ # curl -LsSf https://astral.sh/uv/install.sh | sh
89
+ # source ~/.bashrc
90
+ # uv tool install tribalmemory
91
+ ```
92
+
57
93
  ## Quick Start
58
94
 
59
95
  ### Option A: Local Mode (Zero Cloud, Zero Cost)
@@ -61,8 +97,6 @@ Tribal Memory is a shared memory server that any AI agent can connect to. Store
61
97
  No API keys. No cloud. Everything runs on your machine.
62
98
 
63
99
  ```bash
64
- pip install tribalmemory
65
-
66
100
  # Set up with local Ollama embeddings
67
101
  tribalmemory init --local
68
102
 
@@ -76,8 +110,6 @@ tribalmemory serve
76
110
  ### Option B: OpenAI Embeddings
77
111
 
78
112
  ```bash
79
- pip install tribalmemory
80
-
81
113
  # Set up with OpenAI
82
114
  export OPENAI_API_KEY=sk-...
83
115
  tribalmemory init
@@ -224,19 +256,40 @@ await service.correct(
224
256
  )
225
257
  ```
226
258
 
259
+ ## Demo
260
+
261
+ See cross-agent memory sharing in action:
262
+
263
+ ```bash
264
+ # Start the server
265
+ tribalmemory serve
266
+
267
+ # Run the interactive demo
268
+ ./demo.sh
269
+ ```
270
+
271
+ See [docs/demo-output.md](docs/demo-output.md) for example output.
272
+
227
273
  ## HTTP API
228
274
 
275
+ All endpoints are under the `/v1` prefix.
276
+
229
277
  ```bash
230
278
  # Store a memory
231
- curl -X POST http://localhost:18790/memories \
279
+ curl -X POST http://localhost:18790/v1/remember \
232
280
  -H "Content-Type: application/json" \
233
281
  -d '{"content": "The database uses Postgres 16", "tags": ["infra"]}'
234
282
 
235
283
  # Search memories
236
- curl "http://localhost:18790/memories/search?query=what+database&limit=5"
284
+ curl -X POST http://localhost:18790/v1/recall \
285
+ -H "Content-Type: application/json" \
286
+ -d '{"query": "what database", "limit": 5}'
237
287
 
238
288
  # Get stats
239
- curl http://localhost:18790/stats
289
+ curl http://localhost:18790/v1/stats
290
+
291
+ # Health check
292
+ curl http://localhost:18790/v1/health
240
293
  ```
241
294
 
242
295
  ## OpenClaw Integration
@@ -94,11 +94,11 @@ class TestInitCommand:
94
94
  assert "old config" not in config_file.read_text()
95
95
 
96
96
  def test_init_claude_code_creates_mcp_config(self, cli_env):
97
- """init --claude-code should write Claude MCP config."""
97
+ """init --claude-code should write Claude Code CLI config (~/.claude.json)."""
98
98
  result = cmd_init(FakeArgs(claude_code=True))
99
99
 
100
100
  assert result == 0
101
- claude_config = cli_env / ".claude" / "claude_desktop_config.json"
101
+ claude_config = cli_env / ".claude.json"
102
102
  assert claude_config.exists()
103
103
  mcp = json.loads(claude_config.read_text())
104
104
  assert "tribal-memory" in mcp["mcpServers"]
@@ -109,12 +109,58 @@ class TestInitCommand:
109
109
  result = cmd_init(FakeArgs(local=True, claude_code=True))
110
110
 
111
111
  assert result == 0
112
- claude_config = cli_env / ".claude" / "claude_desktop_config.json"
112
+ claude_config = cli_env / ".claude.json"
113
113
  mcp = json.loads(claude_config.read_text())
114
114
  env = mcp["mcpServers"]["tribal-memory"]["env"]
115
115
  assert "TRIBAL_MEMORY_EMBEDDING_API_BASE" in env
116
116
  assert "localhost:11434" in env["TRIBAL_MEMORY_EMBEDDING_API_BASE"]
117
117
 
118
+ def test_init_claude_code_creates_desktop_config(self, cli_env):
119
+ """init --claude-code should create both CLI and Desktop configs."""
120
+ result = cmd_init(FakeArgs(claude_code=True))
121
+
122
+ assert result == 0
123
+ # CLI config
124
+ cli_config = cli_env / ".claude.json"
125
+ assert cli_config.exists()
126
+ cli_mcp = json.loads(cli_config.read_text())
127
+ assert "tribal-memory" in cli_mcp["mcpServers"]
128
+ # Desktop config (Linux path under fake home)
129
+ desktop_config = cli_env / ".claude" / "claude_desktop_config.json"
130
+ assert desktop_config.exists()
131
+ desktop_mcp = json.loads(desktop_config.read_text())
132
+ assert "tribal-memory" in desktop_mcp["mcpServers"]
133
+
134
+ def test_init_claude_code_backs_up_invalid_json(self, cli_env):
135
+ """init --claude-code should backup invalid JSON config before replacing."""
136
+ cli_config = cli_env / ".claude.json"
137
+ cli_config.write_text("not valid json {{{")
138
+
139
+ result = cmd_init(FakeArgs(claude_code=True))
140
+
141
+ assert result == 0
142
+ # Original should be replaced with valid config
143
+ mcp = json.loads(cli_config.read_text())
144
+ assert "tribal-memory" in mcp["mcpServers"]
145
+ # Backup should exist with the old content
146
+ backup = cli_env / ".claude.json.bak"
147
+ assert backup.exists()
148
+ assert backup.read_text() == "not valid json {{{"
149
+
150
+ def test_init_claude_code_preserves_existing_desktop_entries(self, cli_env):
151
+ """init --claude-code should not clobber existing Desktop MCP entries."""
152
+ desktop_dir = cli_env / ".claude"
153
+ desktop_dir.mkdir(parents=True, exist_ok=True)
154
+ desktop_config = desktop_dir / "claude_desktop_config.json"
155
+ desktop_config.write_text(json.dumps({"mcpServers": {"other": {"command": "other-cmd"}}}) + "\n")
156
+
157
+ result = cmd_init(FakeArgs(claude_code=True))
158
+
159
+ assert result == 0
160
+ desktop_mcp = json.loads(desktop_config.read_text())
161
+ assert "tribal-memory" in desktop_mcp["mcpServers"]
162
+ assert "other" in desktop_mcp["mcpServers"] # preserved
163
+
118
164
 
119
165
  class TestCodexIntegration:
120
166
  """Tests for Codex CLI MCP integration."""
File without changes
File without changes