🎯 Objective
Implement agent heartbeat monitoring and automatic dead-agent cleanup so that the agent registry reflects real-time online/offline status.
📁 Files to Modify
| Action |
File Path |
Description |
| Modify |
backend/src/api/app.ts |
Add heartbeat endpoint and background cleanup job |
| Modify |
backend/src/db/agents.ts |
Add updateLastSeen and markOfflineStale queries |
| Modify |
backend/src/config/index.ts |
Add heartbeat and cleanup interval config |
| Modify |
backend/.env.example |
Document new config vars |
| Modify |
frontend/src/hooks/useAgentRegistry.ts |
Auto-refresh on status change |
📁 Files to Create
| Action |
File Path |
Description |
| Create |
backend/src/api/routes/agents.ts (extend) |
Heartbeat POST endpoint |
| Create |
backend/src/services/heartbeat.ts |
Background cleanup service |
🔍 Current State
// db/agents.ts — lastSeenAt set once at registration, never updated
INSERT INTO agents (id, ..., lastSeenAt, status)
VALUES (?, ..., datetime('now'), 'online');
// status is always 'online' — never changes to 'offline'
// Frontend AgentFilterBar — status toggle exists but data is stale
const [statusFilter, setStatusFilter] = useState<'all' | 'online' | 'offline'>('all');
💥 Impact
- Agents that go offline remain marked as
online forever
- Users see stale agent availability data
- Coordinator may try to dispatch to dead agents
- No automatic cleanup of abandoned agent registrations
✅ Expected Implementation
1. Add Heartbeat Endpoint (app.ts)
// POST /api/agents/:id/heartbeat
app.post('/api/agents/:id/heartbeat', async (req, res) => {
const { id } = req.params;
const agent = agentDb.getAgent(id);
if (!agent) {
return res.status(404).json({ error: 'Agent not found' });
}
// Update lastSeenAt and ensure status is online
agentDb.updateLastSeen(id);
res.json({ status: 'ok', lastSeenAt: new Date().toISOString() });
});
2. Add Database Methods (db/agents.ts)
export function updateLastSeen(agentId: string): void {
db.prepare(`
UPDATE agents
SET lastSeenAt = datetime('now'),
status = 'online'
WHERE id = ?
`).run(agentId);
}
export function markStaleAgents(staleThresholdMinutes: number = 5): number {
const result = db.prepare(`
UPDATE agents
SET status = 'offline'
WHERE status = 'online'
AND datetime(lastSeenAt, '+' || ? || ' minutes') < datetime('now')
`).run(staleThresholdMinutes);
return result.changes;
}
export function deleteOfflineAgents(offlineThresholdHours: number = 24): number {
const result = db.prepare(`
DELETE FROM agents
WHERE status = 'offline'
AND datetime(lastSeenAt, '+' || ? || ' hours') < datetime('now')
`).run(offlineThresholdHours);
return result.changes;
}
3. Background Cleanup Service (services/heartbeat.ts)
import { markStaleAgents, deleteOfflineAgents } from '../db/agents';
const CLEANUP_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
export function startHeartbeatService() {
setInterval(() => {
const markedOffline = markStaleAgents(5); // 5 min threshold
const deleted = deleteOfflineAgents(24); // 24h threshold
if (markedOffline > 0 || deleted > 0) {
console.log(`Heartbeat cleanup: ${markedOffline} marked offline, ${deleted} deleted`);
}
}, CLEANUP_INTERVAL_MS);
}
4. Config (config/index.ts)
HEARTBEAT_INTERVAL_MS: z.coerce.number().default(300_000), // 5 min
HEARTBEAT_STALE_THRESHOLD_MINUTES: z.coerce.number().default(5),
AGENT_OFFLINE_DELETE_HOURS: z.coerce.number().default(24),
📁 Reference Files
| File Path |
Purpose |
backend/src/api/app.ts |
Add heartbeat route |
backend/src/db/agents.ts |
Add update/delete methods |
backend/src/config/index.ts |
Add config vars |
backend/.env.example |
Document config |
frontend/src/hooks/useAgentRegistry.ts |
Auto-refresh |
frontend/src/components/agents/AgentFilterBar.tsx |
Status filter UI |
✅ Acceptance Criteria
🎯 Objective
Implement agent heartbeat monitoring and automatic dead-agent cleanup so that the agent registry reflects real-time online/offline status.
📁 Files to Modify
backend/src/api/app.tsbackend/src/db/agents.tsupdateLastSeenandmarkOfflineStalequeriesbackend/src/config/index.tsbackend/.env.examplefrontend/src/hooks/useAgentRegistry.ts📁 Files to Create
backend/src/api/routes/agents.ts(extend)backend/src/services/heartbeat.ts🔍 Current State
💥 Impact
onlineforever✅ Expected Implementation
1. Add Heartbeat Endpoint (app.ts)
2. Add Database Methods (db/agents.ts)
3. Background Cleanup Service (services/heartbeat.ts)
4. Config (config/index.ts)
📁 Reference Files
backend/src/api/app.tsbackend/src/db/agents.tsbackend/src/config/index.tsbackend/.env.examplefrontend/src/hooks/useAgentRegistry.tsfrontend/src/components/agents/AgentFilterBar.tsx✅ Acceptance Criteria
POST /api/agents/:id/heartbeatendpointupdateLastSeen(agentId)todb/agents.tsmarkStaleAgents(thresholdMinutes)to mark offlinedeleteOfflineAgents(thresholdHours)for cleanupservices/heartbeat.tsbackground service.env.examplewith new vars