Skip to content

Commit 0baa40f

Browse files
committed
chore: update docs
1 parent c676400 commit 0baa40f

2 files changed

Lines changed: 24 additions & 12 deletions

File tree

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ Or add to `~/.config/opencode/opencode.json` (OpenCode):
5656
- At least one coding agent CLI on PATH:
5757
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (`claude`)
5858
- [OpenCode](https://opencode.ai) (`opencode`)
59-
- For OpenCode teammates: `OPENCODE_SERVER_URL` must be set (for example, `http://localhost:4096`)
59+
- For OpenCode teammates:
60+
- `OPENCODE_SERVER_URL` must be set (for example, `http://localhost:4096`)
61+
- the `claude-teams` MCP server must be connected in that OpenCode instance
6062

6163
## Tools
6264

@@ -65,7 +67,7 @@ Or add to `~/.config/opencode/opencode.json` (OpenCode):
6567
| `team_create` | Create a new agent team. One team per server session. |
6668
| `team_delete` | Delete a team and all its data. Fails if teammates are still active. |
6769
| `spawn_teammate` | Spawn a teammate in tmux (pane by default, window when `USE_TMUX_WINDOWS` is set). |
68-
| `send_message` | Send direct messages, broadcasts, shutdown/plan approval responses. |
70+
| `send_message` | Send direct messages (teammates to team-lead), broadcasts (team-lead only), and shutdown/plan responses. |
6971
| `read_inbox` | Read messages from an agent's inbox. |
7072
| `poll_inbox` | Long-poll an inbox for new messages (up to 30s). |
7173
| `read_config` | Read team configuration and member list. |
@@ -79,9 +81,9 @@ Or add to `~/.config/opencode/opencode.json` (OpenCode):
7981
## How it works
8082

8183
- **Spawning**: Teammates launch in tmux via `tmux split-window` (default) or `tmux new-window` when `USE_TMUX_WINDOWS` is set. Backend can be Claude (`claude`) or OpenCode (`opencode`). Each gets a unique agent ID (`name@team`) and color.
82-
- **Messaging**: JSON-based inboxes under `~/.claude/teams/<team>/inboxes/`. File locking (`fcntl`) prevents corruption from concurrent reads/writes.
84+
- **Messaging**: JSON inboxes live under `~/.claude/teams/<team>/inboxes/`. Team lead can message anyone; teammates can message only team lead.
8385
- **Tasks**: JSON task files under `~/.claude/tasks/<team>/`. Tasks have status tracking, ownership, and dependency management (`blocks`/`blockedBy`).
84-
- **Concurrency safety**: Atomic writes via `tempfile` + `os.replace` for config. `fcntl` file locks for inbox operations.
86+
- **Concurrency safety**: Atomic config writes via `tempfile` + `os.replace` (with Windows retry). Cross-platform file locks via `filelock`.
8587

8688
## Storage layout
8789

src/claude_teams/opencode_client.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ def __init__(
1818
self.response_body = response_body
1919

2020

21-
def _request(method: str, url: str, body: dict | None = None, timeout: int = 15) -> bytes:
21+
def _request(
22+
method: str, url: str, body: dict | None = None, timeout: int = 15
23+
) -> bytes:
2224
headers = {"Content-Type": "application/json"}
2325
data = json.dumps(body).encode() if body is not None else None
2426
req = urllib.request.Request(url, data=data, headers=headers, method=method)
@@ -36,25 +38,31 @@ def _request(method: str, url: str, body: dict | None = None, timeout: int = 15)
3638
if status == 400:
3739
raise OpenCodeAPIError(
3840
f"Opencode rejected request to {endpoint}: {body_text or status}",
39-
status_code=status, response_body=body_text,
41+
status_code=status,
42+
response_body=body_text,
4043
)
4144
if status == 404:
4245
raise OpenCodeAPIError(
4346
f"Opencode resource not found at {endpoint}",
44-
status_code=status, response_body=body_text,
47+
status_code=status,
48+
response_body=body_text,
4549
)
4650
if status >= 500:
4751
raise OpenCodeAPIError(
4852
f"Opencode server error ({status}) on {endpoint}: {body_text}",
49-
status_code=status, response_body=body_text,
53+
status_code=status,
54+
response_body=body_text,
5055
)
5156
raise OpenCodeAPIError(
5257
f"Unexpected response from opencode ({status}) on {endpoint}: {body_text}",
53-
status_code=status, response_body=body_text,
58+
status_code=status,
59+
response_body=body_text,
5460
)
5561
except urllib.error.URLError as e:
5662
if isinstance(e.reason, socket.timeout):
57-
raise OpenCodeAPIError(f"Opencode server at {url} timed out after {timeout}s")
63+
raise OpenCodeAPIError(
64+
f"Opencode server at {url} timed out after {timeout}s"
65+
)
5866
raise OpenCodeAPIError(f"Cannot reach opencode server at {url}: {e.reason}")
5967
except socket.timeout:
6068
raise OpenCodeAPIError(f"Opencode server at {url} timed out after {timeout}s")
@@ -64,7 +72,7 @@ def _request(method: str, url: str, body: dict | None = None, timeout: int = 15)
6472
Cannot spawn opencode teammate: the 'claude-teams' MCP server is not configured \
6573
(or not connected) in the opencode instance at {server_url}.
6674
67-
Add the following to your opencode MCP config (~/.config/opencode/config.json):
75+
Add the following to your opencode MCP config (~/.config/opencode/opencode.json):
6876
6977
{{
7078
"mcp": {{
@@ -141,7 +149,9 @@ def list_agents(server_url: str) -> list[dict]:
141149
return [
142150
{"name": a["name"], "description": a.get("description", "")}
143151
for a in data
144-
if isinstance(a, dict) and "name" in a and a.get("description")
152+
if isinstance(a, dict)
153+
and "name" in a
154+
and a.get("description")
145155
and a["name"] not in _OPENCODE_INTERNAL_AGENTS
146156
]
147157

0 commit comments

Comments
 (0)