agent-dispatch 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
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: ${{ matrix.python-version }}
22
+
23
+ - name: Install dependencies
24
+ run: pip install -e ".[dev]"
25
+
26
+ - name: Lint
27
+ run: ruff check src/ tests/
28
+
29
+ - name: Test
30
+ run: pytest tests/ -v
@@ -0,0 +1,26 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ environment: pypi
11
+ permissions:
12
+ id-token: write
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.12"
19
+
20
+ - name: Build
21
+ run: |
22
+ pip install build
23
+ python -m build
24
+
25
+ - name: Publish to PyPI
26
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,20 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+ *.egg
9
+ .venv/
10
+ venv/
11
+ .env
12
+ .pytest_cache/
13
+ .ruff_cache/
14
+ .mypy_cache/
15
+ *.so
16
+ .DS_Store
17
+ CLAUDE.md
18
+ .claude/
19
+ .mcp.json
20
+ *.db
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ginkida
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,353 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-dispatch
3
+ Version: 0.1.0
4
+ Summary: MCP server that lets Claude Code agents delegate tasks to agents in other project directories
5
+ Project-URL: Homepage, https://github.com/ginkida/agent-dispatch
6
+ Project-URL: Repository, https://github.com/ginkida/agent-dispatch
7
+ Project-URL: Issues, https://github.com/ginkida/agent-dispatch/issues
8
+ Author: ginkida
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,claude,dispatch,mcp,multi-agent
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: click>=8.0
23
+ Requires-Dist: mcp[cli]>=1.2.0
24
+ Requires-Dist: pyyaml>=6.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
27
+ Requires-Dist: pytest>=8.0; extra == 'dev'
28
+ Requires-Dist: ruff>=0.4; extra == 'dev'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # agent-dispatch
32
+
33
+ **MCP server that lets Claude Code agents delegate tasks to agents in other project directories.**
34
+
35
+ Each agent runs as a separate `claude -p` session in its own project directory — inheriting that project's MCP servers, CLAUDE.md, and tools. The calling agent just gets the result back.
36
+
37
+ Works with OAuth, API key, and Claude subscription authentication.
38
+
39
+ ## Quick Start
40
+
41
+ ```bash
42
+ pip install agent-dispatch
43
+
44
+ # Initialize: creates config + registers MCP server with Claude Code
45
+ agent-dispatch init
46
+
47
+ # Add agents (description auto-generated from project files)
48
+ agent-dispatch add infra ~/projects/infra
49
+ agent-dispatch add backend ~/projects/backend
50
+
51
+ # Test it works
52
+ agent-dispatch test infra
53
+ ```
54
+
55
+ Done. Every Claude Code session now has access to all dispatch tools.
56
+
57
+ ## When to Dispatch
58
+
59
+ **Do dispatch** when a task needs tools, files, or context from another project:
60
+ - Check container logs via infra agent's Portainer MCP
61
+ - Query a database via db agent's postgres MCP
62
+ - Read code or run tests in another repository
63
+
64
+ **Don't dispatch** when you can do it yourself — dispatching spawns a full Claude session.
65
+
66
+ ## MCP Tools Reference
67
+
68
+ ### `list_agents`
69
+
70
+ Lists all configured agents. **Call this first** to see what's available.
71
+
72
+ ```json
73
+ // Response
74
+ [
75
+ {
76
+ "name": "infra",
77
+ "directory": "/home/user/projects/infra",
78
+ "description": "Infrastructure agent. MCP: portainer. Stack: Python, Docker",
79
+ "healthy": true,
80
+ "has_claude_md": true,
81
+ "has_mcp_config": true
82
+ }
83
+ ]
84
+ ```
85
+
86
+ ### `dispatch`
87
+
88
+ One-shot task delegation. Results are cached — identical requests within TTL return instantly.
89
+
90
+ | Parameter | Type | Required | Description |
91
+ |-----------|------|----------|-------------|
92
+ | `agent` | string | yes | Agent name from `list_agents` |
93
+ | `task` | string | yes | What to do — be specific, the agent has no context from your conversation |
94
+ | `context` | string | no | Extra context: error messages, code snippets, stack traces |
95
+ | `caller` | string | no | Your project/role — helps the agent understand who's asking |
96
+ | `goal` | string | no | Broader objective — helps the agent make better trade-offs |
97
+
98
+ ```json
99
+ // Response
100
+ {
101
+ "agent": "infra",
102
+ "success": true,
103
+ "result": "Found 3 errors in container logs: TypeError in scheduler.py:42...",
104
+ "session_id": "sess-abc-123",
105
+ "cost_usd": 0.02,
106
+ "duration_ms": 5000,
107
+ "num_turns": 2
108
+ }
109
+ ```
110
+
111
+ **Always pass `caller` and `goal`** — the dispatched agent sees a structured prompt:
112
+
113
+ ```markdown
114
+ ## Goal
115
+ debug production crash
116
+
117
+ ## Dispatched by
118
+ backend
119
+
120
+ ## Context
121
+ Error: TypeError at scheduler.py:42
122
+
123
+ ## Task
124
+ Check container logs for recent errors related to the scheduler service
125
+ ```
126
+
127
+ ### `dispatch_session`
128
+
129
+ Multi-turn: continue a conversation with an agent. First call starts a session, pass `session_id` back to continue. Never cached.
130
+
131
+ | Parameter | Type | Required | Description |
132
+ |-----------|------|----------|-------------|
133
+ | `agent` | string | yes | Agent name |
134
+ | `task` | string | yes | Task or follow-up message |
135
+ | `session_id` | string | no | From previous response — empty for new session |
136
+ | `context` | string | no | Extra context |
137
+ | `caller` | string | no | Who is dispatching |
138
+ | `goal` | string | no | Broader objective |
139
+
140
+ ```
141
+ Turn 1: dispatch_session("infra", "List running containers")
142
+ → session_id: "sess-abc"
143
+
144
+ Turn 2: dispatch_session("infra", "Restart the nginx one", session_id="sess-abc")
145
+ → agent remembers previous context
146
+ ```
147
+
148
+ ### `dispatch_parallel`
149
+
150
+ Run multiple tasks concurrently. Much faster than sequential `dispatch` calls.
151
+
152
+ | Parameter | Type | Required | Description |
153
+ |-----------|------|----------|-------------|
154
+ | `dispatches` | string (JSON) | yes | JSON array of `{"agent", "task", "context?", "caller?", "goal?"}` |
155
+ | `aggregate` | string | no | Agent name to synthesize all results into one answer |
156
+
157
+ **Important:** `dispatches` is a JSON string, not a list.
158
+
159
+ ```json
160
+ // Input
161
+ [
162
+ {"agent": "infra", "task": "check pod logs for errors", "caller": "backend", "goal": "debug crash"},
163
+ {"agent": "db", "task": "are all migrations applied?", "caller": "backend", "goal": "debug crash"}
164
+ ]
165
+ ```
166
+
167
+ ```json
168
+ // Response (without aggregate)
169
+ [
170
+ {"agent": "infra", "success": true, "result": "No errors in pod logs", ...},
171
+ {"agent": "db", "success": true, "result": "All migrations applied", ...}
172
+ ]
173
+ ```
174
+
175
+ ```json
176
+ // Response (with aggregate="backend")
177
+ {
178
+ "individual_results": [
179
+ {"agent": "infra", "success": true, "result": "No errors in pod logs", ...},
180
+ {"agent": "db", "success": true, "result": "All migrations applied", ...}
181
+ ],
182
+ "aggregated": {
183
+ "agent": "backend",
184
+ "success": true,
185
+ "result": "Summary: all systems nominal. No pod errors, all migrations applied."
186
+ }
187
+ }
188
+ ```
189
+
190
+ ### `dispatch_stream`
191
+
192
+ Same as `dispatch` but shows live progress while the agent works. Use for long-running tasks. Not cached.
193
+
194
+ Parameters are identical to `dispatch`.
195
+
196
+ ### `dispatch_dialogue`
197
+
198
+ Two agents collaborate through multi-turn conversation. Never cached.
199
+
200
+ | Parameter | Type | Required | Description |
201
+ |-----------|------|----------|-------------|
202
+ | `requester` | string | yes | Agent with the problem/context |
203
+ | `responder` | string | yes | Agent with the expertise/tools |
204
+ | `topic` | string | yes | Problem or question to discuss |
205
+ | `max_rounds` | int | no | Max back-and-forth rounds (default: 3, max: 10) |
206
+
207
+ Each round costs up to 2 dispatches. Agents signal completion with `[RESOLVED]`.
208
+
209
+ ```json
210
+ // Response
211
+ {
212
+ "resolved": true,
213
+ "rounds": 2,
214
+ "total_cost_usd": 0.04,
215
+ "total_duration_ms": 12000,
216
+ "final_answer": "Staging had 1 pending migration. Applied successfully.",
217
+ "conversation": [
218
+ {"agent": "db", "role": "responder", "round": 1, "message": "Which environment?", "cost_usd": 0.01},
219
+ {"agent": "backend", "role": "requester", "round": 1, "message": "Staging", "cost_usd": 0.01},
220
+ {"agent": "db", "role": "responder", "round": 2, "message": "Applied. [RESOLVED]", "cost_usd": 0.01}
221
+ ]
222
+ }
223
+ ```
224
+
225
+ ### `add_agent`
226
+
227
+ Register a new project directory as an agent. Description is auto-generated from project files if omitted.
228
+
229
+ | Parameter | Type | Required | Description |
230
+ |-----------|------|----------|-------------|
231
+ | `name` | string | yes | Agent name (letters, digits, hyphens, underscores) |
232
+ | `directory` | string | yes | Absolute path to project directory |
233
+ | `description` | string | no | What this agent can do — auto-generated if empty |
234
+
235
+ ### `remove_agent`
236
+
237
+ Remove an agent from config.
238
+
239
+ | Parameter | Type | Required | Description |
240
+ |-----------|------|----------|-------------|
241
+ | `name` | string | yes | Agent name to remove |
242
+
243
+ ### `cache_stats` / `cache_clear`
244
+
245
+ View cache hit rate and size, or clear all cached results.
246
+
247
+ ### Error Responses
248
+
249
+ All tools return errors as:
250
+
251
+ ```json
252
+ {"error": "Unknown agent: 'foo'. Available: infra, db, monitoring"}
253
+ ```
254
+
255
+ ## Which Tool to Use
256
+
257
+ | Scenario | Tool |
258
+ |----------|------|
259
+ | Quick one-off question to another project | `dispatch` |
260
+ | Multi-step workflow with follow-ups | `dispatch_session` |
261
+ | Need answers from several agents at once | `dispatch_parallel` |
262
+ | Long task, want to see progress | `dispatch_stream` |
263
+ | Two agents need to collaborate | `dispatch_dialogue` |
264
+ | Need a combined summary from multiple agents | `dispatch_parallel` with `aggregate` |
265
+
266
+ ## Configuration
267
+
268
+ Config at `~/.config/agent-dispatch/agents.yaml` (override: `AGENT_DISPATCH_CONFIG` env var):
269
+
270
+ ```yaml
271
+ agents:
272
+ infra:
273
+ directory: ~/projects/infra
274
+ description: "Infrastructure agent. MCP: portainer."
275
+ timeout: 300 # seconds, default: 300
276
+ # model: sonnet # optional model override
277
+ # max_budget_usd: 1.0 # cost limit per dispatch
278
+ # permission_mode: auto # permission mode for the agent
279
+ # allowed_tools: # restrict which tools the agent can use
280
+ # - Read
281
+ # - Grep
282
+ # disallowed_tools: # block specific tools
283
+ # - Write
284
+
285
+ settings:
286
+ default_timeout: 300
287
+ max_dispatch_depth: 3 # recursion protection
288
+ max_concurrency: 5 # max parallel claude -p processes
289
+ cache:
290
+ enabled: true
291
+ ttl: 300 # seconds
292
+ ```
293
+
294
+ Config is reloaded on every tool call — add agents without restarting.
295
+
296
+ ### Auto-Description
297
+
298
+ `agent-dispatch add` without `--description` generates one from:
299
+
300
+ - `CLAUDE.md` — first meaningful paragraph (priority)
301
+ - `README.md` — first substantial line (fallback)
302
+ - `pyproject.toml` / `package.json` — project description
303
+ - `.mcp.json` — lists MCP server names
304
+ - Stack indicators — Docker, Rust, Go, Python, Node.js
305
+ - DB indicators — Prisma, Alembic, migrations
306
+
307
+ ## How It Works
308
+
309
+ ```
310
+ Your Claude Code session
311
+
312
+ ├─ dispatch("infra", "find errors", caller="backend", goal="debug crash")
313
+
314
+
315
+ agent-dispatch MCP server
316
+ ├─ cache check → hit? return cached result
317
+ ├─ semaphore → limit concurrent processes
318
+ └─ subprocess.run("claude -p ...", cwd=~/projects/infra/)
319
+
320
+
321
+ New Claude Code session in ~/projects/infra/
322
+ ├─ Inherits: CLAUDE.md, .mcp.json, project tools
323
+ ├─ Receives structured prompt with goal/caller/context/task
324
+ └─ Returns result → cached for future identical requests
325
+ ```
326
+
327
+ ## Safety
328
+
329
+ - **Recursion protection** — `AGENT_DISPATCH_DEPTH` env var tracks nesting. Default limit: 3.
330
+ - **Cost control** — `max_budget_usd` per agent or globally.
331
+ - **Concurrency** — `max_concurrency` (default: 5) limits parallel `claude -p` processes.
332
+ - **Timeout** — per-agent or global (default: 300s). Orphaned processes are cleaned up.
333
+ - **Caching** — identical `(agent, task, context)` requests return cached results. Only successes are cached. Sessions and dialogues are never cached.
334
+
335
+ ## CLI
336
+
337
+ | Command | Description |
338
+ |---------|-------------|
339
+ | `agent-dispatch init` | Create config + register MCP server with Claude Code |
340
+ | `agent-dispatch add <name> <dir>` | Add an agent (auto-generates description) |
341
+ | `agent-dispatch remove <name>` | Remove an agent |
342
+ | `agent-dispatch list` | List agents with health status |
343
+ | `agent-dispatch test <name> [task]` | Test an agent with a dispatch |
344
+ | `agent-dispatch serve` | Start MCP server (stdio, used by Claude Code) |
345
+
346
+ ## Requirements
347
+
348
+ - Python >= 3.10
349
+ - [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated
350
+
351
+ ## License
352
+
353
+ MIT