Rewrite README with architecture docs and mermaid diagrams
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
235
README.md
235
README.md
@@ -1,23 +1,220 @@
|
||||
# DevClaw
|
||||
|
||||
Multi-project dev/qa pipeline orchestration plugin for [OpenClaw](https://openclaw.ai).
|
||||
An [OpenClaw](https://openclaw.ai) plugin that turns a single orchestrator agent into a development team lead managing multiple projects simultaneously.
|
||||
|
||||
Replaces manual orchestration steps with atomic agent tools. Instead of 10+ error-prone manual steps per task, the agent calls a single tool that handles GitLab labels, state management, model selection, and audit logging atomically.
|
||||
## The idea
|
||||
|
||||
You have one AI agent — the orchestrator. It lives in a Telegram group per project. Each project has its own GitLab repo, its own task backlog, and its own pair of sub-agent workers: a **DEV** that writes code and a **QA** that reviews it. The orchestrator decides what to work on, spawns the right worker with the right model, and moves tasks through the pipeline — across all projects at once.
|
||||
|
||||
DevClaw gives the orchestrator four tools that replace hundreds of lines of manual orchestration logic. Instead of the agent following a 10-step checklist (fetch issue, check labels, pick model, check for existing session, transition label, update state, log audit event...), it calls `task_pickup` and the plugin handles everything atomically.
|
||||
|
||||
## How it works
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Orchestrator Agent"
|
||||
O[Orchestrator]
|
||||
end
|
||||
|
||||
subgraph "Project A — Telegram Group"
|
||||
direction TB
|
||||
A_GL[GitLab Issues]
|
||||
A_DEV[DEV sub-agent]
|
||||
A_QA[QA sub-agent]
|
||||
end
|
||||
|
||||
subgraph "Project B — Telegram Group"
|
||||
direction TB
|
||||
B_GL[GitLab Issues]
|
||||
B_DEV[DEV sub-agent]
|
||||
B_QA[QA sub-agent]
|
||||
end
|
||||
|
||||
subgraph "Project C — Telegram Group"
|
||||
direction TB
|
||||
C_GL[GitLab Issues]
|
||||
C_DEV[DEV sub-agent]
|
||||
C_QA[QA sub-agent]
|
||||
end
|
||||
|
||||
O -->|task_pickup / task_complete| A_GL
|
||||
O -->|task_pickup / task_complete| B_GL
|
||||
O -->|task_pickup / task_complete| C_GL
|
||||
O -->|sessions_spawn / sessions_send| A_DEV
|
||||
O -->|sessions_spawn / sessions_send| A_QA
|
||||
O -->|sessions_spawn / sessions_send| B_DEV
|
||||
O -->|sessions_spawn / sessions_send| B_QA
|
||||
O -->|sessions_spawn / sessions_send| C_DEV
|
||||
O -->|sessions_spawn / sessions_send| C_QA
|
||||
```
|
||||
|
||||
Each project is identified by its **Telegram group ID** — the orchestrator receives messages from project groups and knows which project context it's operating in.
|
||||
|
||||
## Task lifecycle
|
||||
|
||||
Every task (GitLab issue) moves through a fixed pipeline of label states. DevClaw tools handle every transition atomically — label change, state update, audit log, and session management in a single call.
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Planning
|
||||
Planning --> ToDo: Ready for development
|
||||
|
||||
ToDo --> Doing: task_pickup (DEV)
|
||||
Doing --> ToTest: task_complete (DEV done)
|
||||
|
||||
ToTest --> Testing: task_pickup (QA)
|
||||
Testing --> Done: task_complete (QA pass)
|
||||
Testing --> ToImprove: task_complete (QA fail)
|
||||
Testing --> Refining: task_complete (QA refine)
|
||||
|
||||
ToImprove --> Doing: task_pickup (DEV fix)
|
||||
Refining --> ToDo: Human decision
|
||||
|
||||
Done --> [*]
|
||||
```
|
||||
|
||||
## Session reuse
|
||||
|
||||
Sub-agent sessions are expensive to start — each new spawn requires the agent to read the full codebase (~50K tokens). DevClaw preserves session IDs across task completions. When a DEV finishes task A and picks up task B on the same project, the plugin detects the existing session and returns `"sessionAction": "send"` instead of `"spawn"` — the orchestrator sends the new task to the running session instead of creating a new one.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant O as Orchestrator
|
||||
participant DC as DevClaw Plugin
|
||||
participant GL as GitLab
|
||||
participant S as Sub-agent Session
|
||||
|
||||
O->>DC: task_pickup({ issueId: 42, role: "dev" })
|
||||
DC->>GL: Fetch issue, verify label
|
||||
DC->>DC: Select model (haiku/sonnet/opus)
|
||||
DC->>DC: Check existing session
|
||||
DC->>GL: Transition label (To Do → Doing)
|
||||
DC->>DC: Update projects.json, write audit log
|
||||
DC-->>O: { sessionAction: "send", sessionId: "...", model: "sonnet" }
|
||||
O->>S: sessions_send (task description)
|
||||
```
|
||||
|
||||
## Model selection
|
||||
|
||||
The plugin selects the cheapest model that can handle each task:
|
||||
|
||||
| Complexity | Model | When |
|
||||
|------------|-------|------|
|
||||
| Simple | Haiku | Typos, CSS, renames, copy changes |
|
||||
| Standard | Sonnet | Features, bug fixes, multi-file changes |
|
||||
| Complex | Opus | Architecture, migrations, security, system-wide refactoring |
|
||||
| QA | Grok | All QA tasks (code review, test validation) |
|
||||
|
||||
Selection is based on issue title/description keywords. The orchestrator can override with `modelOverride` on any `task_pickup` call.
|
||||
|
||||
## State management
|
||||
|
||||
All project state lives in a single `memory/projects.json` file in the orchestrator's workspace, keyed by Telegram group ID:
|
||||
|
||||
```json
|
||||
{
|
||||
"projects": {
|
||||
"-5044836116": {
|
||||
"name": "trainerswap",
|
||||
"repo": "~/git/trainerswap",
|
||||
"groupName": "Henk - Trainerswap",
|
||||
"baseBranch": "development",
|
||||
"dev": {
|
||||
"active": false,
|
||||
"sessionId": "agent:henk-dev:subagent:a9e4d078-...",
|
||||
"issueId": null,
|
||||
"model": "haiku"
|
||||
},
|
||||
"qa": {
|
||||
"active": false,
|
||||
"sessionId": "agent:henk-dev:subagent:18707821-...",
|
||||
"issueId": null,
|
||||
"model": "grok"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Key design decision: when a worker completes a task, `sessionId` and `model` are **preserved** (only `active` and `issueId` are cleared). This enables session reuse on the next pickup.
|
||||
|
||||
All writes go through atomic temp-file-then-rename to prevent corruption.
|
||||
|
||||
## Tools
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `task_pickup` | Pick up a task from the GitLab queue. Handles label transition, model selection, state update, and session reuse detection. |
|
||||
| `task_complete` | Complete a task (DEV done, QA pass/fail/refine). Handles label transition, issue close/reopen, and fix cycle preparation. |
|
||||
| `queue_status` | Show task queue counts and worker status across all projects. |
|
||||
| `session_health` | Detect zombie sessions, stale workers, and state mismatches. Auto-fix with `autoFix: true`. |
|
||||
### `task_pickup`
|
||||
|
||||
Pick up a task from the GitLab queue for a DEV or QA worker.
|
||||
|
||||
**Parameters:**
|
||||
- `issueId` (number, required) — GitLab issue ID
|
||||
- `role` ("dev" | "qa", required) — Worker role
|
||||
- `projectGroupId` (string, required) — Telegram group ID
|
||||
- `modelOverride` (string, optional) — Force a specific model
|
||||
|
||||
**What it does atomically:**
|
||||
1. Resolves project from `projects.json`
|
||||
2. Validates no active worker for this role
|
||||
3. Fetches issue from GitLab, verifies correct label state
|
||||
4. Selects model based on task complexity
|
||||
5. Detects session reuse opportunity
|
||||
6. Transitions GitLab label (e.g. `To Do` → `Doing`)
|
||||
7. Updates `projects.json` state
|
||||
8. Writes audit log entry
|
||||
9. Returns structured instructions for the orchestrator
|
||||
|
||||
### `task_complete`
|
||||
|
||||
Complete a task with one of four results.
|
||||
|
||||
**Parameters:**
|
||||
- `role` ("dev" | "qa", required)
|
||||
- `result` ("done" | "pass" | "fail" | "refine", required)
|
||||
- `projectGroupId` (string, required)
|
||||
- `summary` (string, optional) — For the Telegram announcement
|
||||
|
||||
**Results:**
|
||||
- **DEV "done"** — Pulls latest code, moves label `Doing` → `To Test`, deactivates worker
|
||||
- **QA "pass"** — Moves label `Testing` → `Done`, closes issue, deactivates worker
|
||||
- **QA "fail"** — Moves label `Testing` → `To Improve`, reopens issue, prepares DEV fix cycle with model selection
|
||||
- **QA "refine"** — Moves label `Testing` → `Refining`, awaits human decision
|
||||
|
||||
### `queue_status`
|
||||
|
||||
Returns task queue counts and worker status across all projects (or a specific one).
|
||||
|
||||
**Parameters:**
|
||||
- `projectGroupId` (string, optional) — Omit for all projects
|
||||
|
||||
### `session_health`
|
||||
|
||||
Detects and optionally fixes state inconsistencies.
|
||||
|
||||
**Parameters:**
|
||||
- `autoFix` (boolean, optional) — Auto-fix zombies and stale state
|
||||
- `activeSessions` (string[], optional) — Live session IDs from `sessions_list`
|
||||
|
||||
**Checks:**
|
||||
- Active worker with no session ID (critical)
|
||||
- Active worker whose session is dead — zombie (critical)
|
||||
- Worker active for >2 hours (warning)
|
||||
- Inactive worker with lingering issue ID (warning)
|
||||
|
||||
## Audit logging
|
||||
|
||||
Every tool call automatically appends an NDJSON entry to `memory/audit.log`. No manual logging required from the orchestrator agent.
|
||||
|
||||
```jsonl
|
||||
{"ts":"2026-02-08T10:30:00Z","event":"task_pickup","project":"trainerswap","issue":42,"role":"dev","model":"sonnet","sessionAction":"send"}
|
||||
{"ts":"2026-02-08T10:30:01Z","event":"model_selection","issue":42,"role":"dev","selected":"sonnet","reason":"Standard dev task"}
|
||||
{"ts":"2026-02-08T10:45:00Z","event":"task_complete","project":"trainerswap","issue":42,"role":"dev","result":"done"}
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Local development (link from extensions directory)
|
||||
openclaw plugins install -l ~/.openclaw/extensions/devclaw
|
||||
# Local (place in extensions directory — auto-discovered)
|
||||
cp -r devclaw ~/.openclaw/extensions/
|
||||
|
||||
# From npm (future)
|
||||
openclaw plugins install @openclaw/devclaw
|
||||
@@ -25,7 +222,7 @@ openclaw plugins install @openclaw/devclaw
|
||||
|
||||
## Configuration
|
||||
|
||||
Optional plugin config in `openclaw.json`:
|
||||
Optional config in `openclaw.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -33,11 +230,7 @@ Optional plugin config in `openclaw.json`:
|
||||
"entries": {
|
||||
"devclaw": {
|
||||
"config": {
|
||||
"glabPath": "/usr/local/bin/glab",
|
||||
"modelSelection": {
|
||||
"enabled": true,
|
||||
"analyzerModel": "anthropic/claude-haiku-4-5"
|
||||
}
|
||||
"glabPath": "/usr/local/bin/glab"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,13 +238,13 @@ Optional plugin config in `openclaw.json`:
|
||||
}
|
||||
```
|
||||
|
||||
Restrict tools to your orchestrator agent:
|
||||
Restrict tools to your orchestrator agent only:
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"list": [{
|
||||
"id": "henk-development",
|
||||
"id": "my-orchestrator",
|
||||
"tools": {
|
||||
"allow": ["task_pickup", "task_complete", "queue_status", "session_health"]
|
||||
}
|
||||
@@ -62,10 +255,10 @@ Restrict tools to your orchestrator agent:
|
||||
|
||||
## Requirements
|
||||
|
||||
- OpenClaw >= 0.x
|
||||
- [OpenClaw](https://openclaw.ai)
|
||||
- Node.js >= 20
|
||||
- `glab` CLI installed and authenticated
|
||||
- `memory/projects.json` in the orchestrator agent's workspace
|
||||
- [`glab`](https://gitlab.com/gitlab-org/cli) CLI installed and authenticated
|
||||
- A `memory/projects.json` in the orchestrator agent's workspace
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Reference in New Issue
Block a user