Skip to content

feat: boot timing + dynamic imports for lean daemon mode#966

Open
mistercrunch wants to merge 1 commit into
mainfrom
daemon-lean-boot
Open

feat: boot timing + dynamic imports for lean daemon mode#966
mistercrunch wants to merge 1 commit into
mainfrom
daemon-lean-boot

Conversation

@mistercrunch
Copy link
Copy Markdown
Member

@mistercrunch mistercrunch commented Apr 12, 2026

Summary

  • Boot timing instrumentation: Added performance.now() timing to every major boot phase in startDaemon() and startup() — config load, service tier resolution, DB init, registerServices, registerHooks, registerRoutes, plus sub-step timing for orphan cleanup, health monitor, master secret, app.listen, scheduler init, gateway init, and total boot time. All logged with ⏱️ [boot] prefix for easy grep.

  • Dynamic imports for 10+ conditionally-loaded services: Converted top-level import statements to await import() gated on svcEnabled() for: SchedulerService, TerminalsService, gateway (4 modules), boards (3 modules), cards (2 modules), artifacts, leaderboard, and MCP servers. When disabled via config, these modules are never loaded — zero overhead.

  • Lean mode preset docs + example config: Added documentation to DaemonServicesConfig describing the recommended lean/headless preset, and included config-lean.example.yaml with the minimal config for k8s deployments.

What each gated service does and its boot cost

Service What it does Boot cost
scheduler Cron-based session spawning — timer loop + DB polling every 30s Module load + timer setup
terminals Web terminal via xterm.js — node-pty native bindings Native module load (node-pty)
gateway Slack/Discord/GitHub integrations — Socket Mode listeners, channel cache SDK load + channel state refresh + listener startup
boards Spatial canvas boards, board-objects, board-comments 3 service registrations, DB repos
cards Kanban cards + card type definitions 2 service registrations
artifacts Sandpack artifact previews — bundler detection Service + filesystem probe
file_browser File/context browsing endpoints 3 service registrations
leaderboard Usage analytics / cost tracking DB aggregation queries
mcp_servers MCP server configuration + OAuth Complex OAuth setup, token cache
static_files UI static file serving Express static middleware

Lean mode config gains

With config-lean.example.yaml, the daemon skips:

  • 8 service groups (scheduler, terminals, gateway, boards, cards, artifacts, file_browser, leaderboard) + static files
  • ~15 module loads that would otherwise happen at import time
  • 0 background timers (no scheduler tick, no gateway listeners)
  • 0 native bindings (no node-pty)

Essential services preserved: core (sessions/tasks/messages), worktrees, repos, users, mcp_servers.

Boot timing output format

⏱️  [boot] Handlebars helpers: 2ms
⏱️  [boot] Config load: 15ms
⏱️  [boot] Service tier resolution: 1ms
⏱️  [boot] Database init: 89ms
⏱️  [boot] Phase 1 — registerServices: 234ms
⏱️  [boot] Phase 2 — registerHooks: 12ms
⏱️  [boot] Phase 3 — registerRoutes: 45ms
⏱️  [boot]   cleanupOrphans: 28ms
⏱️  [boot]   createHealthMonitor: 3ms
⏱️  [boot]   ensureMasterSecret: 5ms
⏱️  [boot]   app.listen: 18ms
⏱️  [boot]   scheduler init: 4ms
⏱️  [boot]   gateway init (async): 156ms
⏱️  [boot] Phase 4 — startup: 312ms
⏱️  [boot] Total boot time: 791ms

Test plan

  • pnpm check passes (typecheck + lint + build)
  • Run daemon with full config — verify all timing lines appear
  • Run daemon with config-lean.example.yaml — verify disabled services are not imported
  • Verify no regression in service registration (all endpoints respond)

🤖 Generated with Claude Code

… mode

Add performance.now() timing to every major boot phase (config load, DB init,
registerServices, registerHooks, registerRoutes, startup sub-steps) so we can
identify what's slow.

Convert 10 conditionally-registered services from top-level imports to dynamic
await import() gated on svcEnabled(): SchedulerService, TerminalsService,
gateway (4 modules), boards (3 modules), cards (2 modules), artifacts,
leaderboard, and MCP servers. When these services are disabled via config,
their modules are never loaded — zero overhead in lean mode.

Add lean/headless preset documentation to DaemonServicesConfig and include
config-lean.example.yaml with the recommended minimal config for k8s.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant