beadhub 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.
- beadhub/__init__.py +12 -0
- beadhub/api.py +260 -0
- beadhub/auth.py +101 -0
- beadhub/aweb_context.py +65 -0
- beadhub/aweb_introspection.py +70 -0
- beadhub/beads_sync.py +514 -0
- beadhub/cli.py +330 -0
- beadhub/config.py +65 -0
- beadhub/db.py +129 -0
- beadhub/defaults/invariants/01-tracking-bdh-only.md +11 -0
- beadhub/defaults/invariants/02-communication-mail-first.md +36 -0
- beadhub/defaults/invariants/03-communication-chat.md +60 -0
- beadhub/defaults/invariants/04-identity-no-impersonation.md +17 -0
- beadhub/defaults/invariants/05-collaborate.md +12 -0
- beadhub/defaults/roles/backend.md +55 -0
- beadhub/defaults/roles/coordinator.md +44 -0
- beadhub/defaults/roles/frontend.md +77 -0
- beadhub/defaults/roles/implementer.md +73 -0
- beadhub/defaults/roles/reviewer.md +56 -0
- beadhub/defaults/roles/startup-expert.md +93 -0
- beadhub/defaults.py +262 -0
- beadhub/events.py +704 -0
- beadhub/internal_auth.py +121 -0
- beadhub/jsonl.py +68 -0
- beadhub/logging.py +62 -0
- beadhub/migrations/beads/001_initial.sql +70 -0
- beadhub/migrations/beads/002_search_indexes.sql +20 -0
- beadhub/migrations/server/001_initial.sql +279 -0
- beadhub/names.py +33 -0
- beadhub/notifications.py +275 -0
- beadhub/pagination.py +125 -0
- beadhub/presence.py +495 -0
- beadhub/rate_limit.py +152 -0
- beadhub/redis_client.py +11 -0
- beadhub/roles.py +35 -0
- beadhub/routes/__init__.py +1 -0
- beadhub/routes/agents.py +303 -0
- beadhub/routes/bdh.py +655 -0
- beadhub/routes/beads.py +778 -0
- beadhub/routes/claims.py +141 -0
- beadhub/routes/escalations.py +471 -0
- beadhub/routes/init.py +348 -0
- beadhub/routes/mcp.py +338 -0
- beadhub/routes/policies.py +833 -0
- beadhub/routes/repos.py +538 -0
- beadhub/routes/status.py +568 -0
- beadhub/routes/subscriptions.py +362 -0
- beadhub/routes/workspaces.py +1642 -0
- beadhub/workspace_config.py +202 -0
- beadhub-0.1.0.dist-info/METADATA +254 -0
- beadhub-0.1.0.dist-info/RECORD +54 -0
- beadhub-0.1.0.dist-info/WHEEL +4 -0
- beadhub-0.1.0.dist-info/entry_points.txt +2 -0
- beadhub-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""Workspace configuration reading from .beadhub files."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
MAX_CONFIG_SIZE = 4096 # 4KB max for .beadhub file
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class WorkspaceConfig:
|
|
11
|
+
"""Configuration loaded from a .beadhub file."""
|
|
12
|
+
|
|
13
|
+
workspace_id: str | None = None
|
|
14
|
+
beadhub_url: str | None = None
|
|
15
|
+
alias: str | None = None
|
|
16
|
+
human_name: str | None = None
|
|
17
|
+
project_slug: str | None = None
|
|
18
|
+
repo_origin: str | None = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _strip_quotes(value: str) -> str:
|
|
22
|
+
"""Strip matching quotes from a value string.
|
|
23
|
+
|
|
24
|
+
Only removes quotes if they match (both single or both double).
|
|
25
|
+
"""
|
|
26
|
+
value = value.strip()
|
|
27
|
+
if len(value) >= 2:
|
|
28
|
+
if (value.startswith('"') and value.endswith('"')) or (
|
|
29
|
+
value.startswith("'") and value.endswith("'")
|
|
30
|
+
):
|
|
31
|
+
return value[1:-1]
|
|
32
|
+
return value
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _parse_beadhub_file(content: str) -> dict[str, str]:
|
|
36
|
+
"""Parse simple YAML-like .beadhub config file.
|
|
37
|
+
|
|
38
|
+
Format:
|
|
39
|
+
# comments are ignored
|
|
40
|
+
key: "value" # quoted values
|
|
41
|
+
key: value # unquoted values
|
|
42
|
+
|
|
43
|
+
Note: This is NOT a full YAML parser. It only supports simple key: value lines.
|
|
44
|
+
"""
|
|
45
|
+
config: dict[str, str] = {}
|
|
46
|
+
for line in content.splitlines():
|
|
47
|
+
line = line.strip()
|
|
48
|
+
if not line or line.startswith("#"):
|
|
49
|
+
continue
|
|
50
|
+
if ":" in line:
|
|
51
|
+
key, value = line.split(":", 1)
|
|
52
|
+
key = key.strip()
|
|
53
|
+
if not key:
|
|
54
|
+
continue
|
|
55
|
+
value = _strip_quotes(value)
|
|
56
|
+
if value:
|
|
57
|
+
config[key] = value
|
|
58
|
+
return config
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def load_workspace_config(path: Path | None = None) -> WorkspaceConfig | None:
|
|
62
|
+
"""Load workspace configuration from .beadhub file.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
path: Directory containing .beadhub file. Defaults to current directory.
|
|
66
|
+
Security note: Caller must ensure this path is trusted.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
WorkspaceConfig if file exists, None if file doesn't exist.
|
|
70
|
+
|
|
71
|
+
Raises:
|
|
72
|
+
ValueError: If file is too large or unreadable.
|
|
73
|
+
"""
|
|
74
|
+
if path is None:
|
|
75
|
+
path = Path.cwd()
|
|
76
|
+
|
|
77
|
+
config_file = path / ".beadhub"
|
|
78
|
+
if not config_file.exists():
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
file_size = config_file.stat().st_size
|
|
83
|
+
if file_size > MAX_CONFIG_SIZE:
|
|
84
|
+
raise ValueError(f".beadhub file too large ({file_size} bytes, max {MAX_CONFIG_SIZE})")
|
|
85
|
+
content = config_file.read_text(encoding="utf-8")
|
|
86
|
+
except PermissionError:
|
|
87
|
+
raise ValueError(f"Cannot read {config_file}: Permission denied")
|
|
88
|
+
except UnicodeDecodeError:
|
|
89
|
+
raise ValueError(f"{config_file} is not valid UTF-8 text")
|
|
90
|
+
except OSError as e:
|
|
91
|
+
raise ValueError(f"Error reading {config_file}: {e}")
|
|
92
|
+
|
|
93
|
+
parsed = _parse_beadhub_file(content)
|
|
94
|
+
|
|
95
|
+
return WorkspaceConfig(
|
|
96
|
+
workspace_id=parsed.get("workspace_id"),
|
|
97
|
+
beadhub_url=parsed.get("beadhub_url"),
|
|
98
|
+
alias=parsed.get("alias"),
|
|
99
|
+
human_name=parsed.get("human_name"),
|
|
100
|
+
project_slug=parsed.get("project_slug"),
|
|
101
|
+
repo_origin=parsed.get("repo_origin"),
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def get_workspace_id(override: str | None = None, path: Path | None = None) -> str | None:
|
|
106
|
+
"""Get workspace_id, preferring explicit override over file.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
override: Explicit workspace_id (takes precedence).
|
|
110
|
+
path: Directory containing .beadhub file.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
workspace_id or None if not available.
|
|
114
|
+
"""
|
|
115
|
+
if override:
|
|
116
|
+
return override
|
|
117
|
+
|
|
118
|
+
config = load_workspace_config(path)
|
|
119
|
+
if config:
|
|
120
|
+
return config.workspace_id
|
|
121
|
+
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def get_project_slug(override: str | None = None, path: Path | None = None) -> str | None:
|
|
126
|
+
"""Get project_slug, preferring explicit override over file.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
override: Explicit project_slug (takes precedence).
|
|
130
|
+
path: Directory containing .beadhub file.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
project_slug or None if not available.
|
|
134
|
+
"""
|
|
135
|
+
if override:
|
|
136
|
+
return override
|
|
137
|
+
|
|
138
|
+
config = load_workspace_config(path)
|
|
139
|
+
if config:
|
|
140
|
+
return config.project_slug
|
|
141
|
+
|
|
142
|
+
return None
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def get_human_name(override: str | None = None, path: Path | None = None) -> str | None:
|
|
146
|
+
"""Get human_name, preferring explicit override over file.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
override: Explicit human_name (takes precedence).
|
|
150
|
+
path: Directory containing .beadhub file.
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
human_name or None if not available.
|
|
154
|
+
"""
|
|
155
|
+
if override:
|
|
156
|
+
return override
|
|
157
|
+
|
|
158
|
+
config = load_workspace_config(path)
|
|
159
|
+
if config:
|
|
160
|
+
return config.human_name
|
|
161
|
+
|
|
162
|
+
return None
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def get_alias(override: str | None = None, path: Path | None = None) -> str | None:
|
|
166
|
+
"""Get alias, preferring explicit override over file.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
override: Explicit alias (takes precedence).
|
|
170
|
+
path: Directory containing .beadhub file.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
alias or None if not available.
|
|
174
|
+
"""
|
|
175
|
+
if override:
|
|
176
|
+
return override
|
|
177
|
+
|
|
178
|
+
config = load_workspace_config(path)
|
|
179
|
+
if config:
|
|
180
|
+
return config.alias
|
|
181
|
+
|
|
182
|
+
return None
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def get_repo_origin(override: str | None = None, path: Path | None = None) -> str | None:
|
|
186
|
+
"""Get repo_origin, preferring explicit override over file.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
override: Explicit repo_origin (takes precedence).
|
|
190
|
+
path: Directory containing .beadhub file.
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
repo_origin or None if not available.
|
|
194
|
+
"""
|
|
195
|
+
if override:
|
|
196
|
+
return override
|
|
197
|
+
|
|
198
|
+
config = load_workspace_config(path)
|
|
199
|
+
if config:
|
|
200
|
+
return config.repo_origin
|
|
201
|
+
|
|
202
|
+
return None
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: beadhub
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Real-time coordination layer for AI agent teams. File locking, messaging, escalations, and Beads integration.
|
|
5
|
+
Project-URL: Homepage, https://github.com/beadhub/beadhub
|
|
6
|
+
Project-URL: Documentation, https://github.com/beadhub/beadhub#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/beadhub/beadhub.git
|
|
8
|
+
Project-URL: Issues, https://github.com/beadhub/beadhub/issues
|
|
9
|
+
Author-email: Juan Reyero <juan@juanreyero.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: agents,ai,beads,coordination,file-locking,mcp
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Framework :: FastAPI
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
|
+
Requires-Dist: aiofiles>=25.1.0
|
|
23
|
+
Requires-Dist: aweb>=0.1.0
|
|
24
|
+
Requires-Dist: bcrypt>=5.0.0
|
|
25
|
+
Requires-Dist: email-validator>=2.3.0
|
|
26
|
+
Requires-Dist: fastapi>=0.93.0
|
|
27
|
+
Requires-Dist: httpx>=0.23.0
|
|
28
|
+
Requires-Dist: pgdbm>=0.4.0
|
|
29
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
30
|
+
Requires-Dist: redis>=4.2.0
|
|
31
|
+
Requires-Dist: typer>=0.6.0
|
|
32
|
+
Requires-Dist: uvicorn>=0.20.0
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# BeadHub
|
|
36
|
+
|
|
37
|
+
Real-time coordination for AI agent teams.
|
|
38
|
+
|
|
39
|
+
## The Problem
|
|
40
|
+
|
|
41
|
+
When multiple AI agents work on a shared codebase, they collide. Two agents claim the same issue. Both edit the same file. Merge conflicts pile up. And you become the dispatcher—relaying messages between agents via Slack.
|
|
42
|
+
|
|
43
|
+
BeadHub lets agents coordinate themselves. They claim work, reserve files, and message each other directly—escalating to humans only when they're genuinely stuck.
|
|
44
|
+
|
|
45
|
+
**BeadHub is to [Beads](https://github.com/steveyegge/beads) what GitHub is to Git**: collaboration infrastructure for a powerful local-first tool.
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
Prerequisites:
|
|
50
|
+
- Docker
|
|
51
|
+
- [Beads](https://github.com/steveyegge/beads) (`bd` CLI) for issue tracking
|
|
52
|
+
- A git repository with a remote origin configured
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Start the BeadHub server
|
|
56
|
+
git clone https://github.com/beadhub/beadhub.git
|
|
57
|
+
cd beadhub
|
|
58
|
+
make start # or: POSTGRES_PASSWORD=demo docker compose up -d
|
|
59
|
+
|
|
60
|
+
# Install the bdh CLI
|
|
61
|
+
curl -fsSL https://raw.githubusercontent.com/beadhub/bdh/main/install.sh | bash
|
|
62
|
+
|
|
63
|
+
# Initialize a workspace (must be a git repo with remote origin)
|
|
64
|
+
cd /path/to/your-repo
|
|
65
|
+
bdh :init --project demo
|
|
66
|
+
|
|
67
|
+
# Open the dashboard (auto-authenticates using your project API key)
|
|
68
|
+
bdh :dashboard
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Dashboard:
|
|
72
|
+
- Open and auto-authenticate: `bdh :dashboard`
|
|
73
|
+
- If you need to paste a key manually, use the `api_key` from `~/.config/aw/config.yaml` (the account selected by `.aw/context`)
|
|
74
|
+
|
|
75
|
+
## See It In Action
|
|
76
|
+
|
|
77
|
+
Here's what multi-agent coordination looks like. You have three agents: a coordinator and two implementers.
|
|
78
|
+
|
|
79
|
+
> **Note**: The examples below use `bdh update` and `bdh close` which require [Beads](https://github.com/steveyegge/beads) for issue tracking. Install beads first, then run `bd init` in your repo.
|
|
80
|
+
|
|
81
|
+
### 1. Agents come online
|
|
82
|
+
|
|
83
|
+
**coord-main** runs `bdh :aweb who` to see who's online:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
Project: <project_id>
|
|
87
|
+
|
|
88
|
+
ONLINE
|
|
89
|
+
bob-backend (agent) — active
|
|
90
|
+
alice-frontend (agent) — active
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 2. Coordinator assigns work via chat
|
|
94
|
+
|
|
95
|
+
**coord-main** runs `bdh :aweb chat send bob "Can you handle the API endpoints?" --wait 300`:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
Sent chat to bob (session_id=...)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Bob is idle. **You** tell bob to check chat.
|
|
102
|
+
|
|
103
|
+
**bob-backend** runs `bdh :aweb chat pending`:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
CHATS: 1 unread conversation(s)
|
|
107
|
+
|
|
108
|
+
- coord-main (unread: 1)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**bob-backend** runs `bdh :aweb chat send coord-main "Got it, I'll take the API work"`:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
coord-main: Can you handle the API endpoints?
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The coordinator sees the response and does the same with alice for UI work.
|
|
118
|
+
|
|
119
|
+
### 3. Agents claim and complete work
|
|
120
|
+
|
|
121
|
+
**bob-backend** runs `bdh update bd-12 --status in_progress` to claim his issue.
|
|
122
|
+
|
|
123
|
+
If bob tries to claim something alice already has:
|
|
124
|
+
|
|
125
|
+
**bob-backend** runs `bdh update bd-15 --status in_progress`:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
REJECTED: bd-15 is being worked on by alice-frontend (juan)
|
|
129
|
+
|
|
130
|
+
Options:
|
|
131
|
+
- Pick different work: bdh ready
|
|
132
|
+
- Message them: bdh :aweb mail send alice-frontend "message"
|
|
133
|
+
- Escalate: bdh :escalate "subject" "situation"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
No collision. No confusion. Agents resolve conflicts directly.
|
|
137
|
+
|
|
138
|
+
## Adding More Agents
|
|
139
|
+
|
|
140
|
+
Each agent needs its own worktree with its own identity:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
bdh :add-worktree backend
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Or do it manually:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
git worktree add ../myproject-bob-backend -b bob-backend
|
|
150
|
+
cd ../myproject-bob-backend
|
|
151
|
+
bdh :init --project demo --alias bob-backend --human "$USER"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Commands
|
|
155
|
+
|
|
156
|
+
### Status and visibility
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
bdh :aweb whoami # Your aweb identity (project/agent)
|
|
160
|
+
bdh :aweb who # Who's online?
|
|
161
|
+
bdh ready # Find available work
|
|
162
|
+
bdh :aweb locks # See active locks
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Issue workflow
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
bdh ready # Find available work
|
|
169
|
+
bdh update bd-42 --status in_progress # Claim an issue
|
|
170
|
+
bdh close bd-42 # Complete work
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Chat (synchronous)
|
|
174
|
+
|
|
175
|
+
Use chat when you need an answer to proceed. The sender waits.
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
bdh :aweb chat send alice "Quick question..." --wait 300 # Send, wait up to 5 min
|
|
179
|
+
bdh :aweb chat pending # Check pending chats
|
|
180
|
+
bdh :aweb chat send alice "Here's the answer" # Reply
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Mail (async)
|
|
184
|
+
|
|
185
|
+
Use mail for status updates, handoffs, FYIs—anything that doesn't need an immediate response.
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
bdh :aweb mail send alice "Login bug fixed. Changed session handling."
|
|
189
|
+
bdh :aweb mail list # Check messages
|
|
190
|
+
bdh :aweb mail open alice # Read + acknowledge from specific sender
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Escalation
|
|
194
|
+
|
|
195
|
+
When agents can't resolve something themselves:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
bdh :escalate "Need human decision" "Alice and I both need to modify auth.py..."
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## File Reservations
|
|
202
|
+
|
|
203
|
+
bdh automatically reserves files you modify—no commands needed. Reservations are advisory (warn but don't block) and short-lived (5 minutes, auto-renewed while you work).
|
|
204
|
+
|
|
205
|
+
When an agent runs `bdh :aweb locks`:
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
## Other Agents' Reservations
|
|
209
|
+
Do not edit these files:
|
|
210
|
+
- `src/auth.py` — bob-backend (expires in 4m30s) "auto-reserve"
|
|
211
|
+
- `src/api.py` — alice-frontend (expires in 3m15s) "auto-reserve"
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Architecture
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
218
|
+
│ BeadHub Server │
|
|
219
|
+
│ Claims · Reservations · Presence · Messages · Beads Sync │
|
|
220
|
+
├─────────────────────────────────────────────────────────────┤
|
|
221
|
+
│ PostgreSQL Redis │
|
|
222
|
+
│ (claims, issues) (presence, messages) │
|
|
223
|
+
└─────────────────────────────────────────────────────────────┘
|
|
224
|
+
▲ ▲ ▲
|
|
225
|
+
│ │ │
|
|
226
|
+
┌────┴────┐ ┌────┴────┐ ┌────┴────┐
|
|
227
|
+
│ Agent │ │ Agent │ │ Human │
|
|
228
|
+
│ Repo A │ │ Repo B │ │ (dash) │
|
|
229
|
+
└─────────┘ └─────────┘ └─────────┘
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Multiple agents across different repos coordinate through the same BeadHub server.
|
|
233
|
+
|
|
234
|
+
## Requirements
|
|
235
|
+
|
|
236
|
+
- Docker and Docker Compose
|
|
237
|
+
- [Beads](https://github.com/steveyegge/beads) for issue tracking
|
|
238
|
+
|
|
239
|
+
## Documentation
|
|
240
|
+
|
|
241
|
+
- [bdh Command Reference](docs/bdh.md)
|
|
242
|
+
- [Deployment Guide](docs/deployment.md)
|
|
243
|
+
- [Development Guide](docs/development.md)
|
|
244
|
+
- [Changelog](CHANGELOG.md)
|
|
245
|
+
|
|
246
|
+
## Cleanup
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
docker compose down -v
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## License
|
|
253
|
+
|
|
254
|
+
MIT — see [LICENSE](LICENSE)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
beadhub/__init__.py,sha256=xV4F4KIcDjzjBAubgbfnqXQGykDSVbCZ3h8gBsKLJPI,257
|
|
2
|
+
beadhub/api.py,sha256=SdNS8wyoTSpB2Reo7mdiwZEIMyfWllAwzBM3U_V3-yQ,9696
|
|
3
|
+
beadhub/auth.py,sha256=re60LYsPzrB7WU8WB9vYoo7QNMSPbQlUI1gfxuYGL9U,3202
|
|
4
|
+
beadhub/aweb_context.py,sha256=XbeJd_F1YGgJyCnqoHgBuALwSZnjeT-8CTfHjPOIFR0,1905
|
|
5
|
+
beadhub/aweb_introspection.py,sha256=VuJxtGoru6llD9fEziNXnHuv_Mk8EdSrVc37K16aSBc,2562
|
|
6
|
+
beadhub/beads_sync.py,sha256=bRpsJuBTozfj-Yqjjc0Au4mQtHcjTl-BiZPb7oXaDQQ,18086
|
|
7
|
+
beadhub/cli.py,sha256=GsL4DK5nNSouwv4zvAqThz8o9wK3FBGGbCe9CSuKBrU,10670
|
|
8
|
+
beadhub/config.py,sha256=ceuQrP_kZDmTH_bBjcYHH2y5xDqbXl_P8rjgRnB1Gzg,2077
|
|
9
|
+
beadhub/db.py,sha256=an_Sgg3E8BA7ZvC5ruSXlYn1tQnDwqyffoqbQiQJIVk,4628
|
|
10
|
+
beadhub/defaults.py,sha256=aeppczKQCsnFYH9hBR4gEOMQiUZEWyzajAsD-hhH4ec,7978
|
|
11
|
+
beadhub/events.py,sha256=jTxkS4wOXzmiNhO-THlMN3icpI1xm60HF2mq_TQGLqY,23609
|
|
12
|
+
beadhub/internal_auth.py,sha256=0gMnQZTGSKum6RG_aegPAYA9Y0Su-POD3w5hsBXPv6Q,4089
|
|
13
|
+
beadhub/jsonl.py,sha256=rihr6dZtpetCmjI-NAcwC3Nwo59ze7hiW08iBjv7GtA,2164
|
|
14
|
+
beadhub/logging.py,sha256=coreUgbK0imFhuh0wqXG_08ndrP9vt8oSoXr0be3-ZA,1928
|
|
15
|
+
beadhub/names.py,sha256=xKgQgWbS7rvK3Eac_S9Q1y7tq4qI_CNGZbUBsRsifOk,512
|
|
16
|
+
beadhub/notifications.py,sha256=wqRkXBxqIGq6eKACRlj6f14fPsTrJd-65ucxZoynZHw,8487
|
|
17
|
+
beadhub/pagination.py,sha256=lcKBw_CBwBg5_wdBENtXuuL8U6Ncaxib9ajOwc_-Rcc,3893
|
|
18
|
+
beadhub/presence.py,sha256=OgKgooH9ZRdmK8INsVyUiz4IRrGEQ-MLrxJdQBvdn_0,15393
|
|
19
|
+
beadhub/rate_limit.py,sha256=KkicwCZv8aOwoENgFc2m1PMvLDa5CE4SBYXlmWBOsH4,4720
|
|
20
|
+
beadhub/redis_client.py,sha256=f9IRPQH0DOiM5hC7D_LxFiCr7yCyqjZNayA8a-Q9l4U,273
|
|
21
|
+
beadhub/roles.py,sha256=442UQxgQ9lYM_ccyvwn803s-Kt-0ZEcrDMk8-nsOHps,1086
|
|
22
|
+
beadhub/workspace_config.py,sha256=d_xECpDvYZ29qpQb9E1naBhQyHuKcAzjZnguRJVC8bQ,5548
|
|
23
|
+
beadhub/defaults/invariants/01-tracking-bdh-only.md,sha256=_ipwZg5sENZTBfPA-JUuxRniWA8nW5c9aoB09KeIiWA,375
|
|
24
|
+
beadhub/defaults/invariants/02-communication-mail-first.md,sha256=OIpgBFKAndqdL6Z37UAO_Jxfke9YcpDD9GPtswi3qsY,925
|
|
25
|
+
beadhub/defaults/invariants/03-communication-chat.md,sha256=D5_mLxTP-1B1BRWoZd-TQUkpmLbwotQ8tg4J2IoFiws,1844
|
|
26
|
+
beadhub/defaults/invariants/04-identity-no-impersonation.md,sha256=mlwztSun5hNxqD3ADcrXUBYHtcs86fFMnZAlZ_THuPo,534
|
|
27
|
+
beadhub/defaults/invariants/05-collaborate.md,sha256=KvOwHgB5cyn55IsySvZx5tDosaL_QTVUbwNcE3IQT4M,445
|
|
28
|
+
beadhub/defaults/roles/backend.md,sha256=M3FBwOb9MIb6NUVNooS3aFbz20KNBMsAEM45TMCFmmo,1404
|
|
29
|
+
beadhub/defaults/roles/coordinator.md,sha256=bjlMxNUNdmk0lVX0l9jwu-YbqkUzd26maiV19WHURG0,1200
|
|
30
|
+
beadhub/defaults/roles/frontend.md,sha256=gXBqQg2h0oOQqzmCqYDGIdoZZBNaCduLNbfVMjSOTMY,2014
|
|
31
|
+
beadhub/defaults/roles/implementer.md,sha256=s-mte97p5yEuKQctCgjOVb7ncRT1NMARlPujyYteZgk,1886
|
|
32
|
+
beadhub/defaults/roles/reviewer.md,sha256=8cs3vvI6AT0dcN2Qybq7Rr7zBIBtmq4AeRzlNvKSfa4,1442
|
|
33
|
+
beadhub/defaults/roles/startup-expert.md,sha256=JKygzye541J_fd2u989gBYocKNHEsvAyDZJfWRZ4EQA,4793
|
|
34
|
+
beadhub/migrations/beads/001_initial.sql,sha256=I47sncZ9R7fyF42tuBAmouCtyePw3UTWy-Had0G5yVw,2275
|
|
35
|
+
beadhub/migrations/beads/002_search_indexes.sql,sha256=R2ZIc-SO87nv8UyN7Q4nIZfsUUu7QYn_EiZAhYGvzWk,990
|
|
36
|
+
beadhub/migrations/server/001_initial.sql,sha256=FNLSpwg0X-vlPBLEtvYEsMpKG_12OspmH7upmZhPiv0,12339
|
|
37
|
+
beadhub/routes/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
38
|
+
beadhub/routes/agents.py,sha256=d_tu6GS-WjRnnAtok1QxGv2EtPeQysjY9aWPBbDZwDU,9667
|
|
39
|
+
beadhub/routes/bdh.py,sha256=UZ41aeSA1fnOukNZhXFHYbsHRd2piHCn4Toa4-TOGMU,21274
|
|
40
|
+
beadhub/routes/beads.py,sha256=NE1Dnyev9AXIXd6i42nUai4QVUIT3nx-d4JQaKRhGHY,27049
|
|
41
|
+
beadhub/routes/claims.py,sha256=Ab0PWkN2zziEHvS4b9IYFSuepAFeULhRSSg-iHzRHYE,4676
|
|
42
|
+
beadhub/routes/escalations.py,sha256=kTRV1-PqxnzAz0wFpuwcypXaJMixx10pL5EDY9_O5Cc,15766
|
|
43
|
+
beadhub/routes/init.py,sha256=YFSCB-mGQQSoDeUB5mDB4P9hiV2N1tJ_CLcQslsG-pA,12092
|
|
44
|
+
beadhub/routes/mcp.py,sha256=V46oiGUtG7iZ-Q4waRVBon7qezrYOm_jb0mM3u-ZhBs,12140
|
|
45
|
+
beadhub/routes/policies.py,sha256=8RKRb53uGdGAqAmWy5WwTm67jlgkwGHjbVusUwpXY6k,24885
|
|
46
|
+
beadhub/routes/repos.py,sha256=Yfa6ZRZDWAMnUitolFlCDln5Tl3q4Oh4uSPtgvMOfhk,16136
|
|
47
|
+
beadhub/routes/status.py,sha256=QvA8GsDYw9ZJxNMdq-Q6AvSmmnAk6_8vktvFiOgZQq8,19908
|
|
48
|
+
beadhub/routes/subscriptions.py,sha256=6EgpKseRnmMgY0STVRY02Ss5_hLUrmCcH1j9BZW__aI,11733
|
|
49
|
+
beadhub/routes/workspaces.py,sha256=qRwqdfewKMrQb_e772sJklUD5MtWxtl22Lm-lmHO_8Y,58554
|
|
50
|
+
beadhub-0.1.0.dist-info/METADATA,sha256=i0RxPsUCMdK1eBgmVxRzXrDQGtNFfmWr_nZwJE7V-7Y,8224
|
|
51
|
+
beadhub-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
52
|
+
beadhub-0.1.0.dist-info/entry_points.txt,sha256=R0WP_G-w5OLtcXmJBYWegf7nz19r8fWsLmvXcKhCVzg,41
|
|
53
|
+
beadhub-0.1.0.dist-info/licenses/LICENSE,sha256=xkOblX-z-aMOHH5l6MnEAVc0dFrpwFN2dPJGFvKsXtg,1068
|
|
54
|
+
beadhub-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Juan Reyero
|
|
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.
|