From emasoft-orchestrator-agent
Agent progress monitoring via state-based detection. Use when tracking task completion, detecting stalls, or escalating unresponsive agents. Trigger with progress checks.
npx claudepluginhub emasoft/emasoft-plugins --plugin emasoft-orchestrator-agentThis skill uses the workspace's default tool permissions.
This skill defines how the Orchestrator (EOA) monitors agent progress. Monitoring is based on **state transitions** and **response order** - not fixed time intervals. Agents collaborate asynchronously and may be hibernated for extended periods. The orchestrator tracks agent states (Acknowledged, Active, No Progress, Stale, Unresponsive, Blocked, Complete) and escalates through ordered steps whe...
Monitors AI agent progress on GitHub issues via state transitions, detects stalls, sends reminders, escalates unresponsive tasks, handles blockers, and verifies completions.
Orchestrates AI agents by scanning statuses, assessing progress, sending self-contained instructions, and coordinating multi-agent workflows. Use for managing agent progress or multi-agent dev tasks.
Implements PACT agent teams protocol for task claiming, teachback verification, inter-agent messaging with SendMessage, blocker reporting, and work handoffs.
Share bugs, ideas, or general feedback.
This skill defines how the Orchestrator (EOA) monitors agent progress. Monitoring is based on state transitions and response order - not fixed time intervals. Agents collaborate asynchronously and may be hibernated for extended periods. The orchestrator tracks agent states (Acknowledged, Active, No Progress, Stale, Unresponsive, Blocked, Complete) and escalates through ordered steps when issues are detected.
Monitor agents based on their current state:
| State | Definition | Action |
|---|---|---|
| Acknowledged | Agent sent ACK for assigned task | Normal monitoring |
| No ACK | Task assigned but no acknowledgment received | Send reminder |
| Active | Agent sending progress updates | Continue monitoring |
| No Progress | Agent acknowledged but no updates since | Send status request |
| Stale | Agent's last update predates significant events | Escalate priority |
| Unresponsive | Multiple reminders without any response | Consider reassignment |
| Blocked | Agent reported blocker | Address blocker |
| Complete | Agent reported task done | Verify and close |
Use the agent-messaging skill to retrieve the agent's last message timestamp. Query the message list for the agent and extract the timestamp of the most recent message.
# Get task assignment event
gh issue view $ISSUE --json timelineItems | jq '.timelineItems[] | select(.label == "assign:$AGENT_NAME")'
Assigned → (ACK received) → Acknowledged
Acknowledged → (progress update) → Active
Acknowledged → (no updates) → No Progress
Active → (no updates after activity) → Stale
No Progress/Stale → (reminder sent, no response) → Unresponsive
Any → (blocker reported) → Blocked
Active → (completion reported) → Complete
Escalation follows a strict order, not time-based triggers:
| Step | Trigger State | Action | Priority |
|---|---|---|---|
| 1 | No ACK | Send first reminder | Normal |
| 2 | Still No ACK after Step 1 | Send urgent reminder | High |
| 3 | Unresponsive after Step 2 | Notify user, consider reassignment | Urgent |
When state = No ACK or No Progress:
Note: Use the
agent-messagingskill to send messages. The JSON structure below shows the message content.
{
"from": "orchestrator",
"to": "<agent-name>",
"subject": "Status Request: <task-id>",
"priority": "normal",
"content": {
"type": "request",
"message": "What is your current status on <task-id>? Report progress, blockers, and next steps.",
"data": {
"task_id": "<task-id>"
}
}
}
When state = Unresponsive (no response to first reminder):
Note: Use the
agent-messagingskill to send messages. The JSON structure below shows the message content.
{
"from": "orchestrator",
"to": "<agent-name>",
"subject": "URGENT: <task-id> - Response Required",
"priority": "urgent",
"content": {
"type": "escalation",
"message": "No response received. Please provide status immediately or task may be reassigned.",
"data": {
"task_id": "<task-id>",
"escalation_level": 2
}
}
}
When still unresponsive after urgent reminder:
Agents should report progress using this format:
[IN_PROGRESS] <task-id> - <brief-description>
Progress: <percentage or milestone>
Next: <next-step>
Blockers: <none or blocker-list>
[DONE] <task-id> - <result-summary>
Output: <file-path or PR-number>
Tests: <passed/failed>
[BLOCKED] <task-id> - <blocker-description>
Waiting on: <dependency or resource>
Impact: <what cannot proceed>
Suggested resolution: <if any>
IRON RULE FOR BLOCKERS: The user must ALWAYS be informed of blockers immediately. There is NO scenario where a blocker should be "monitored quietly" for hours or days before telling the user. The user may have the solution ready in minutes — but only if they know about the problem.
When an agent reports [BLOCKED], EOA must verify the blocker is real (agent cannot solve it themselves), then IMMEDIATELY escalate to EAMA for user notification. There is NO waiting period for user notification — escalation happens as soon as the blocker is confirmed.
A blocker is ANY condition preventing task progress that the assigned agent cannot resolve independently:
| Blocker Category | Examples | Verification |
|---|---|---|
| Task Dependency | Feature B requires API from Feature A (still in development) | Check if blocking task is complete |
| Problem Resolution | Bug must be fixed before feature can be tested | Verify bug status, check if workaround exists |
| Missing Resource | Need API key, database access, test environment | Confirm resource is not available via normal channels |
| Missing Approval | Design decision, architecture choice, breaking change | Check if approval authority (user/architect) was consulted |
| External Dependency | Third-party API down, vendor response needed | Verify external status, check if alternative exists |
| Access/Credentials | Repository access, deployment credentials, service permissions | Confirm access cannot be obtained via team processes |
When agent reports [BLOCKED]:
status:blocked labelstatus:in-progress (or whatever status it had) labeltype:blocker, referencing the blocked task). This makes the blocking problem visible to all agents and team members on the issue tracker.# BEFORE moving to blocked, record current status
CURRENT_STATUS=$(gh issue view $ISSUE --json labels | jq -r '.labels[] | select(.name | startswith("status:")) | .name')
# Mark task as blocked
gh issue edit $ISSUE --remove-label "$CURRENT_STATUS" --add-label "status:blocked"
# Create a GitHub issue for the blocker (the problem preventing progress)
BLOCKER_ISSUE=$(gh issue create --title "BLOCKER: <one-line description of the blocking problem>" --label "type:blocker" \
--body "## Blocker
This issue tracks a problem that is blocking task #$ISSUE.
**Blocked Task**: #$ISSUE
**Category**: <Task Dependency | Problem Resolution | Missing Resource | Access/Credentials | Missing Approval | External Dependency>
**What's Needed**: <specific action to resolve>
**Impact**: <what work is prevented>
**Previous Status**: $CURRENT_STATUS
## Resolution
Close this issue when the blocking problem is resolved and the blocked task can resume." \
| grep -oP '\d+$')
# Add blocker details as comment on the blocked task
gh issue comment $ISSUE --body "BLOCKED: <blocker-description>. Previous status: $CURRENT_STATUS. Blocker tracked in #$BLOCKER_ISSUE"
When a blocker is resolved, the task returns to the COLUMN IT WAS IN BEFORE being blocked (not always "In Progress" — it could have been in Testing, Review, Deploy, etc.).
# Retrieve previous status from issue comments or metadata
PREVIOUS_STATUS=$(gh issue view $ISSUE --json comments | jq -r '.comments[-1].body' | grep "Previous status:" | awk '{print $3}')
# Close the blocker issue (the issue tracking the blocking problem)
gh issue close $BLOCKER_ISSUE --comment "Resolved: <resolution details>. Blocked task #$ISSUE can now resume."
# Restore previous status on the blocked task
gh issue edit $ISSUE --remove-label "status:blocked" --add-label "$PREVIOUS_STATUS"
# Add resolution comment on the blocked task
gh issue comment $ISSUE --body "Unblocked. Blocker #$BLOCKER_ISSUE resolved. Returning to $PREVIOUS_STATUS."
# Notify agent that blocker is resolved
# (send message via AI Maestro using the agent-messaging skill)
Copy this checklist and track your progress:
When a task becomes blocked:
$CURRENT_STATUS) before moving to Blockedstatus:* label from the blocked taskstatus:blocked label to the blocked taskPrevious status: $CURRENT_STATUS)type:blocker label, referencing the blocked task)agent-messaging skill (include blocker_issue_number)When the blocker is resolved:
gh issue close $BLOCKER_ISSUE --comment "Resolved: ...")status:blocked label from the task$PREVIOUS_STATUS) on the taskWhen agent reports [DONE]:
Copy this checklist and track your progress:
# Update status
gh issue edit $ISSUE --remove-label "status:in-progress" --add-label "status:done"
# Remove assignment (task complete)
gh issue edit $ISSUE --remove-label "assign:$AGENT_NAME"
# Close issue if all criteria met
gh issue close $ISSUE
Send clarification request to agent:
{
"type": "request",
"message": "Completion verification failed. Missing: <list>. Please address and report again."
}
Track all active tasks:
| Task | Agent | State | Last Update | Priority |
|---|---|---|---|---|
| #42 | impl-01 | Active | Recent | High |
| #43 | impl-02 | No Progress | Stale | Normal |
| #44 | reviewer | Blocked | Recent | High |
Query active tasks:
# All in-progress tasks
gh issue list --label "status:in-progress" --json number,title,labels
# Blocked tasks
gh issue list --label "status:blocked" --json number,title,labels
# Tasks by agent
gh issue list --label "assign:impl-01" --json number,title,labels
Follow these steps to monitor agent progress:
status:in-progress label| Output Type | Format | Example |
|---|---|---|
| Agent state report | Markdown table | Task #42, impl-01, Active, last update 2h ago |
| Escalation message | AI Maestro JSON | Reminder or urgent message sent to agent |
| Dashboard view | Markdown table | All in-progress tasks with states |
| Blocker report | Issue comment | "BLOCKED: Waiting on API design approval" |
| Completion verification | Boolean + checklist | PR exists ✓, tests pass ✓, docs updated ✓ |
| Error | Cause | Solution |
|---|---|---|
| Agent never ACKs | Agent offline, hibernated, or unaware | Send reminder, escalate to ECOS if no response |
| Agent stops responding mid-task | Agent crashed, hibernated, or blocked | Follow escalation order (sections 3.1-3.3) |
| Blocker reported but not resolved | Dependency on external event | Coordinate with other agents or escalate to user |
| Completion reported but verification fails | Missing tests, failing CI, or incomplete requirements | Send REVISE message (see eoa-implementer-interview-protocol) |
| Multiple agents updating same task | Concurrent work or reassignment conflict | Check assign:* label, coordinate via AI Maestro |
| Stale state but agent actually hibernated | Normal hibernation, not a failure | Distinguish hibernation from unresponsiveness via ECOS |
# Get agent's last message timestamp
AGENT="implementer-1"
# Use the agent-messaging skill to retrieve messages for the agent
# and extract the timestamp of the most recent message
echo "Agent $AGENT last seen: $LAST_MESSAGE"
# Get task assignment timestamp
ISSUE=42
ASSIGNED_AT=$(gh issue view $ISSUE --json timelineItems | \
jq -r '.timelineItems[] | select(.label.name == "assign:'$AGENT'") | .createdAt')
echo "Task #$ISSUE assigned at: $ASSIGNED_AT"
Send a status request using the agent-messaging skill:
implementer-1request, Priority: normaltask_id: 42Verify: confirm message delivery.
Send an urgent escalation using the agent-messaging skill:
implementer-1escalation, Priority: urgenttask_id: 42, escalation_level: 2Verify: confirm message delivery.
ISSUE=42
# Agent reports blocker via message
# Update issue labels
gh issue edit $ISSUE --remove-label "status:in-progress" --add-label "status:blocked"
# Add blocker comment to issue
gh issue comment $ISSUE --body "BLOCKED: Waiting on API endpoint design approval. Cannot proceed until #38 is resolved."
# Query the blocking issue
BLOCKER_STATUS=$(gh issue view 38 --json state,labels | jq -r '.state')
echo "Blocking issue #38 status: $BLOCKER_STATUS"
# If blocker is resolved, notify agent
if [ "$BLOCKER_STATUS" = "closed" ]; then
gh issue edit $ISSUE --remove-label "status:blocked" --add-label "status:in-progress"
# Send message to agent
fi
ISSUE=42
# Check PR existence
PR_NUMBER=$(gh issue view $ISSUE --json body | jq -r '.body | match("PR #([0-9]+)") | .captures[0].string')
if [ -z "$PR_NUMBER" ]; then
echo "VERIFICATION FAILED: No PR linked"
else
# Check CI status
CI_STATUS=$(gh pr view $PR_NUMBER --json statusCheckRollup | jq -r '.statusCheckRollup[] | select(.conclusion) | .conclusion')
if [ "$CI_STATUS" = "SUCCESS" ]; then
echo "VERIFICATION PASSED: PR #$PR_NUMBER exists and CI passed"
# Update to done
gh issue edit $ISSUE --remove-label "status:in-progress" --add-label "status:done"
gh issue edit $ISSUE --remove-label "assign:implementer-1"
else
echo "VERIFICATION FAILED: CI status is $CI_STATUS"
fi
fi