dispatchbox 0.1.0__py3-none-any.whl
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.
- dispatchbox/__init__.py +3 -0
- dispatchbox/__main__.py +127 -0
- dispatchbox/chat.py +209 -0
- dispatchbox/cron.py +56 -0
- dispatchbox/feishu.py +304 -0
- dispatchbox/hub.py +550 -0
- dispatchbox/net.py +33 -0
- dispatchbox/rules.py +236 -0
- dispatchbox/server.py +480 -0
- dispatchbox/slack.py +251 -0
- dispatchbox/store.py +99 -0
- dispatchbox/worker.py +314 -0
- dispatchbox-0.1.0.dist-info/METADATA +293 -0
- dispatchbox-0.1.0.dist-info/RECORD +18 -0
- dispatchbox-0.1.0.dist-info/WHEEL +5 -0
- dispatchbox-0.1.0.dist-info/entry_points.txt +2 -0
- dispatchbox-0.1.0.dist-info/licenses/LICENSE +21 -0
- dispatchbox-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dispatchbox
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Route events to Claude Code and Codex running on your own machines, and ask you only when it matters.
|
|
5
|
+
Author: Xixian Yang
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/XixianWasTaken/dispatchbox
|
|
8
|
+
Project-URL: Documentation, https://github.com/XixianWasTaken/dispatchbox/tree/main/docs
|
|
9
|
+
Project-URL: Issues, https://github.com/XixianWasTaken/dispatchbox/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/XixianWasTaken/dispatchbox/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: claude-code,codex,ai-agents,human-in-the-loop,webhooks,slack,feishu,automation
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: Software Development
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Provides-Extra: feishu-encryption
|
|
28
|
+
Requires-Dist: cryptography; extra == "feishu-encryption"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
<p align="center">
|
|
32
|
+
<img src="https://raw.githubusercontent.com/XixianWasTaken/dispatchbox/main/docs/logo.png" alt="dispatchbox logo" width="120">
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
<h1 align="center">dispatchbox</h1>
|
|
36
|
+
|
|
37
|
+
<p align="center">
|
|
38
|
+
<strong>Event-driven automation for Claude Code and Codex on your own machines.</strong><br>
|
|
39
|
+
Route webhooks, cron jobs, and chat messages to local coding agents—and pause for human approval only when an action crosses your risk boundary.
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
<p align="center">
|
|
43
|
+
<a href="https://github.com/XixianWasTaken/dispatchbox/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
|
|
44
|
+
<img alt="Python 3.10+" src="https://img.shields.io/badge/python-3.10%2B-blue.svg">
|
|
45
|
+
<img alt="Dependencies: stdlib only" src="https://img.shields.io/badge/dependencies-stdlib%20only-brightgreen.svg">
|
|
46
|
+
</p>
|
|
47
|
+
|
|
48
|
+
<p align="center">
|
|
49
|
+
<strong>English</strong> · <a href="https://github.com/XixianWasTaken/dispatchbox/blob/main/README.zh-CN.md">简体中文</a> · <a href="https://github.com/XixianWasTaken/dispatchbox/blob/main/docs/README.md">Documentation</a> · <a href="https://github.com/XixianWasTaken/dispatchbox/blob/main/docs/rules.md">Rules Guide</a> · <a href="https://github.com/XixianWasTaken/dispatchbox/blob/main/docs/reference.md">CLI & API Reference</a>
|
|
50
|
+
</p>
|
|
51
|
+
|
|
52
|
+
**dispatchbox** is a lightweight hub-and-worker daemon (~2,700 lines of dependency-free Python) that turns **Claude Code (`claude`)** and **OpenAI Codex CLI (`codex`)** from interactive terminal tools into event-driven background workers running on your own hardware.
|
|
53
|
+
|
|
54
|
+
Incoming signals—GitHub webhooks, 5-field cron schedules, Slack or Feishu mentions, or any `POST /events` payload—are normalized, deduplicated, and matched against a hot-reloading JSON rules file. Workers on your macOS or Linux machines long-poll the hub over outbound HTTP, execute `claude` or `codex` in allowed local directories using your existing CLI login, and report structured results, token usage, and session IDs.
|
|
55
|
+
|
|
56
|
+
When an agent reaches an operation you classified as sensitive (such as `delete_data` or `spend_money`), it pauses and sends an interactive decision prompt to Slack, Feishu, or the built-in web dashboard. Clicking an option emits a `decision.made` event; a follow-up rule matching it resumes the same agent session (`claude --resume` / `codex exec resume`), optionally with wider tool permissions to finish the job.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git clone https://github.com/XixianWasTaken/dispatchbox.git && cd dispatchbox
|
|
60
|
+
python3 -m dispatchbox check --rules examples/hello.json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Table of contents
|
|
64
|
+
|
|
65
|
+
- [Why dispatchbox?](#why-dispatchbox)
|
|
66
|
+
- [Quick start (2 minutes)](#quick-start)
|
|
67
|
+
- [Installation](#installation)
|
|
68
|
+
- [Core capabilities](#core-capabilities)
|
|
69
|
+
- [Real-world use cases](#real-world-use-cases)
|
|
70
|
+
- [How it works](#how-it-works)
|
|
71
|
+
- [Comparison with alternatives](#comparison-with-alternatives)
|
|
72
|
+
- [Limitations & trade-offs](#limitations--trade-offs)
|
|
73
|
+
- [Security model](#security-model)
|
|
74
|
+
- [Documentation](#documentation)
|
|
75
|
+
- [Development & contributing](#development--contributing)
|
|
76
|
+
- [License](#license)
|
|
77
|
+
|
|
78
|
+
## Why dispatchbox?
|
|
79
|
+
|
|
80
|
+
Most developers already have `claude` or `codex` signed in on their workstation with access to local repositories, toolchains, and credentials. Automating those agents on background events usually forces an unpleasant trade-off:
|
|
81
|
+
|
|
82
|
+
1. **Cloud runners lack your local environment.** Running agents in GitHub Actions or vendor-hosted sandboxes means re-provisioning toolchains and copying secrets into an environment that is not the one you develop in.
|
|
83
|
+
2. **Unattended agents are either too risky or too noisy.** Giving a background agent unrestricted `Bash` permissions on your machine is dangerous, while requiring approval on every tool call defeats the purpose of background automation.
|
|
84
|
+
3. **Ad-hoc cron scripts and chat wrappers lose context.** Simple shell wrappers around `claude -p` do not deduplicate webhook bursts, serialize concurrent runs on the same branch, detect silent permission failures when a CLI exits `0`, or preserve session state across human approvals.
|
|
85
|
+
|
|
86
|
+
`dispatchbox` solves all three with a minimal, inspectable architecture:
|
|
87
|
+
|
|
88
|
+
- **Bring your own machine and CLI subscription**: No model API keys to configure in `dispatchbox`. Workers invoke the stock `claude` and `codex` binaries already installed on your macOS or Linux machines.
|
|
89
|
+
- **Two-stage privilege escalation via session resume**: Start runs with narrow, read-only flags (e.g., `--allowed-tools Read,Glob,Grep`). When the agent asks for approval and you confirm, the follow-up rule resumes the same session ID with targeted write permissions (e.g., `Bash(rm:*)`).
|
|
90
|
+
- **Outbound-only workers**: Workers pull tasks via `GET /claim` long polling. Your workstation or Mac mini behind home NAT never needs an open inbound port.
|
|
91
|
+
|
|
92
|
+
## Quick start
|
|
93
|
+
|
|
94
|
+
**Prerequisites:**
|
|
95
|
+
- Python **3.10+** (uses the Python standard library only; no `pip install` required).
|
|
96
|
+
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (`claude`) or [Codex CLI](https://github.com/openai/codex) (`codex`) installed and signed in (`examples/hello.json` uses `claude`).
|
|
97
|
+
|
|
98
|
+
### 1. Create a scratch workspace and shared token
|
|
99
|
+
|
|
100
|
+
From the repository root, create a `./demo` directory with two sample files and generate a `DISPATCHBOX_TOKEN`:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
mkdir -p demo && echo "stale" > demo/old.log && echo "# notes" > demo/notes.md
|
|
104
|
+
export DISPATCHBOX_TOKEN="$(python3 -c 'import secrets; print(secrets.token_urlsafe(32))')"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 2. Start the hub
|
|
108
|
+
|
|
109
|
+
The bundled [`examples/hello.json`](https://github.com/XixianWasTaken/dispatchbox/blob/main/examples/hello.json) defines `require_decision_for: ["delete_data"]` and three rules:
|
|
110
|
+
- `ask`: read-only (`--allowed-tools Read,Glob,Grep`)
|
|
111
|
+
- `tidy`: read-only initially; must ask before deleting any file
|
|
112
|
+
- `after-decision`: triggered on `dispatchbox/decision.made`; resumes the session with `Read,Glob,Grep,Bash(rm:*)`
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
python3 -m dispatchbox hub --rules examples/hello.json
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 3. Start a local worker
|
|
119
|
+
|
|
120
|
+
In a **second terminal** (with the same `DISPATCHBOX_TOKEN` exported), start a worker restricted to `./demo`:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
export DISPATCHBOX_TOKEN="<paste-same-token>"
|
|
124
|
+
python3 -m dispatchbox worker --name local --allow-dir ./demo
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 4. Dispatch two events
|
|
128
|
+
|
|
129
|
+
In a **third terminal** (with the same `DISPATCHBOX_TOKEN` exported), send a read-only question and a file-deletion request:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
export DISPATCHBOX_TOKEN="<paste-same-token>"
|
|
133
|
+
python3 -m dispatchbox send manual ask --summary "What files are here?"
|
|
134
|
+
python3 -m dispatchbox send manual tidy --summary "Delete old.log"
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Both events are routed immediately:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{"event_id": 1, "status": "routed", "runs": [1], "coalesced_into": []}
|
|
141
|
+
{"event_id": 2, "status": "routed", "runs": [2], "coalesced_into": []}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 5. Approve the decision and watch the session resume
|
|
145
|
+
|
|
146
|
+
In the hub terminal log, run `#1` finishes on its own, while run `#2` pauses at the `delete_data` boundary:
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
NOTIFY [dispatchbox] run #1 ask: succeeded | The directory holds two small files, notes.md and old.log, and nothing else. | Open: /runs/1
|
|
150
|
+
NOTIFY [dispatchbox] run #2 tidy: awaiting_decision | Question: Delete old.log from the working directory? | Options: Delete old.log / Keep old.log | Context: Found old.log (6 bytes, modified Nov 3 04:55) in the demo directory next to notes.md; no deletion has been performed. | Open: /runs/2
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Open **http://127.0.0.1:8787** in your browser, click run **`#2`**, and click **Delete old.log**. Your choice emits a `decision.made` event, queuing run `#3` (`after-decision`), which resumes run `#2`'s Claude session with `Bash(rm:*)` enabled:
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
NOTIFY [dispatchbox] run #3 after-decision: succeeded | Deleted old.log from the demo directory after owner approval and verified only notes.md remains. | Open: /runs/3
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Installation
|
|
160
|
+
|
|
161
|
+
dispatchbox is on PyPI and has no dependencies:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
pip install dispatchbox # or: uv tool install dispatchbox
|
|
165
|
+
dispatchbox --version
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
The installed `dispatchbox` command is the same as `python3 -m dispatchbox` in the quick start. The quick start runs from a clone because it uses the bundled `examples/hello.json`. To decrypt Feishu events signed with an Encrypt Key, install the optional extra: `pip install "dispatchbox[feishu-encryption]"`.
|
|
169
|
+
|
|
170
|
+
## Core capabilities
|
|
171
|
+
|
|
172
|
+
### 1. Multi-source event normalization, deduplication, and coalescing
|
|
173
|
+
GitHub webhooks (`pull_request`, `issues`, `issue_comment`, `pull_request_review_comment`, `push`, `workflow_run`), built-in 5-field cron schedules, Slack mentions/DMs, Feishu messages, and `POST /events` calls all normalize into a single event schema (`source`, `type`, `subject`, `summary`, `link`, `payload`, `dedupe_key`).
|
|
174
|
+
- **Deduplication**: Repeated events within `dedupe_window` (default `10m`, or `24h` for chat events) are dropped automatically.
|
|
175
|
+
- **Coalescing**: When rapid-fire events (e.g., three commits pushed to the same PR or follow-up comments) match a rule while a run for the same `group` is still `queued`, they merge into that queued run so the agent handles the full batch in one pass.
|
|
176
|
+
|
|
177
|
+
### 2. Policy-gated human-in-the-loop with session continuation
|
|
178
|
+
Instead of approving individual bash commands, you declare high-level risk categories in `require_decision_for` (e.g., `["delete_data", "spend_money", "send_external_message"]`).
|
|
179
|
+
- When an agent hits one of those boundaries, it outputs a structured `DISPATCHBOX_DECISION:` line and exits cleanly.
|
|
180
|
+
- The hub transitions the run to `awaiting_decision` and renders interactive option buttons in Slack, Feishu, or the web UI.
|
|
181
|
+
- Recording a decision emits a `dispatchbox/decision.made` event carrying the run's `run_id` and `session_id`. If a rule matches that event (like `after-decision` in the examples), its run invokes `claude --resume <session_id>` or `codex exec resume <session_id>`, keeping the agent's context while applying that rule's tool flags. Without such a rule, nothing happens after the decision.
|
|
182
|
+
- **Standing memory**: Configure `"memory": ["DECISIONS.md", "WONT_DO.md"]` so agents read prior owner rulings before asking repetitive questions.
|
|
183
|
+
|
|
184
|
+
### 3. Pull-based workers with directory and concurrency guards
|
|
185
|
+
- **NAT-friendly**: Workers poll `GET /claim` over outbound HTTP/HTTPS. Run the hub on a small VPS or behind a Cloudflare Tunnel while workers run on your local workstation, build server, or laptop.
|
|
186
|
+
- **Directory allowlisting**: Workers enforce `--allow-dir` (repeatable) and refuse any rule whose `cwd` resolves outside allowed paths (exit code `126`).
|
|
187
|
+
- **Process and secret hygiene**: Prompts are piped via `stdin` (never exposed in `ps` process arguments), `DISPATCHBOX_TOKEN` is stripped from the child environment, and timed-out process groups are terminated cleanly (`SIGTERM` then `SIGKILL`).
|
|
188
|
+
- **Group serialization & concurrency**: Runs sharing a `group` key (default `{rule}:{subject}`) never execute concurrently, preventing git index locks or race conditions on the same repo/PR, while `concurrency` caps parallel runs per rule across all workers.
|
|
189
|
+
|
|
190
|
+
### 4. Honest status reporting, usage accounting, and automatic retries
|
|
191
|
+
- **Agent verdict over exit code**: When a coding agent is blocked by `--allowed-tools` or sandbox flags, the CLI process often still exits `0`. `dispatchbox` requires agents to emit `DISPATCHBOX_STATUS: succeeded | failed` and marks a run `failed` if either the exit code is non-zero or the agent reports `failed`.
|
|
192
|
+
- **Cost & token tracking**: Parses `claude -p --output-format json` (capturing `total_cost_usd`, fresh + cached input tokens, and output tokens) and `codex exec --json` (capturing `input_tokens` and `output_tokens`).
|
|
193
|
+
- **Heartbeat reaping & retries**: Workers send heartbeats every 20 seconds. If a worker goes silent for >120 seconds, the hub marks the run `lost` and (if `retries > 0`) re-queues it with a prompt warning that a prior attempt may have partially completed the task.
|
|
194
|
+
|
|
195
|
+
### 5. Thread-aware Slack and Feishu chat-ops
|
|
196
|
+
- Mention the bot or DM it in **Slack** or **Feishu (飞书)** to trigger a run.
|
|
197
|
+
- Enforce strict user access via hot-reloaded `allowed_users` (who can trigger runs) and `approvers` (who can click decision buttons).
|
|
198
|
+
- Replies, decision cards, and post-decision follow-up answers stay in the originating chat thread, with internal `DISPATCHBOX_*` protocol markers stripped automatically.
|
|
199
|
+
|
|
200
|
+
## Real-world use cases
|
|
201
|
+
|
|
202
|
+
[`rules.example.json`](https://github.com/XixianWasTaken/dispatchbox/blob/main/rules.example.json) contains example rules to adapt. Replace its placeholder worker names (`m4`, `m5`), paths and sources with your own:
|
|
203
|
+
|
|
204
|
+
1. **Automated read-only PR reviews (`codex`)**: Trigger on `github` `pr.opened` / `pr.synchronize`, run `codex` with `-s read-only` in your local checkout, and post actionable bug reports via `gh pr review`.
|
|
205
|
+
2. **Self-healing CI failures (`claude`)**: Trigger on `github` `ci.failure`, route to a specific build machine (`"worker": "m4"`), allow `Bash(git:*),Bash(gh:*),Bash(npm test:*)`, and let Claude inspect logs and push a fix to the failing branch.
|
|
206
|
+
3. **Two-stage destructive maintenance (a pattern to write yourself)**: Give a `cron` rule read-only `args` and list `delete_data` in `require_decision_for`, so the agent finds stale resources and asks first; approve from Slack or Feishu, and an `after-decision` rule resumes the session with delete permissions. `rules.example.json` does not include this; its `nightly-cleanup` rule runs weekly without an approval step. [`examples/hello.json`](https://github.com/XixianWasTaken/dispatchbox/blob/main/examples/hello.json) shows the same two-stage pattern on a small scale (`tidy`, then `after-decision`).
|
|
207
|
+
4. **Test rules before running**: Validate your configuration and dry-run event matching from the CLI:
|
|
208
|
+
```bash
|
|
209
|
+
python3 -m dispatchbox check --rules rules.example.json --source github --type ci.failure --subject me/app:main
|
|
210
|
+
# ok: 7 rules, 1 schedules, dedupe window 600s
|
|
211
|
+
# matches: ci-failed
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## How it works
|
|
215
|
+
|
|
216
|
+
<p align="center">
|
|
217
|
+
<img src="https://raw.githubusercontent.com/XixianWasTaken/dispatchbox/main/docs/how-it-works.png" alt="dispatchbox system architecture and workflow diagram" width="100%">
|
|
218
|
+
</p>
|
|
219
|
+
|
|
220
|
+
1. **Ingest & Match**: The hub receives an event, checks `dedupe_key` against the SQLite `events` table, evaluates `rules.json` in order, and either coalesces the event into an existing `queued` run or inserts a new `queued` run.
|
|
221
|
+
2. **Claim & Render**: A worker matching the rule's `worker` glob pattern and `runner` capability claims the run via `GET /claim`. The hub renders the prompt template (`{subject}`, `{summary}`, `{payload.*}`), appends trigger metadata, standing `memory` file instructions, and the `DISPATCHBOX_*` reporting contract.
|
|
222
|
+
3. **Execute & Parse**: The worker verifies `cwd` is inside `--allow-dir`, spawns `claude`, `codex`, or `/bin/sh`, streams heartbeats every 20s, and parses the CLI's JSON output for the final response, `session_id`, token counts, and cost.
|
|
223
|
+
4. **Decide & Resume**: If the output contains `DISPATCHBOX_DECISION: {...}`, the run enters `awaiting_decision`. When an authorized user selects an option (via Web UI, Slack, Feishu, or `POST /runs/{id}/decision`), the hub records the choice and emits a `dispatchbox/decision.made` event. A rule matching that event queues a follow-up run with the original run as its parent, and the worker resumes the parent's `session_id`.
|
|
224
|
+
|
|
225
|
+
See [Architecture](https://github.com/XixianWasTaken/dispatchbox/blob/main/docs/architecture.md) for the sequence diagram, SQLite schema, and module breakdown.
|
|
226
|
+
|
|
227
|
+
## Comparison with alternatives
|
|
228
|
+
|
|
229
|
+
| Approach | Where it excels | What dispatchbox does differently |
|
|
230
|
+
|---|---|---|
|
|
231
|
+
| **[Claude Code GitHub Actions](https://docs.anthropic.com/en/docs/claude-code/github-actions)** | Running Claude on GitHub-hosted runners for GitHub repo events | Runs on **your own machines** with local toolchains and signed-in CLIs; supports **Codex**, cron, Slack, Feishu, and custom HTTP events; supports mid-task **decision pause & session resume** |
|
|
232
|
+
| **Chat-only agent bots** (Slack/Discord wrappers) | Interactive Q&A with a local agent from a chat channel | Handles non-chat sources (webhooks, cron, HTTP); provides **deduplication, event coalescing, group serialization, and per-rule concurrency**; supports both Slack and Feishu |
|
|
233
|
+
| **Agent orchestration SDKs** (LangGraph, custom Python/TS) | Building bespoke agents with fine-grained programmatic tool hooks | **Zero code to write**; orchestrates unmodified `claude` and `codex` CLIs via a declarative JSON rules file |
|
|
234
|
+
| **General workflow engines** (n8n, Zapier, cron scripts) | Connecting SaaS APIs or running stateless shell scripts | Purpose-built for coding agents: **outbound long-polling workers**, `stdin` prompt piping, **session ID resumption**, agent verdict parsing (`DISPATCHBOX_STATUS`), and token/cost tracking |
|
|
235
|
+
| **Cloud background agents** (Devin, hosted coding sandboxes) | Fully managed cloud execution without local hardware | **Self-hosted and zero-dependency**: code, credentials, and execution stay on your hardware |
|
|
236
|
+
|
|
237
|
+
**When to use dispatchbox:**
|
|
238
|
+
You already use Claude Code or Codex locally, want them to react automatically to webhooks, schedules, or chat messages on your own machines, and want human approval strictly at high-risk boundaries.
|
|
239
|
+
|
|
240
|
+
**When not to use dispatchbox:**
|
|
241
|
+
You need multi-node high availability, multi-tenant isolation across untrusted users, a built-in VM/container sandbox, or a drag-and-drop visual workflow builder.
|
|
242
|
+
|
|
243
|
+
## Limitations & trade-offs
|
|
244
|
+
|
|
245
|
+
- **Single-process hub**: State lives in one local SQLite database (`WAL` mode). There is no multi-node clustering or automatic failover.
|
|
246
|
+
- **Public HTTPS required for Slack and Feishu**: Both chat platforms deliver events and button callbacks via HTTP webhooks (`POST /hooks/slack`, `POST /hooks/feishu`), requiring a reverse proxy or tunnel (e.g., `cloudflared`). Slack Socket Mode and Feishu WebSocket long connections are not supported yet.
|
|
247
|
+
- **Prompt-level reporting contract**: `DISPATCHBOX_DECISION`, `DISPATCHBOX_STATUS`, and `DISPATCHBOX_SUMMARY` rely on the agent following prompt instructions. If an agent exits `0` without printing a status line, the hub treats the run as `succeeded`.
|
|
248
|
+
- **CLI JSON format coupling**: `dispatchbox` parses `claude -p --output-format json` and `codex exec --json`. Breaking upstream changes to those CLI flags or JSON schemas require updating `dispatchbox/worker.py`.
|
|
249
|
+
- **No built-in OS sandbox**: `dispatchbox` enforces `--allow-dir` for the working directory, but sandboxing the agent's actions relies on the flags you pass in `args` (such as Claude's `--allowed-tools` or Codex's `-s read-only`) and the OS user account running the worker.
|
|
250
|
+
|
|
251
|
+
## Security model
|
|
252
|
+
|
|
253
|
+
A worker executes coding agents on your machine under your OS user account. Keep these essentials in mind:
|
|
254
|
+
|
|
255
|
+
- **Protect `DISPATCHBOX_TOKEN`**: The bearer token authorizes queueing events and claiming tasks. Treat it like an SSH key.
|
|
256
|
+
- **Apply least privilege per rule**: Always restrict initial rules using `--allowed-tools` (Claude) or `-s read-only` / `-s workspace-write` (Codex) in `args`. Grant broader permissions only in follow-up rules triggered after human approval (`decision.made`).
|
|
257
|
+
- **Treat event payloads as untrusted input**: Public GitHub issues, PR descriptions, and chat messages are injected into prompts. Never give rules triggered by untrusted external events unrestricted shell or write access.
|
|
258
|
+
- **Lock down public hubs**: Always pass `--public-url https://...` when exposing the hub behind a reverse proxy or tunnel so the web dashboard enforces token authentication on every request.
|
|
259
|
+
|
|
260
|
+
Read **[SECURITY.md](https://github.com/XixianWasTaken/dispatchbox/blob/main/SECURITY.md)** before exposing the hub to a network.
|
|
261
|
+
|
|
262
|
+
## Documentation
|
|
263
|
+
|
|
264
|
+
| Guide | What it covers |
|
|
265
|
+
|---|---|
|
|
266
|
+
| **[Documentation Index](https://github.com/XixianWasTaken/dispatchbox/blob/main/docs/README.md)** | Overview of all guides, example configs, and project roadmap |
|
|
267
|
+
| **[Rules, Events & Decisions](https://github.com/XixianWasTaken/dispatchbox/blob/main/docs/rules.md)** | Complete `rules.json` schema, event normalization, GitHub webhook mapping, templating, cron syntax, decisions, and retries |
|
|
268
|
+
| **[Slack & Feishu Integration](https://github.com/XixianWasTaken/dispatchbox/blob/main/docs/chat.md)** | Step-by-step app setup, permissions, signature/encryption verification, allowlists, and interactive cards |
|
|
269
|
+
| **[Deployment Guide](https://github.com/XixianWasTaken/dispatchbox/blob/main/docs/deployment.md)** | Single-machine vs. remote-hub topologies, `launchd` (macOS) and `systemd` (Linux) service templates, GitHub webhooks, and SQLite backups |
|
|
270
|
+
| **[CLI & API Reference](https://github.com/XixianWasTaken/dispatchbox/blob/main/docs/reference.md)** | All `dispatchbox` subcommands (`hub`, `worker`, `send`, `check`), environment variables, HTTP API endpoints, and run states |
|
|
271
|
+
| **[Architecture](https://github.com/XixianWasTaken/dispatchbox/blob/main/docs/architecture.md)** | Internal design decisions, request lifecycle, SQLite data model, and module breakdown |
|
|
272
|
+
| **[Troubleshooting](https://github.com/XixianWasTaken/dispatchbox/blob/main/docs/troubleshooting.md)** | Common exit codes (`124`, `126`, `127`), webhook signature errors, TLS certificate fixes, and stuck runs |
|
|
273
|
+
|
|
274
|
+
## Development & contributing
|
|
275
|
+
|
|
276
|
+
Run the full test suite (unit tests, end-to-end hub/worker tests with a scripted fake `claude` binary, and Slack/Feishu tests against a local mock API server) using Python's built-in test runner:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
python3 -m unittest discover -s tests -t . -v
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Validate rule files at any time:
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
python3 -m dispatchbox check --rules examples/hello.json
|
|
286
|
+
python3 -m dispatchbox check --rules rules.example.json
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Contributions are welcome! Please read **[CONTRIBUTING.md](https://github.com/XixianWasTaken/dispatchbox/blob/main/CONTRIBUTING.md)** for our design principles (stdlib-only core, thin over clever, safe by default) and instructions for adding new adapters.
|
|
290
|
+
|
|
291
|
+
## License
|
|
292
|
+
|
|
293
|
+
Released under the [MIT License](https://github.com/XixianWasTaken/dispatchbox/blob/main/LICENSE).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
dispatchbox/__init__.py,sha256=C6dgGeYTJL2LiLONy3UjIL_-ytx0mQ6o9VeVGWoiDyU,117
|
|
2
|
+
dispatchbox/__main__.py,sha256=_76aRMPkudxjaxgyMdamlj5AZ4UMu6nUlqy5iNL5FHA,5776
|
|
3
|
+
dispatchbox/chat.py,sha256=qlFFnLxGK7cAcd1Z1nEC-e6WkCsRW-ztJxxbRMuTR2Q,9380
|
|
4
|
+
dispatchbox/cron.py,sha256=Wgv2eCREvIbCxZjDR2eySM-bbvF2JQqUaSb7Zhkk830,2019
|
|
5
|
+
dispatchbox/feishu.py,sha256=D5YYQ5CgRZiw_OvqwBKkbOaSU-cdYVquRlTwu7jZAaE,14542
|
|
6
|
+
dispatchbox/hub.py,sha256=MLMPmzORhnLXf_ArAJpHF2PkHujdTuAidVYzSRk36b8,25359
|
|
7
|
+
dispatchbox/net.py,sha256=tObAtoo9m6R-d4IZ_FRtZOJwjRJPvwGjhD8XcmMxnBA,1243
|
|
8
|
+
dispatchbox/rules.py,sha256=6CSrVm-Qd8O_rznc8D6u06cyn6O1gkVHxUycjoJyMG0,8222
|
|
9
|
+
dispatchbox/server.py,sha256=r1nJwUmsSY288knoWDFel2QaZYiy8CE1GuMpE6N658c,24259
|
|
10
|
+
dispatchbox/slack.py,sha256=ayX-30cHOkVHwhMuMxY7BIhWF8UWSbOIx1ipzeEZwVw,11224
|
|
11
|
+
dispatchbox/store.py,sha256=xwcHlQR_UN4kuc4lR_sKJtySB9x672xn_Qo28yoxT6I,2863
|
|
12
|
+
dispatchbox/worker.py,sha256=dQo4kjr4EAPuqDY93YTMgkoh8XCl-ro9MCG87V71evo,12997
|
|
13
|
+
dispatchbox-0.1.0.dist-info/licenses/LICENSE,sha256=hgOz9zf_i-51YHIry---qUiQnxcLHGdaQjs2yzDhlYI,1081
|
|
14
|
+
dispatchbox-0.1.0.dist-info/METADATA,sha256=r_veGYOoLM5ZpyR_9anmC4eeqhXJjMfpJ9cbOr5EuDw,23560
|
|
15
|
+
dispatchbox-0.1.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
16
|
+
dispatchbox-0.1.0.dist-info/entry_points.txt,sha256=ENq21j0Z6TTEkhzSepmZQ64pQ27mWkdnsUM3PGNdE2s,58
|
|
17
|
+
dispatchbox-0.1.0.dist-info/top_level.txt,sha256=JtmT_e8H4odFDRbvuSiKiq9YlmEjud97bNrb1PCNPSw,12
|
|
18
|
+
dispatchbox-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dispatchbox contributors
|
|
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 @@
|
|
|
1
|
+
dispatchbox
|