Phase 2: Heartbeat & Autonomous Daemon
This phase adds scheduled autonomous behavior to AgenC agents. The Heartbeat system allows agents to wake up on a schedule (cron-like) and perform actions witho
Phase 2: Heartbeat & Autonomous Daemon
Overview
This phase adds scheduled autonomous behavior to AgenC agents. The Heartbeat system allows agents to wake up on a schedule (cron-like) and perform actions without user input. The Daemon subsystem provides production-ready process management with PID files, signal handling, systemd integration, and crash recovery.
What this enables:
Dependencies
Phase 1: Gateway & Channel Foundation
Gateway for sending autonomous messagesChannelPlugin to deliver heartbeat resultsSession for maintaining autonomous conversation threadsExisting runtime infrastructure:
TaskScanner from runtime/src/autonomous/scanner.tsTaskDiscovery from runtime/src/task/discovery.tsruntime/src/bin/cli.tsIssue Dependency Graph
Implementation Order
- 1081 β Heartbeat scheduler (M)
- Core scheduler, action dispatch, quiet heartbeat contract
- 1084 β Built-in heartbeat actions (M)
- Task scan, daily summary, portfolio monitor
- 1085 β Cron-like scheduling (S)
- Per-action cron expressions
- 1078 β Daemon lifecycle (M)
- PID file, signal handling, systemd service, crash recovery
Rationale: Scheduler β actions β cron β daemon. Basic scheduler first, then actions to test it, then flexible scheduling, finally production hardening.
Issue Details
2.1: Heartbeat scheduler (#1081)
Goal: Create a scheduler that runs heartbeat actions on intervals.
Files to create:
gateway/src/heartbeat/scheduler.ts β HeartbeatScheduler classgateway/src/heartbeat/types.ts β HeartbeatAction, HeartbeatContext, HeartbeatResultgateway/src/heartbeat/index.tsgateway/src/heartbeat/scheduler.test.tsFiles to modify:
gateway/src/gateway.ts β integrate HeartbeatSchedulergateway/src/index.ts β export heartbeat typesIntegration points:
Patterns to follow:
runtime/src/utils/logger.tsKey interfaces:
interface HeartbeatAction {
readonly name: string;
readonly description: string;
execute(context: HeartbeatContext): PromiseHeartbeatResult>;
}
interface HeartbeatContext {
gateway: Gateway;
runtime: AgentRuntime;
session: Session;
logger: Logger;
}
interface HeartbeatResult {
shouldNotify: boolean;
message?: string;
metadata?: Recordstring, unknown>;
}
interface HeartbeatScheduler {
registerAction(action: HeartbeatAction, intervalMs: number): void;
start(): Promisevoid>;
stop(): Promisevoid>;
}Testing strategy:
Estimated scope: M (400-500 lines)
2.2: Built-in heartbeat actions (task scan, summary, portfolio) (#1084)
Goal: Implement three core heartbeat actions.
Files to create:
gateway/src/heartbeat/actions/task-scan.ts β TaskScanActiongateway/src/heartbeat/actions/daily-summary.ts β DailySummaryActiongateway/src/heartbeat/actions/portfolio-monitor.ts β PortfolioMonitorActiongateway/src/heartbeat/actions/index.tsgateway/src/heartbeat/actions/task-scan.test.tsgateway/src/heartbeat/actions/daily-summary.test.tsgateway/src/heartbeat/actions/portfolio-monitor.test.tsFiles to modify:
gateway/src/gateway.ts β register built-in actions by defaultgateway/src/heartbeat/index.ts β export actionsIntegration points:
TaskScanner from runtime/src/autonomous/scanner.ts to find claimable tasks- Quiet heartbeat: only notify if new tasks found
- Message: "Found {count} new tasks matching your capabilities"
- Quiet heartbeat: always send (once per day)
- Message: "Daily summary: {completions} tasks completed, {earnings} earned"
- Quiet heartbeat: only notify if alerts found
- Message: "Alert: Task #{id} deadline in 2 hours"
Patterns to follow:
TaskScanner classTaskOperations for queriesDisputeOperations for dispute checksruntime/src/types/errors.tsKey interfaces:
class TaskScanAction implements HeartbeatAction {
readonly name = 'task-scan';
readonly description = 'Scan for new claimable tasks';
// implementation
}
class DailySummaryAction implements HeartbeatAction {
readonly name = 'daily-summary';
readonly description = 'Generate daily activity summary';
// implementation
}
class PortfolioMonitorAction implements HeartbeatAction {
readonly name = 'portfolio-monitor';
readonly description = 'Monitor active tasks for alerts';
// implementation
}Testing strategy:
Estimated scope: M (500-700 lines total across 3 actions)
2.3: Cron-like scheduling with per-action schedules (#1085)
Goal: Replace fixed intervals with cron expressions for flexible scheduling.
Files to create:
gateway/src/heartbeat/cron-scheduler.ts β CronScheduler classgateway/src/heartbeat/cron-parser.ts β Cron expression parsergateway/src/heartbeat/cron-scheduler.test.tsFiles to modify:
gateway/src/heartbeat/scheduler.ts β integrate CronSchedulergateway/src/heartbeat/types.ts β add schedule field to action registrationIntegration points:
node-cron or similar library for parsing - TaskScanAction: */5 * * * * (every 5 minutes)
- DailySummaryAction: 0 9 * * * (9 AM daily)
- PortfolioMonitorAction: 0 * * * * (hourly)
Patterns to follow:
ensureLazyModule()Key interfaces:
interface CronScheduler {
schedule(action: HeartbeatAction, cronExpr: string): void;
unschedule(actionName: string): void;
start(): Promisevoid>;
stop(): Promisevoid>;
}
interface CronExpression {
minute: string;
hour: string;
dayOfMonth: string;
month: string;
dayOfWeek: string;
}Testing strategy:
Estimated scope: S (250-350 lines)
2.4: Daemon lifecycle (PID, signals, systemd, crash recovery) (#1078)
Goal: Production-ready daemon management with process supervision.
Files to create:
gateway/src/daemon/manager.ts β DaemonManager classgateway/src/daemon/pidfile.ts β PID file managementgateway/src/daemon/signals.ts β Signal handlersgateway/src/daemon/recovery.ts β Crash recovery logicgateway/src/daemon/systemd.ts β Systemd service generatorgateway/src/daemon/index.tsgateway/src/daemon/manager.test.tsscripts/install-systemd-service.sh β Systemd install scriptFiles to modify:
gateway/src/bin/cli.ts β add daemon commands (start, stop, restart, status)gateway/src/gateway.ts β integrate signal handlersIntegration points:
~/.agenc/gateway.pid - SIGTERM β graceful shutdown (stop gateway, save state, exit)
- SIGHUP β reload config (re-read ~/.agenc/gateway.json)
- SIGINT β graceful shutdown (same as SIGTERM)
- Type=simple
- Restart=on-failure
- RestartSec=10s
- WatchdogSec=60s
Patterns to follow:
runtime/src/connection/manager.tsKey interfaces:
interface DaemonManager {
start(): Promisevoid>;
stop(): Promisevoid>;
restart(): Promisevoid>;
status(): DaemonStatus;
setupSignalHandlers(): void;
}
interface DaemonStatus {
running: boolean;
pid?: number;
uptime?: number;
lastCrash?: number;
}
interface PidFile {
write(pid: number): Promisevoid>;
read(): Promisenumber | null>;
remove(): Promisevoid>;
exists(): Promiseboolean>;
}Testing strategy:
Estimated scope: M (500-700 lines)
Integration Checklist
After completing all issues:
Configuration Example
{
"heartbeat": {
"enabled": true,
"actions": [
{
"name": "task-scan",
"schedule": "*/5 * * * *",
"config": {
"minReward": 100000000,
"capabilities": 3
}
},
{
"name": "daily-summary",
"schedule": "0 9 * * *"
},
{
"name": "portfolio-monitor",
"schedule": "0 * * * *"
}
]
},
"daemon": {
"pidFile": "~/.agenc/gateway.pid",
"watchdogInterval": 60000
}
}Systemd Service Template
[Unit]
Description=AgenC Gateway Daemon
After=network.target
[Service]
Type=simple
User=%i
ExecStart=/usr/bin/node /path/to/gateway/dist/bin/cli.js daemon start
Restart=on-failure
RestartSec=10s
WatchdogSec=60s
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target