tommy-orchestrator 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,30 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .venv/
7
+ venv/
8
+ .env
9
+ .env.*
10
+ !.env.example
11
+ *.bak
12
+ *.prerestructure-bak
13
+ .memnos/
14
+ .claude/
15
+ ~/.memnos
16
+ memnos.yaml
17
+ *.log
18
+ .DS_Store
19
+ .idea/
20
+ .vscode/
21
+ *.db
22
+ *.db-shm
23
+ *.db-wal
24
+ graphify-out/
25
+ neo4j_data/
26
+ qdrant_data/
27
+ evolution_data/
28
+ run_canary.sh
29
+ run_consolidate.sh
30
+ docs/assets/.cc-replay/
@@ -0,0 +1,367 @@
1
+ Metadata-Version: 2.5
2
+ Name: tommy-orchestrator
3
+ Version: 0.1.0
4
+ Summary: Tommy — a personal coding orchestrator built on memnos
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: click>=8.1
7
+ Requires-Dist: fastmcp>=2.0
8
+ Requires-Dist: httpx>=0.27
9
+ Requires-Dist: memnos-sdk>=0.1.21
10
+ Provides-Extra: dev
11
+ Requires-Dist: pytest>=8; extra == 'dev'
12
+ Description-Content-Type: text/markdown
13
+
14
+ # Tommy — memnos-native coding orchestrator
15
+
16
+ Tommy is a lightweight CLI orchestrator that sits between your editor and your
17
+ coding harness (Claude Code, Codex, etc.). It enriches every task with
18
+ long-term memory from [memnos](../../README.md), routes work to the right
19
+ harness, and lets you steer a running sub-agent mid-run without waiting for it
20
+ to finish.
21
+
22
+ ```
23
+ ┌─────────────┐ tommy --mcp ┌──────────────────────────────────────────┐
24
+ │ Editor / │ ─────────────→ │ Tommy (stdio process) │
25
+ │ IDE │ ←────────────── │ 8 MCP tools · memnos · harness mgr │
26
+ └─────────────┘ JSON-RPC/stdio └──────────────────────┬───────────────────┘
27
+ │ Popen
28
+ TOMMY_CTRL_PORT
29
+ │
30
+ ┌──────────────▼──────────────┐
31
+ │ Harness (Claude Code, etc.) │
32
+ │ progress / wrap_up / abort │
33
+ └─────────────────────────────┘
34
+ ```
35
+
36
+ **Key design decisions:**
37
+ - Tommy is a **stdio subprocess**, not a daemon or HTTP server. The editor
38
+ spawns it (`tommy --mcp`) and owns its lifecycle.
39
+ - **memnos is the only persistent server.** Tommy talks to memnos for memory;
40
+ it exposes no long-lived listening ports.
41
+ - A **TCP loopback control channel** (`TOMMY_CTRL_PORT`) is opened
42
+ *transiently* — one ephemeral `127.0.0.1:0` socket per dispatch, closed
43
+ when the sub-agent exits. This lets Tommy send `wrap_up` / `abort` /
44
+ `pivot` to a running sub-agent and receive live progress without polling.
45
+
46
+ ---
47
+
48
+ ## Requirements
49
+
50
+ | Dependency | Version |
51
+ |-----------|---------|
52
+ | Python | ≥ 3.10 |
53
+ | [uv](https://docs.astral.sh/uv/) | any recent |
54
+ | memnos | installed and running (HTTP or stdio) |
55
+ | A supported harness | Claude Code (`claude`), Codex, etc. |
56
+
57
+ ---
58
+
59
+ ## Install
60
+
61
+ ```bash
62
+ # From the memnos repo root (editable, uv-managed):
63
+ uv tool install -e ~/git/memnos/agents/tommy
64
+
65
+ # Verify:
66
+ tommy --version
67
+ ```
68
+
69
+ > **Note:** always use `--force` when pyproject.toml dependencies change:
70
+ > ```bash
71
+ > uv tool install -e ~/git/memnos/agents/tommy --force
72
+ > ```
73
+
74
+ ### First-time setup
75
+
76
+ ```bash
77
+ tommy --install
78
+ ```
79
+
80
+ This creates `~/.memnos/agents/tommy/tommy.conf` with sensible defaults.
81
+
82
+ ---
83
+
84
+ ## Configuration
85
+
86
+ Edit `~/.memnos/agents/tommy/tommy.conf`:
87
+
88
+ ```ini
89
+ # Who you are
90
+ TOMMY_USER=YourName
91
+ ORG=your-org
92
+
93
+ # memnos namespaces
94
+ TOMMY_NS=user:yourname:tommy # where Tommy journals its own sessions
95
+ DEFAULT_NS=org:your-org:engineering # default namespace for new memories
96
+
97
+ # Model & harness
98
+ DEFAULT_MODEL=claude-sonnet-4-5
99
+ HARNESS=claude # claude | codex | auto
100
+ SMART_ROUTING=on
101
+
102
+ # Projects — format: key:Name:JIRA_PROJECT:absolute/path/to/repo
103
+ # (one per line, comma-separated)
104
+ PROJECTS=\
105
+ myapp:MyApp:MYAPP:~/git/myapp,\
106
+ platform:Platform:PLAT:~/git/platform,\
107
+ infra:Infra:PLAT:~/git/infra
108
+ ```
109
+
110
+ ### Project fields
111
+
112
+ | Field | Meaning |
113
+ |-------|---------|
114
+ | `key` | Short identifier used in `tommy --project <key>` |
115
+ | `Name` | Human-readable label |
116
+ | `JIRA_PROJECT` | Jira project key (used in commit messages, ticket links) |
117
+ | `path` | Absolute path — the workspace Tommy gives to the harness |
118
+
119
+ ---
120
+
121
+ ## Usage
122
+
123
+ ### CLI
124
+
125
+ ```bash
126
+ # Launch harness with memory context
127
+ tommy
128
+
129
+ # Activate a project (workspace + namespace auto-set)
130
+ tommy --project myapp
131
+
132
+ # List configured projects
133
+ tommy --list-projects
134
+
135
+ # List detected harnesses
136
+ tommy --list-harnesses
137
+
138
+ # Upgrade (respects uv/pipx/pip — never mixes installers)
139
+ tommy --upgrade
140
+ ```
141
+
142
+ ### MCP stdio mode (for editors)
143
+
144
+ ```bash
145
+ tommy --mcp
146
+ ```
147
+
148
+ The editor spawns this process, sends JSON-RPC over stdin/stdout, and kills
149
+ the process when done. In MCP mode Tommy itself has no persistent listening
150
+ port — but each `tommy_dispatch` call opens a transient `127.0.0.1:0` TCP
151
+ control channel that is closed when the sub-agent exits.
152
+
153
+ ---
154
+
155
+ ## Editor integration
156
+
157
+ ### Claude Desktop
158
+
159
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
160
+
161
+ ```json
162
+ {
163
+ "mcpServers": {
164
+ "tommy": {
165
+ "command": "tommy",
166
+ "args": ["--mcp"]
167
+ }
168
+ }
169
+ }
170
+ ```
171
+
172
+ ### Cursor
173
+
174
+ Add to `.cursor/mcp.json` in your project root (or the global
175
+ `~/.cursor/mcp.json`):
176
+
177
+ ```json
178
+ {
179
+ "servers": {
180
+ "tommy": {
181
+ "command": "tommy",
182
+ "args": ["--mcp"]
183
+ }
184
+ }
185
+ }
186
+ ```
187
+
188
+ ### VS Code + Continue
189
+
190
+ In `.continue/config.json`:
191
+
192
+ ```json
193
+ {
194
+ "mcpServers": [
195
+ {
196
+ "name": "tommy",
197
+ "command": "tommy",
198
+ "args": ["--mcp"]
199
+ }
200
+ ]
201
+ }
202
+ ```
203
+
204
+ ### Zed
205
+
206
+ In `~/.config/zed/settings.json`:
207
+
208
+ ```json
209
+ {
210
+ "context_servers": {
211
+ "tommy": {
212
+ "command": {
213
+ "path": "tommy",
214
+ "args": ["--mcp"]
215
+ }
216
+ }
217
+ }
218
+ }
219
+ ```
220
+
221
+ ---
222
+
223
+ ## MCP tools
224
+
225
+ | Tool | Description |
226
+ |------|-------------|
227
+ | `tommy_recall` | Query memnos memory for context |
228
+ | `tommy_remember` | Persist a fact / decision to memnos |
229
+ | `tommy_dispatch` | Launch a harness task (async by default) |
230
+ | `tommy_status` | Check a running task's output / exit code |
231
+ | `tommy_control` | Send `wrap_up` / `abort` / `pivot` / `answer` to a running task |
232
+ | `tommy_switch_project` | Set active project (workspace + namespace) |
233
+ | `tommy_route` | Dry-run: which harness would Tommy pick? |
234
+ | `tommy_list_harnesses` | Available harnesses + active routing config |
235
+
236
+ ### `tommy_dispatch`
237
+
238
+ ```
239
+ tommy_dispatch(
240
+ task="refactor the auth module to use PKCE",
241
+ harness="auto", # or "claude", "codex", …
242
+ workspace="/path/to/repo",
243
+ async_run=True, # return task_id immediately
244
+ inject_memory=True, # prepend memnos recall to prompt
245
+ )
246
+ → {"task_id": "a3f1b2c4", "status": "running", "harness": "claude"}
247
+ ```
248
+
249
+ ### `tommy_control` — steer a running task
250
+
251
+ ```
252
+ # Ask the harness to wrap up (gives it 60 s to finish gracefully)
253
+ tommy_control(task_id="a3f1b2c4", action="wrap_up", budget_seconds=60)
254
+
255
+ # Stop immediately
256
+ tommy_control(task_id="a3f1b2c4", action="abort")
257
+
258
+ # Redirect to a different goal mid-run
259
+ tommy_control(task_id="a3f1b2c4", action="pivot",
260
+ message="focus only on the login flow, skip registration")
261
+
262
+ # Answer a question the harness asked
263
+ tommy_control(task_id="a3f1b2c4", action="answer", message="yes, overwrite")
264
+ ```
265
+
266
+ The harness receives the message over a **TCP loopback control channel**
267
+ (`TOMMY_CTRL_PORT` env var) — no polling required.
268
+
269
+ ---
270
+
271
+ ## Control channel (for harness authors)
272
+
273
+ If you write a custom harness in Python, connect back to Tommy using the
274
+ bundled `ControlClient`:
275
+
276
+ ```python
277
+ from tommy.control import ControlClient
278
+
279
+ def handle_tommy_message(msg: dict) -> None:
280
+ if msg["type"] == "wrap_up":
281
+ # save state and exit within msg["budget_seconds"]
282
+ ...
283
+ elif msg["type"] == "abort":
284
+ raise SystemExit(1)
285
+ elif msg["type"] == "pivot":
286
+ current_goal = msg["new_goal"]
287
+ elif msg["type"] == "answer":
288
+ # Reply to a question you sent via client.question()
289
+ user_answer = msg["text"]
290
+
291
+ client = ControlClient(on_control=handle_tommy_message)
292
+
293
+ # Report progress
294
+ client.progress(25, "parsed 250 / 1000 files")
295
+ client.checkpoint("analysis", "found 3 duplicate patterns")
296
+
297
+ # Send a question to Tommy/user; answer arrives via the on_control callback as {"type": "answer", "text": ...}
298
+ client.question("Should I overwrite existing tests?", options=["yes", "no"])
299
+
300
+ client.done("refactoring complete — 12 files changed")
301
+ client.close()
302
+ ```
303
+
304
+ The client auto-reads `TOMMY_CTRL_PORT` from the environment.
305
+
306
+ **Protocol (newline-delimited JSON):**
307
+
308
+ | Direction | `type` | Extra fields |
309
+ |-----------|--------|-------------|
310
+ | Harness → Tommy | `progress` | `pct`, `detail` |
311
+ | Harness → Tommy | `checkpoint` | `phase`, `summary` |
312
+ | Harness → Tommy | `done` | `summary` |
313
+ | Harness → Tommy | `error` | `message` |
314
+ | Harness → Tommy | `question` | `text`, `options` |
315
+ | Tommy → Harness | `wrap_up` | `reason`, `budget_seconds` |
316
+ | Tommy → Harness | `abort` | — |
317
+ | Tommy → Harness | `pivot` | `new_goal` |
318
+ | Tommy → Harness | `answer` | `text` |
319
+
320
+ The control channel uses TCP loopback (`127.0.0.1`), which works on macOS,
321
+ Linux, and Windows without any extra setup.
322
+
323
+ ---
324
+
325
+ ## Upgrade
326
+
327
+ ```bash
328
+ tommy --upgrade
329
+ ```
330
+
331
+ Tommy detects whether it was installed with `uv`, `pipx`, or `pip` and uses
332
+ the same tool to upgrade — so the venv is never mixed.
333
+
334
+ To upgrade manually with uv:
335
+
336
+ ```bash
337
+ uv tool install -e ~/git/memnos/agents/tommy --force
338
+ ```
339
+
340
+ ---
341
+
342
+ ## Project structure
343
+
344
+ ```
345
+ agents/tommy/
346
+ ├── README.md ← you are here
347
+ ├── pyproject.toml
348
+ └── tommy/
349
+ ├── __init__.py
350
+ ├── cli.py ← click entrypoint, _launch_harness
351
+ ├── config.py ← TommyConfig, ProjectEntry
352
+ ├── control.py ← ControlServer + ControlClient (TCP IPC)
353
+ ├── install.py ← tommy --install
354
+ ├── mcp_server.py ← FastMCP stdio server, 8 tools
355
+ ├── prompt.py ← memnos-enriched system prompt builder
356
+ └── discovery/
357
+ └── harnesses.py ← auto-detect installed harnesses
358
+ ```
359
+
360
+ ---
361
+
362
+ ## Roadmap
363
+
364
+ - [ ] Supervision loop: idle + wall-clock timeout with automatic `wrap_up`
365
+ - [ ] Smart harness routing by task type (coding vs. research vs. review)
366
+ - [ ] memnos lease heartbeat while harness is running
367
+ - [ ] Multi-harness fan-out (run two harnesses in parallel, merge outputs)