Every project management board eventually lies. Not because people are careless, but because state updates require a separate manual action after the real-world event that should have triggered them. A PR gets merged — the board still says "In Review." A blocker gets resolved in a Slack thread — the board still says "Blocked." A decision gets made in a call — it never makes it to the board at all.
The divergence rate scales with project velocity. The faster things move, the further the board drifts from actual project state. At some point, checking the board stops being useful and the team reverts to asking each other directly.
Event-driven state management inverts this. Every meaningful project event — commit, PR merge, Slack message, decision — triggers an automatic state update. The board reflects reality because it is derived from events, not maintained in parallel with them.
This is one of the most practically transformative OpenClaw use cases in the Infrastructure & DevOps category, and a direct extension of the STATE.yaml coordination pattern introduced in the Autonomous Project Management tutorial.
By the end of this tutorial you'll have a project state system that updates automatically on every commit, PR, Slack decision, and custom event — with a plain-English query interface that answers "what is blocking task X?" or "what happened on this project in the last 48 hours?" from a live STATE.yaml. Validate the state update logic in AI Studio before connecting any live webhook. Get your WisGate key at wisgate.ai/hall/tokens.
WisGate + OpenClaw Configuration
Step 1 — Open the configuration file
nano ~/.openclaw/openclaw.json
Step 2 — Add the WisGate provider
Paste the following into your models section. This registers Claude Haiku for high-frequency event ingestion and state updates, and Claude Sonnet for context summarization and project status queries:
"models": {
"mode": "merge",
"providers": {
"moonshot": {
"baseUrl": "https://api.wisgate.ai/v1",
"apiKey": "WISGATE-API-KEY",
"api": "openai-completions",
"models": [
{
"id": "claude-haiku-4-5-20251001",
"name": "Claude Haiku 4.5",
"reasoning": false,
"input": ["text"],
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"contextWindow": 256000,
"maxTokens": 8192
},
{
"id": "claude-sonnet-4-5",
"name": "Claude Sonnet 4.5",
"reasoning": false,
"input": ["text"],
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"contextWindow": 256000,
"maxTokens": 8192
}
]
}
}
}
Replace WISGATE-API-KEY with your key from wisgate.ai/hall/tokens. Confirm both model prices at wisgate.ai/models.
Step 3 — Save and restart
Ctrl + O→Enter→Ctrl + Xto save and exitCtrl + Cto stop, then runopenclaw tui
Step 4 — Validate the state update logic before connecting live webhooks
curl -s -X POST "https://api.wisgate.ai/v1/chat/completions" \
-H "Authorization: Bearer $WISDOM_GATE_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-haiku-4-5-20251001",
"messages": [
{"role": "system", "content": "[PASTE EVENT INGESTION PROMPT HERE]"},
{"role": "user", "content": "Event:\n\n[SAMPLE EVENT PAYLOAD]\n\nCurrent STATE.yaml:\n\n[PASTE STATE HERE]"}
],
"max_tokens": 1024
}' | jq -r '.choices[0].message.content'
Note: OpenClaw was previously known as ClawdBot and MoltBot. These steps apply to all versions.
LLM Event-Driven Project Management: EVENT → STATE.yaml Pipeline
Three event sources feed a single STATE.yaml file:
| Event source | Event types | Trigger method |
|---|---|---|
| GitHub | Push, PR opened/merged/closed, issue comment | GitHub Apps webhook |
| Slack | Message in project channel, reaction added | Slack Events API subscription |
| Custom | Deploy, test result, decision, any structured event | Generic POST endpoint |
State update pipeline — per event:
Incoming event webhook
↓
Normalize to event schema
↓
Haiku: classify event type → generate STATE.yaml patch
↓
Apply patch to STATE.yaml
↓
If decision or blocker event:
Sonnet: generate context summary → append to decision_log[]
↓
STATE.yaml updated — query interface available immediately
Why two model tiers: Haiku processes every incoming event — it classifies the type and applies the minimum necessary patch to STATE.yaml. Sonnet is triggered only on decision and blocker events, where generating a durable, specific context summary warrants the additional inference quality. Running Sonnet on every event would increase per-day cost roughly 5× without meaningful improvement on routine commits and PRs.
Connection to STATE.yaml pattern: this tutorial extends the Autonomous Project Management STATE.yaml pattern. That case uses STATE.yaml as a task queue for parallel agents. This case uses the same file as a live project state document maintained by real-world event streams. The schema is compatible — an autonomous agent and an event-driven tracker can operate on the same STATE.yaml simultaneously.
OpenClaw API Project State Automation: Event Schema and STATE.yaml Structure
Normalized event schema — all three sources map to this format:
{
"event_id": "unique identifier",
"event_type": "commit|pr_merged|pr_opened|issue_comment|slack_message|decision|blocker|deploy|custom",
"source": "github|slack|custom",
"project_id": "maps to STATE.yaml pipeline_id",
"actor": "username or handle",
"timestamp": "ISO 8601",
"content": "event description or message text",
"metadata": {}
}
Webhook setup (GitHub example):
- Repository Settings → Webhooks → Add webhook
- Payload URL:
POST https://your-server.com/events/github - Content type:
application/json - Events: Pushes, Pull requests, Issue comments
- Your server normalizes the GitHub payload to the event schema above before passing to the agent
STATE.yaml schema — extends the Autonomous Project Management pattern:
pipeline_id: "project-alpha"
project_name: "Alpha — API Rewrite"
last_updated: "2026-03-16T07:45:00Z"
overall_status: "on_track" # on_track | at_risk | blocked
tasks:
- id: "task-003"
description: "Migrate auth service to new API"
status: "in_progress" # pending | in_progress | blocked | completed
assigned_to: "dev-handle"
last_event: "PR #47 opened 2026-03-15"
blockers: []
completed_at: null
decision_log:
- timestamp: "2026-03-14T15:30:00Z"
decision: "Defer OAuth2 migration to v2 — out of scope for this sprint"
actor: "lead-handle"
source: "slack"
decision_log[] is a first-class field. It is what separates this from a simple task tracker and makes the query interface useful for retrospectives and audits.
The Event Ingestion and Context Capture Prompts
Event ingestion system prompt (Haiku — runs on every event):
You are a project state manager.
INPUT: a normalized event object and the current STATE.yaml.
TASK:
1. Match the event to a task by content keywords vs task descriptions
2. Apply the correct state update:
- commit or pr_merged → update last_event; if PR closes task, set status=completed
- blocker event → add to task blockers[]; set status=blocked; overall_status=at_risk
- blocker resolved → remove from blockers[]; restore status=in_progress
- decision event → flag for Sonnet context capture; do NOT update task status
3. Apply only the minimum necessary changes
4. Return the complete updated STATE.yaml only. No preamble.
If the event cannot be matched to any task with confidence, append to
unmatched_events[] for manual review.
Context summarization prompt (Sonnet — decision and blocker events only):
You are a project context capture agent.
INPUT: a decision or blocker event and the current STATE.yaml.
Generate one decision_log entry:
- Decision: what was decided, by whom, and the stated reason (one sentence)
- Blocker: what is blocked, what is blocking it, who reported it (one sentence)
Append to decision_log[]. Return the updated decision_log section only.
Natural language query interface (Sonnet, on demand):
You are a project status assistant.
You have access to the current STATE.yaml provided below.
Answer using only information present in STATE.yaml.
Be specific: reference task IDs, dates, actors, event descriptions.
If the answer is not in the data, say so.
Return plain prose — no YAML, no JSON.
STATE.yaml:
${STATE_YAML_CONTENT}
Example queries: "What is blocking task-003?" / "What happened in the last 48 hours?" / "Which tasks are at risk?" / "What decisions were logged this week?"
OpenClaw Use Cases: Cost Per Active Project Day
Daily token estimate (20 events/day, 3 decisions/day, 5 queries/day):
| Operation | Model | Calls/day | Tokens/call | Daily tokens |
|---|---|---|---|---|
| Event ingestion + state update | Haiku | 20 | ~1,200 | ~24,000 |
| Context summarization (decisions) | Sonnet | 3 | ~800 | ~2,400 |
| Project status queries | Sonnet | 5 | ~2,000 | ~10,000 |
| Daily total | Mixed | 28 | — | ~36,400 |
Annual cost (260 workdays) — confirm both model prices from wisgate.ai/models:
| Model | Annual tokens | WisGate cost | Direct API cost |
|---|---|---|---|
| Haiku — event updates | ~6.24M | Confirm + calculate | Confirm + calculate |
| Sonnet — context + queries | ~3.23M | Confirm + calculate | Confirm + calculate |
| Total | ~9.47M | Calculate | Calculate |
The Haiku event ingestion calls are the high-frequency baseline; Sonnet runs only on decisions, blockers, and explicit queries — keeping per-day cost proportional to actual project activity rather than event volume.
OpenClaw Use Cases: Project State That Updates Itself
The event schema is defined. Both system prompts are ready. The STATE.yaml structure is compatible with the Autonomous Project Management pattern — the same file can be used by autonomous agents and updated by live event streams simultaneously.
Deployment sequence: configure one event source (start with GitHub webhooks) → run the Step 4 validation call against a real event payload → verify STATE.yaml output → connect Slack events → activate the query interface.
Start with GitHub events only. A single active repository generates enough events to validate the full state update pipeline within one workday — before adding Slack and custom sources.
All three system prompts are on this page. Generate your WisGate key at wisgate.ai/hall/tokens — one key for Haiku event ingestion and Sonnet context capture. Before wiring any live webhook, test the event ingestion prompt against a real GitHub payload at wisgate.ai/studio/image. The first event that updates STATE.yaml automatically is the moment the Kanban board becomes optional.