taskflow-inbox-triage
This TaskFlow skill demonstrates how to route inbox messages into different handling paths: business items post to Slack and await replies, personal items trigger immediate notifications, and remaining messages queue for end-of-day summary. Use this pattern when building workflows that require classification-based branching with mixed synchronous and asynchronous processing, including waiting for external responses before completion.
git clone --depth 1 https://github.com/the-open-agent/openagent /tmp/taskflow-inbox-triage && cp -r /tmp/taskflow-inbox-triage/skills/taskflow-inbox-triage ~/.claude/skills/taskflow-inbox-triageSKILL.md
# TaskFlow inbox triage
This is a concrete example of how to think about TaskFlow without turning the core runtime into a DSL.
## Goal
Triage inbox items with one owner flow:
- business → post to Slack and wait for reply
- personal → notify the owner now
- everything else → keep for end-of-day summary
## Pattern
1. Create one flow for the inbox batch.
2. Run one detached task to classify new items.
3. Persist the routing state in `stateJson`.
4. Move to `waiting` only when an outside reply is required.
5. Resume the flow when classification or human input completes.
6. Finish when the batch has been routed.
## Suggested `stateJson` shape
```json
{
"businessThreads": [],
"personalItems": [],
"eodSummary": []
}
```
Suggested `waitJson` when blocked on Slack:
```json
{
"kind": "reply",
"channel": "slack",
"threadKey": "slack:thread-1"
}
```
## Minimal runtime calls
```ts
const taskFlow = api.runtime.tasks.flow.fromToolContext(ctx);
const created = taskFlow.createManaged({
controllerId: "my-plugin/inbox-triage",
goal: "triage inbox",
currentStep: "classify",
stateJson: {
businessThreads: [],
personalItems: [],
eodSummary: [],
},
});
const child = taskFlow.runTask({
flowId: created.flowId,
runtime: "acp",
childSessionKey: "agent:main:subagent:classifier",
task: "Classify inbox messages",
status: "running",
startedAt: Date.now(),
lastEventAt: Date.now(),
});
if (!child.created) {
throw new Error(child.reason);
}
const waiting = taskFlow.setWaiting({
flowId: created.flowId,
expectedRevision: created.revision,
currentStep: "await_business_reply",
stateJson: {
businessThreads: ["slack:thread-1"],
personalItems: [],
eodSummary: [],
},
waitJson: {
kind: "reply",
channel: "slack",
threadKey: "slack:thread-1",
},
});
if (!waiting.applied) {
throw new Error(waiting.code);
}
const resumed = taskFlow.resume({
flowId: waiting.flow.flowId,
expectedRevision: waiting.flow.revision,
status: "running",
currentStep: "route_items",
stateJson: waiting.flow.stateJson,
});
if (!resumed.applied) {
throw new Error(resumed.code);
}
taskFlow.finish({
flowId: resumed.flow.flowId,
expectedRevision: resumed.flow.revision,
stateJson: resumed.flow.stateJson,
});
```
## Related example
- `skills/taskflow/examples/inbox-triage.lobster`Set up and use 1Password CLI (op). Use when installing the CLI, enabling desktop app integration, signing in (single or multi-account), or reading/injecting/running secrets via op.
Manage Apple Notes via the `memo` CLI on macOS (create, view, edit, delete, search, move, and export notes). Use when a user asks OpenClaw to add a note, list notes, search notes, or manage note folders.
Manage Apple Reminders via remindctl CLI (list, add, edit, complete, delete). Supports lists, date filters, and JSON/plain output.
Create, search, and manage Bear notes via grizzly CLI.
Monitor blogs and RSS/Atom feeds for updates using the blogwatcher CLI.
BluOS CLI (blu) for discovery, playback, grouping, and volume.
Use when you need to send or manage iMessages via BlueBubbles (recommended iMessage integration). Calls go through the generic message tool with channel="bluebubbles".
Capture frames or clips from RTSP/ONVIF cameras.