Adds automatic PR/MR URL detection and inclusion in DEV completion announcements to provide better visibility into completed work. Changes: 1. TaskManager interface: - Added getMergedMRUrl() method to fetch PR/MR URL for an issue 2. GitHub/GitLab providers: - Implemented getMergedMRUrl() to find most recent merged PR/MR - Returns URL of PR/MR that references the issue number 3. task_complete tool: - Added optional prUrl parameter - Auto-detects PR/MR URL if not provided - Includes PR URL in announcement with 🔗 prefix - Format: 'PR: https://github.com/...' 4. Role templates (dev.md): - Updated to instruct workers to include prUrl in task_complete - Documents that prUrl is optional (auto-detected as fallback) Example announcement: ✅ DEV done #101 — Added PR/MR URL to notifications 🔗 PR: https://github.com/user/repo/pull/102 . Moved to QA queue. Addresses issue #101
DevClaw - Development Plugin for OpenClaw
Every group chat becomes an autonomous development team.
Add the agent to a Telegram/WhatsApp group, point it at a GitLab/GitHub repo — that group now has an orchestrator managing the backlog, a DEV worker session writing code, and a QA worker session reviewing it. All autonomous. Add another group, get another team. Each project runs in complete isolation with its own task queue, workers, and session state.
DevClaw is the OpenClaw plugin that makes this work.
Why
OpenClaw is great at giving AI agents the ability to develop software — spawn worker sessions, manage sessions, work with code. But running a real multi-project development pipeline exposes a gap: the orchestration layer between "agent can write code" and "agent reliably manages multiple projects" is brittle. Every task involves 10+ coordinated steps across GitLab labels, session state, model selection, and audit logging. Agents forget steps, corrupt state, null out session IDs they should preserve, or pick the wrong model for the job.
DevClaw fills that gap with guardrails. It gives the orchestrator atomic tools that make it impossible to forget a label transition, lose a session reference, or skip an audit log entry. The complexity of multi-project orchestration moves from agent instructions (that LLMs follow imperfectly) into deterministic code (that runs the same way every time).
The idea
One orchestrator agent manages all your projects. It reads task backlogs, creates issues, decides priorities, and delegates work. For each task, DevClaw assigns a developer from your team — a junior, medior, or senior dev writes the code, then a QA engineer reviews it. Every Telegram/WhatsApp group is a separate project — the orchestrator keeps them completely isolated while managing them all from a single process.
DevClaw gives the orchestrator nine tools that replace hundreds of lines of manual orchestration logic. Instead of following a 10-step checklist per task (fetch issue, check labels, pick model, check for existing session, transition label, dispatch task, update state, log audit event...), it calls task_pickup and the plugin handles everything atomically — including session dispatch. Workers call task_complete themselves for atomic state updates, and can file follow-up issues via task_create.
Developer tiers
DevClaw uses a developer seniority model. Each tier maps to a configurable LLM model:
| Tier | Role | Default model | Assigns to |
|---|---|---|---|
| junior | Junior developer | anthropic/claude-haiku-4-5 |
Typos, single-file fixes, simple changes |
| medior | Mid-level developer | anthropic/claude-sonnet-4-5 |
Features, bug fixes, multi-file changes |
| senior | Senior developer | anthropic/claude-opus-4-5 |
Architecture, migrations, system-wide refactoring |
| qa | QA engineer | anthropic/claude-sonnet-4-5 |
Code review, test validation |
Configure which model each tier uses during setup or in openclaw.json plugin config.
How it works
graph TB
subgraph "Group Chat A"
direction TB
A_O["🎯 Orchestrator"]
A_GL[GitLab Issues]
A_DEV["🔧 DEV (worker session)"]
A_QA["🔍 QA (worker session)"]
A_O -->|task_pickup| A_GL
A_O -->|task_pickup dispatches| A_DEV
A_O -->|task_pickup dispatches| A_QA
end
subgraph "Group Chat B"
direction TB
B_O["🎯 Orchestrator"]
B_GL[GitLab Issues]
B_DEV["🔧 DEV (worker session)"]
B_QA["🔍 QA (worker session)"]
B_O -->|task_pickup| B_GL
B_O -->|task_pickup dispatches| B_DEV
B_O -->|task_pickup dispatches| B_QA
end
subgraph "Group Chat C"
direction TB
C_O["🎯 Orchestrator"]
C_GL[GitLab Issues]
C_DEV["🔧 DEV (worker session)"]
C_QA["🔍 QA (worker session)"]
C_O -->|task_pickup| C_GL
C_O -->|task_pickup dispatches| C_DEV
C_O -->|task_pickup dispatches| C_QA
end
AGENT["Single OpenClaw Agent"]
AGENT --- A_O
AGENT --- B_O
AGENT --- C_O
It's the same agent process — but each group chat gives it a different project context. The orchestrator role, the workers, the task queue, and all state are fully isolated per group.
Task lifecycle
Every task (GitLab issue) moves through a fixed pipeline of label states. Issues are created by the orchestrator agent or by worker sessions — not manually. DevClaw tools handle every transition atomically — label change, state update, audit log, and session management in a single call.
stateDiagram-v2
[*] --> Planning
Planning --> ToDo: Ready for development
ToDo --> Doing: task_pickup (DEV) ⇄ blocked
Doing --> ToTest: task_complete (DEV done)
ToTest --> Testing: task_pickup (QA) / auto-chain ⇄ blocked
Testing --> Done: task_complete (QA pass)
Testing --> ToImprove: task_complete (QA fail)
Testing --> Refining: task_complete (QA refine)
ToImprove --> Doing: task_pickup (DEV fix) or auto-chain
Refining --> ToDo: Human decision
Done --> [*]
Worker self-reporting
Workers (DEV/QA sub-agent sessions) call task_complete directly when they finish — no orchestrator involvement needed for the state transition. Workers can also call task_create to file follow-up issues they discover during work.
Completion enforcement
Three layers guarantee that task_complete always runs, preventing tasks from getting stuck in "Doing" or "Testing" forever:
- Completion contract — Every task message includes a mandatory section requiring the worker to call
task_complete, even on failure. Workers use"blocked"if stuck. - Blocked result — Both DEV and QA can return
"blocked"to gracefully put a task back in queue (Doing → To Do,Testing → To Test) instead of silently dying. - Stale worker watchdog — The heartbeat health check detects workers active >2 hours and auto-reverts labels to queue, catching sessions that crashed or ran out of context.
Auto-chaining
When a project has autoChain: true, task_complete automatically dispatches the next step:
- DEV "done" → QA is dispatched immediately (using the qa tier)
- QA "fail" → DEV fix is dispatched immediately (reuses previous DEV tier)
- QA "pass" / "refine" / "blocked" → no chaining (pipeline done, needs human input, or returned to queue)
- DEV "blocked" → no chaining (returned to queue for retry)
When autoChain is false, task_complete returns a nextAction hint for the orchestrator to act on.
Session reuse
Worker sessions are expensive to start — each new spawn requires the session to read the full codebase (~50K tokens). DevClaw maintains separate sessions per tier per role (session-per-tier design). When a medior dev finishes task A and picks up task B on the same project, the plugin detects the existing session and sends the task directly — no new session needed.
The plugin handles session dispatch internally via OpenClaw CLI. The orchestrator agent never calls sessions_spawn or sessions_send — it just calls task_pickup and the plugin does the rest.
sequenceDiagram
participant O as Orchestrator
participant DC as DevClaw Plugin
participant GL as GitLab
participant S as Worker Session
O->>DC: task_pickup({ issueId: 42, role: "dev" })
DC->>GL: Fetch issue, verify label
DC->>DC: Assign tier (junior/medior/senior)
DC->>DC: Check existing session for assigned tier
DC->>GL: Transition label (To Do → Doing)
DC->>S: Dispatch task via CLI (create or reuse session)
DC->>DC: Update projects.json, write audit log
DC-->>O: { success: true, announcement: "🔧 DEV (medior) picking up #42" }
Developer assignment
The orchestrator LLM evaluates each issue's title, description, and labels to assign the appropriate developer tier, then passes it to task_pickup via the model parameter. This gives the LLM full context for the decision — it can weigh factors like codebase familiarity, task dependencies, and recent failure history that keyword matching would miss.
The keyword heuristic in model-selector.ts serves as a fallback only, used when the orchestrator omits the model parameter.
| Tier | Role | When |
|---|---|---|
| junior | Junior developer | Typos, CSS, renames, copy changes |
| medior | Mid-level developer | Features, bug fixes, multi-file changes |
| senior | Senior developer | Architecture, migrations, security, system-wide refactoring |
| qa | QA engineer | All QA tasks (code review, test validation) |
State management
All project state lives in a single memory/projects.json file in the orchestrator's workspace, keyed by Telegram group ID:
{
"projects": {
"-1234567890": {
"name": "my-webapp",
"repo": "~/git/my-webapp",
"groupName": "Dev - My Webapp",
"baseBranch": "development",
"autoChain": true,
"dev": {
"active": false,
"issueId": null,
"model": "medior",
"sessions": {
"junior": "agent:orchestrator:subagent:a9e4d078-...",
"medior": "agent:orchestrator:subagent:b3f5c912-...",
"senior": null
}
},
"qa": {
"active": false,
"issueId": null,
"model": "qa",
"sessions": {
"qa": "agent:orchestrator:subagent:18707821-..."
}
}
}
}
}
Key design decisions:
- Session-per-tier — each tier gets its own worker session, accumulating context independently. Tier selection maps directly to a session key.
- Sessions preserved on completion — when a worker completes a task,
sessionsmap is preserved (onlyactiveandissueIdare cleared). This enables session reuse on the next pickup. - Plugin-controlled dispatch — the plugin creates and dispatches to sessions via OpenClaw CLI (
sessions.patch+openclaw agent). The orchestrator agent never callssessions_spawnorsessions_send. - Sessions persist indefinitely — no auto-cleanup.
session_healthhandles manual cleanup when needed.
All writes go through atomic temp-file-then-rename to prevent corruption.
Tools
devclaw_setup
Set up DevClaw in an agent's workspace. Creates AGENTS.md, HEARTBEAT.md, role templates, and configures models. Can optionally create a new agent.
Parameters:
newAgentName(string, optional) — Create a new agent with this namemodels(object, optional) — Model overrides per tier:{ junior, medior, senior, qa }
task_pickup
Pick up a task from the issue queue for a DEV or QA worker.
Parameters:
issueId(number, required) — Issue IDrole("dev" | "qa", required) — Worker roleprojectGroupId(string, required) — Telegram group IDmodel(string, optional) — Developer tier (junior, medior, senior, qa). The orchestrator should evaluate the task complexity and choose. Falls back to keyword heuristic if omitted.
What it does atomically:
- Resolves project from
projects.json - Validates no active worker for this role
- Fetches issue from issue tracker, verifies correct label state
- Assigns tier (LLM-chosen via
modelparam, keyword heuristic fallback) - Loads role instructions from
roles/<project>/<role>.md(fallback:roles/default/<role>.md) - Looks up existing session for assigned tier (session-per-tier)
- Transitions label (e.g.
To Do→Doing) - Creates session via Gateway RPC if new (
sessions.patch) - Dispatches task to worker session via CLI (
openclaw agent) with role instructions appended - Updates
projects.jsonstate (active, issueId, tier, session key) - Writes audit log entry
- Returns announcement text for the orchestrator to post
task_complete
Complete a task with a result. Called by workers (DEV/QA sub-agent sessions) directly, or by the orchestrator.
Parameters:
role("dev" | "qa", required)result("done" | "pass" | "fail" | "refine" | "blocked", required)projectGroupId(string, required)summary(string, optional) — For the Telegram announcement
Results:
- DEV "done" — Pulls latest code, moves label
Doing→To Test, deactivates worker. IfautoChainenabled, automatically dispatches QA. - DEV "blocked" — Moves label
Doing→To Do, deactivates worker. Task returns to queue for retry. - QA "pass" — Moves label
Testing→Done, closes issue, deactivates worker - QA "fail" — Moves label
Testing→To Improve, reopens issue. IfautoChainenabled, automatically dispatches DEV fix (reuses previous DEV tier). - QA "refine" — Moves label
Testing→Refining, awaits human decision - QA "blocked" — Moves label
Testing→To Test, deactivates worker. Task returns to QA queue for retry.
task_update
Change an issue's state label programmatically without going through the full pickup/complete flow.
Parameters:
projectGroupId(string, required) — Telegram/WhatsApp group IDissueId(number, required) — Issue ID to updatestate(string, required) — New state label (Planning, To Do, Doing, To Test, Testing, Done, To Improve, Refining)reason(string, optional) — Audit log reason for the change
Use cases:
- Manual state adjustments (e.g., Planning → To Do after approval)
- Failed auto-transitions that need correction
- Bulk state changes by orchestrator
task_comment
Add a comment to an issue for feedback, notes, or discussion.
Parameters:
projectGroupId(string, required) — Telegram/WhatsApp group IDissueId(number, required) — Issue ID to comment onbody(string, required) — Comment body in markdownauthorRole("dev" | "qa" | "orchestrator", optional) — Attribution role
Use cases:
- QA adds review feedback without blocking pass/fail
- DEV posts implementation notes or progress updates
- Orchestrator adds summary comments
task_create
Create a new issue in the project's issue tracker. Used by workers to file follow-up bugs, or by the orchestrator to create tasks from chat.
Parameters:
projectGroupId(string, required) — Telegram group IDtitle(string, required) — Issue titledescription(string, optional) — Full issue body in markdownlabel(string, optional) — State label (defaults to "Planning")assignees(string[], optional) — Usernames to assignpickup(boolean, optional) — If true, immediately pick up for DEV after creation
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
What it does:
- Queries live sessions via Gateway RPC (
sessions.list) - Cross-references with
projects.jsonworker state
Checks:
- Active worker with no session key (critical, auto-fixable)
- Active worker whose session is dead — zombie (critical, auto-fixable)
- Worker active for >2 hours — stale watchdog (warning, auto-fixable: reverts label to queue)
- Inactive worker with lingering issue ID (warning, auto-fixable)
project_register
Register a new project with DevClaw. Creates all required issue tracker labels (idempotent), scaffolds role instruction files, and adds the project to projects.json. One-time setup per project. Auto-detects GitHub/GitLab from git remote.
Parameters:
projectGroupId(string, required) — Telegram group ID (key in projects.json)name(string, required) — Short project namerepo(string, required) — Path to git repo (e.g.~/git/my-project)groupName(string, required) — Telegram group display namebaseBranch(string, required) — Base branch for developmentdeployBranch(string, optional) — Defaults to baseBranchdeployUrl(string, optional) — Deployment URL
What it does atomically:
- Validates project not already registered
- Resolves repo path, auto-detects GitHub/GitLab, and verifies access
- Creates all 8 state labels (idempotent — safe to run on existing projects)
- Adds project entry to
projects.jsonwith empty worker state andautoChain: false - Scaffolds role instruction files:
roles/<project>/dev.mdandroles/<project>/qa.md(copied fromroles/default/) - Writes audit log entry
- Returns announcement text
Audit logging
Every tool call automatically appends an NDJSON entry to memory/audit.log. No manual logging required from the orchestrator agent.
{"ts":"2026-02-08T10:30:00Z","event":"task_pickup","project":"my-webapp","issue":42,"role":"dev","tier":"medior","sessionAction":"send"}
{"ts":"2026-02-08T10:30:01Z","event":"model_selection","issue":42,"role":"dev","tier":"medior","reason":"Standard dev task"}
{"ts":"2026-02-08T10:45:00Z","event":"task_complete","project":"my-webapp","issue":42,"role":"dev","result":"done"}
Quick start
# 1. Install the plugin
cp -r devclaw ~/.openclaw/extensions/
# 2. Run setup (interactive — creates agent, configures models, writes workspace files)
openclaw devclaw setup
# 3. Add bot to Telegram group, then register a project
# (via the agent in Telegram)
See the Onboarding Guide for detailed instructions.
Configuration
Model tier configuration in openclaw.json:
{
"plugins": {
"entries": {
"devclaw": {
"config": {
"models": {
"junior": "anthropic/claude-haiku-4-5",
"medior": "anthropic/claude-sonnet-4-5",
"senior": "anthropic/claude-opus-4-5",
"qa": "anthropic/claude-sonnet-4-5"
}
}
}
}
}
}
Restrict tools to your orchestrator agent only:
{
"agents": {
"list": [
{
"id": "my-orchestrator",
"tools": {
"allow": [
"devclaw_setup",
"task_pickup",
"task_complete",
"task_update",
"task_comment",
"task_create",
"queue_status",
"session_health",
"project_register"
]
}
}
]
}
}
DevClaw uses an
IssueProviderinterface to abstract issue tracker operations. GitLab (viaglabCLI) and GitHub (viaghCLI) are supported — the provider is auto-detected from the git remote URL. Jira is planned.
Role instructions
Workers receive role-specific instructions appended to their task message. project_register scaffolds editable files:
workspace/
├── roles/
│ ├── default/ ← sensible defaults (created once)
│ │ ├── dev.md
│ │ └── qa.md
│ ├── my-webapp/ ← per-project overrides (edit to customize)
│ │ ├── dev.md
│ │ └── qa.md
│ └── another-project/
│ ├── dev.md
│ └── qa.md
task_pickup loads roles/<project>/<role>.md with fallback to roles/default/<role>.md. Edit the per-project files to customize worker behavior — for example, adding project-specific deployment steps or test commands.
Requirements
- OpenClaw
- Node.js >= 20
glabCLI installed and authenticated (GitLab provider), orghCLI (GitHub provider)
License
MIT
