Install
openclaw skills install @netanel-abergel/pa-ownershipAutonomous task tracking with retry loops and proactive updates. Use when Heleni takes ownership of a task that needs to be tracked, retried on failure, and reported when complete or stuck. Integrates with heartbeat to surface stale tasks.
openclaw skills install @netanel-abergel/pa-ownershipCONTEXT_FILE="/opt/ocana/openclaw/workspace/skills/pa-ownership/.context"
[ -f "$CONTEXT_FILE" ] && source "$CONTEXT_FILE"
# Then use: $OWNER_PHONE, $TASKS_FILE, $WORKSPACE, etc.
Heleni tracks tasks she owns — executing, retrying when blocked, and closing the loop when done.
Trigger phrases:
All tasks are persisted to:
/opt/ocana/openclaw/workspace/data/pa-tasks.json
{
"tasks": [
{
"id": "task_<YYYYMMDD_HHMMSS>",
"title": "Short task description",
"description": "Full context / what needs to happen",
"status": "NEW",
"initiated_by": "Netanel | group:<jid> | self",
"created_at": "2026-04-03T10:00:00Z",
"updated_at": "2026-04-03T10:00:00Z",
"due_at": null,
"attempts": 0,
"max_attempts": 3,
"last_attempt_at": null,
"blocked_reason": null,
"result": null,
"reported_done": false
}
]
}
| Status | Meaning |
|---|---|
NEW | Task received, not yet started |
IN_PROGRESS | Currently executing |
DONE | Completed successfully |
BLOCKED | Cannot proceed — waiting on something |
FAILED | Exhausted all retry attempts |
When a task is received and Heleni commits to it:
data/pa-tasks.json (create if missing: {"tasks": []})task_<YYYYMMDD_HHMMSS>initiated_by:
"Netanel""group:<jid>""self"status: "NEW", attempts: 0memory/whatsapp/dms/<PHONE-sanitized>/context.mdIN_PROGRESS, update updated_atOn failure or block:
attempts counterblocked_reasonlast_attempt_atBackoff schedule:
FAILED, notify Netanel immediatelyIf attempts >= max_attempts:
→ Set status: "FAILED"
→ Report to initiated_by: "❌ [task] failed after 3 attempts: [reason]"
→ Do NOT retry further
Else:
→ Set status: "BLOCKED"
→ Log blocked_reason
→ Schedule retry (via heartbeat or mental note)
status: "DONE", result: "<outcome summary>", updated_at: nowreported_done == false:
initiated_by with resultreported_done: trueClose-the-loop rule: ALWAYS report back to whoever initiated the task. No exceptions.
After every state change, write the full updated pa-tasks.json.
import json, datetime, os
TASKS_FILE = "/opt/ocana/openclaw/workspace/data/pa-tasks.json"
def load_tasks():
if not os.path.exists(TASKS_FILE):
return {"tasks": []}
with open(TASKS_FILE) as f:
return json.load(f)
def save_tasks(data):
os.makedirs(os.path.dirname(TASKS_FILE), exist_ok=True)
with open(TASKS_FILE, "w") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
def update_task_status(task_id, status, **kwargs):
data = load_tasks()
for task in data["tasks"]:
if task["id"] == task_id:
task["status"] = status
task["updated_at"] = datetime.datetime.utcnow().isoformat() + "Z"
for k, v in kwargs.items():
task[k] = v
break
save_tasks(data)
During every heartbeat, scan for stale tasks:
For each task in pa-tasks.json where status IN ["IN_PROGRESS", "BLOCKED"]:
age = now - updated_at
If age > 2 hours AND NOT reported_stuck:
→ Mark last_notified_at = now
If status == "BLOCKED" AND attempts < max_attempts:
→ Attempt retry
Add this block to HEARTBEAT.md:
## PA Ownership Check
- Scan data/pa-tasks.json for IN_PROGRESS or BLOCKED tasks
- Alert if any task >2h without update
- Retry BLOCKED tasks with remaining attempts
When setting up this skill for the first time, add to HEARTBEAT.md:
## Task Ownership Check
- Read /opt/ocana/openclaw/workspace/data/pa-tasks.json
- Flag any task with status IN_PROGRESS or BLOCKED updated >2h ago
- Retry BLOCKED tasks if attempts < max_attempts
- Report FAILED tasks to Netanel immediately
📋 [task title]
[max_attempts]
📝 [result summary]
last_notified_at)