Daemon Mode
Daemon mode runs Heartbit as a persistent service with task management, event streaming, and interactive channels.
Overview
Section titled “Overview”- Kafka consumer loop processes
DaemonCommandmessages - Axum HTTP API — submit, list, and cancel tasks; stream events via SSE
- Cron scheduler — 6-field cron expressions for recurring tasks
- Heartbeat pulse — periodic awareness loop that reads
HEARTBIT.mdstanding orders, checks todos, submits tasks with idle backoff - Bounded concurrency —
max_concurrent_taskslimits parallel agent runs - WebSocket + Telegram — interactive channels via
InteractionBridge - Multi-tenant isolation — JWT/JWKS authentication extracts
UserContextper request - A2A Agent Card —
GET /.well-known/agent.jsonfor agent discovery
Quick Start
Section titled “Quick Start”# Start Kafkadocker compose up kafka -d
# Run the daemonheartbit daemon --config heartbit.toml
# Submit a task (with bearer token auth)curl -X POST http://localhost:3000/tasks \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer $YOUR_API_KEY' \ -d '{"task":"Analyze the codebase"}'
# Submit a task (with JWT auth)curl -X POST http://localhost:3000/tasks \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer <jwt-token>' \ -d '{"task":"Analyze the codebase"}'
# List taskscurl http://localhost:3000/tasks \ -H 'Authorization: Bearer $YOUR_API_KEY'
# Stream events (SSE)curl -N http://localhost:3000/tasks/<id>/events
# Agent discoverycurl http://localhost:3000/.well-known/agent.json
# Cancel a taskcurl -X DELETE http://localhost:3000/tasks/<id>Configuration
Section titled “Configuration”[daemon]bind = "127.0.0.1:3000"max_concurrent_tasks = 4
[daemon.kafka]brokers = "localhost:9092"consumer_group = "heartbit-daemon"commands_topic = "heartbit.commands"events_topic = "heartbit.events"
[[daemon.schedules]]name = "daily-review"cron = "0 0 9 * * *" # 6-field cron (sec min hr dom mon dow)task = "Review yesterday's work"Authentication
Section titled “Authentication”The daemon supports two auth modes (both can be active simultaneously):
| Mode | Config key | How it works |
|---|---|---|
| Bearer tokens | daemon.auth.bearer_tokens | Static API keys; supports multiple tokens for rotation |
| JWT/JWKS | daemon.auth.jwks_url | RS256 tokens verified against a JWKS endpoint; extracts UserContext |
[daemon.auth]bearer_tokens = ["$YOUR_API_KEY"]jwks_url = "https://idp.example.com/.well-known/jwks.json"issuer = "https://idp.example.com"audience = "heartbit-daemon"user_id_claim = "sub"tenant_id_claim = "tid"roles_claim = "roles"When JWT auth is configured, authenticated requests carry a UserContext through the entire lifecycle:
- Memory — wrapped with
NamespacedMemoryusingtenant:{tid}:user:{uid}prefix - Workspace — scoped to
{base}/{tenant_id}/{user_id}/ - Tasks — filtered by authenticated tenant
- Audit — records include
user_id,tenant_id, anddelegation_chain
See the Multi-Tenant guide for full details on multi-tenant setup.
Dynamic MCP Authentication
Section titled “Dynamic MCP Authentication”For multi-tenant MCP server access, the AuthProvider trait enables per-user token injection:
StaticAuthProvider— returns the same auth header for all users (backward-compatible)TokenExchangeAuthProvider— implements RFC 8693 token exchange against an IdP, caching per-user tokens
See the MCP Servers guide for configuration details.
Cron Scheduling
Section titled “Cron Scheduling”Define recurring tasks with 6-field cron expressions (second, minute, hour, day-of-month, month, day-of-week):
[[daemon.schedules]]name = "daily-review"cron = "0 0 9 * * *" # Every day at 9:00 AMtask = "Review yesterday's work and summarize findings"
[[daemon.schedules]]name = "hourly-check"cron = "0 0 * * * *" # Every hourtask = "Check for new issues in the bug tracker"A2A Agent Card
Section titled “A2A Agent Card”The daemon serves an Agent-to-Agent discovery endpoint at GET /.well-known/agent.json. The card includes agent name, description, skills (from config agents), auth schemes, and endpoint URL.