Bug: `claude-flow status` shows STOPPED even when daemon is running
- Dominant language
- TypeScript
- Stars
- 72.7k
- Forks
- 8.6k
- Avg merge
- 2d 23h
- Merged PRs (30d)
- 83
Description
# Bug: `claude-flow status` shows STOPPED even when daemon is running
## Summary
Running `claude-flow status` always shows `[STOPPED]` with all metrics at zero, even when:
- Daemon is confirmed running (`ps aux` shows the process)
- `claude-flow daemon start` reports success
- `claude-flow doctor` passes all checks
## Environment
- **Version**: @claude-flow/cli@3.0.0-alpha.158
- **OS**: macOS (Darwin 24.0.0)
- **Node**: v23.10.0
## Steps to Reproduce
```bash
# Start daemon
npx @claude-flow/cli@latest daemon start
# Output: [OK] Daemon started in background (PID: 18824)
# Verify daemon is running
ps aux | grep 18824
# Output: node ... daemon start --foreground --quiet
# Check status
npx @claude-flow/cli@latest status
# Output: Claude Flow V3 [STOPPED] ← BUG: should show [RUNNING]
```
## Root Cause
Two issues in the codebase:
### Issue 1: Missing `task_summary` MCP tool
**File**: `src/mcp-tools/task-tools.ts`
The `status.ts` command calls `task_summary` but this tool doesn't exist. Only these tools are defined:
- `task_create`, `task_status`, `task_list`, `task_complete`, `task_update`, `task_cancel`
### Issue 2: Monolithic error handling in `getSystemStatus()`
**File**: `src/commands/status.ts` (around line 69)
The entire function is wrapped in ONE try-catch. If ANY MCP tool fails, it returns "stopped":
```typescript
async function getSystemStatus() {
try {
const swarmStatus = await callMCPTool('swarm_status', {});
const memoryStatus = await callMCPTool('memory_stats', {});
const taskStatus = await callMCPTool('task_summary', {}); // ← FAILS: tool doesn't exist
// ... build status object
} catch (error) {
// ANY error → return stopped status
return { running: false, ... };
}
}
```
## Fix
### Fix 1: Add `task_summary` tool
In `src/mcp-tools/task-tools.ts`, add this tool definition to the `taskTools` array:
```typescript
{
name: 'task_summary',
description: 'Get task summary counts by status',
category: 'task',
inputSchema: {
type: 'object',
properties: {},
},
handler: async () => {
const store = loadTaskStore();
const tasks = Object.values(store.tasks);
return {
total: tasks.length,
pending: tasks.filter(t => t.status === 'pending').length,
running: tasks.filter(t => t.status === 'in_progress' || t.status === 'running').length,
completed: tasks.filter(t => t.status === 'completed').length,
failed: tasks.filter(t => t.status === 'failed').length,
cancelled: tasks.filter(t => t.status === 'cancelled').length,
};
},
},
```
### Fix 2: Granular error handling in status.ts
Replace the monolithic try-catch with individual try-catch per service. This way, if one service fails, others still report correctly:
```typescript
async function getSystemStatus() {
const status = {
initialized: true,
running: false,
swarm: { id: null, topology: 'none', agents: { total: 0, active: 0, idle: 0 }, health: 'stopped', uptime: 0 },
mcp: { running: false, port: null, transport: 'stdio' },
memory: { entries: 0, size: '0 B', backend: 'none', performance: { searchTime: 0, cacheHitRate: 0 } },
tasks: { total: 0, pending: 0, running: 0, completed: 0, failed: 0 },
performance: { cpuUsage: getProcessCpuUsage(), memoryUsage: getProcessMemoryUsage(), flashAttention: 'N/A', searchSpeed: 'N/A' }
};
let anyServiceRunning = false;
// Swarm (with fallback)
try {
const swarmStatus = await callMCPTool('swarm_status', { includeMetrics: true });
if (swarmStatus) {
anyServiceRunning = true;
status.swarm = {
id: swarmStatus.swarmId || swarmStatus.id || null,
topology: swarmStatus.topology || 'unknown',
agents: swarmStatus.agents || { total: swarmStatus.agentCount || 0, active: 0, idle: 0 },
health: swarmStatus.health || (swarmStatus.status === 'running' ? 'healthy' : 'stopped'),
uptime: swarmStatus.uptime || 0
};
}
} catch { /* swarm not running */ }
// MCP (with fallback)
try {
const mcp = await callMCPTool('mcp_status', {});
if (mcp) { anyServiceRunning = true; status.mcp = mcp; }
} catch { /* MCP not running */ }
// Memory (with fallback + field name handling)
try {
const memoryStatus = await callMCPTool('memory_stats', {});
if (memoryStatus) {
anyServiceRunning = true;
const entries = memoryStatus.entries ?? memoryStatus.totalEntries ?? 0;
const size = typeof memoryStatus.size === 'number' ? memoryStatus.size : 0;
status.memory = {
entries,
size: formatBytes(size),
backend: memoryStatus.backend || 'unknown',
performance: {
searchTime: memoryStatus.performance?.avgSearchTime ?? 0,
cacheHitRate: memoryStatus.performance?.cacheHitRate ?? 0
}
};
}
} catch { /* memory not available */ }
// Tasks (with fallback to task_list)
try {
const taskStatus = await callMCPTool('task_summary', {});
if (taskStatus) { anyServiceRunning = true; status.tasks = taskStatus; }
} catch {
try {
const taskList = await callMCPTool('task_list', {});
if (taskList?.tasks) {
anyServiceRunning = true;
const tasks = taskList.tasks;
status.tasks = {
total: tasks.length,
pending: tasks.filter(t => t.status === 'pending').length,
running: tasks.filter(t => t.status === 'in_progress' || t.status === 'running').length,
completed: tasks.filter(t => t.status === 'completed').length,
failed: tasks.filter(t => t.status === 'failed').length
};
}
} catch { /* tasks not available */ }
}
status.running = anyServiceRunning;
if (anyServiceRunning) {
status.performance.flashAttention = '2.8x speedup';
status.performance.searchSpeed = '150x faster';
}
return status;
}
```
## Tested Fix
I applied these fixes locally to the npx cache and confirmed:
```bash
$ npx @claude-flow/cli@latest status
Claude Flow V3 [RUNNING] ← Now works!
Swarm
+----------+---------+
| Property | Value |
+----------+---------+
| Topology | unknown |
| Health | healthy |
+----------+---------+
Tasks
+-----------+-------+
| Pending | 1 | ← Correctly counts tasks
| Total | 1 |
+-----------+-------+
Memory
+----------------+-------+
| Backend | file | ← Correctly detects backend
+----------------+-------+
```
## Bonus Bug Found: Memory Backend Mismatch
While investigating, I found a separate issue:
- `memory_stats` MCP tool reads from hardcoded path `.claude-flow/memory/store.json`
- CLI `memory store` command writes to agentdb (different backend)
- Config specifies `persistPath: .claude-flow/data`
This causes `memory_stats` to always show 0 entries even after storing data. Separate issue, lower priority.
---
**Files to modify:**
1. `v3/@claude-flow/cli/src/mcp-tools/task-tools.ts` - add `task_summary`
2. `v3/@claude-flow/cli/src/commands/status.ts` - granular error handling
Contributor guide
Research direction
Start by reading src/commands/status.ts around getSystemStatus() and src/mcp-tools/task-tools.ts, then run the reported daemon start and status commands. Confirm that status remains RUNNING when an individual MCP lookup fails, that task counts are available, and that the relevant existing checks pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100