一键导入
ax-provider-scheduler
Use when modifying scheduler providers — cron jobs, heartbeats, proactive hints, or active hours in src/providers/scheduler/
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when modifying scheduler providers — cron jobs, heartbeats, proactive hints, or active hours in src/providers/scheduler/
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when modifying logging, error handling, or diagnostic messages — logger setup, transports, error diagnosis patterns in src/logger.ts and src/errors.ts
Use when modifying the trusted host process — server orchestration, message routing, IPC handler, request lifecycle, event streaming, file handling, plugin loading, or agent delegation in src/host/
Use when modifying the sandboxed agent process — runner, IPC client, local/IPC tools, tool catalog, prompt building, or identity loading in src/agent/
Use when modifying agent sandbox isolation -- Docker, Apple Container (macOS), or k8s providers in src/providers/sandbox/
Use when modifying IPC protocol between host and agent — schemas, actions, length-prefix framing, or Zod validation in ipc-schemas.ts and ipc-server.ts
AX project architecture and coding skills - use sub-skills for specific subsystems (agent, host, cli, providers, etc.)
| name | ax-provider-scheduler |
| description | Use when modifying scheduler providers — cron jobs, heartbeats, proactive hints, or active hours in src/providers/scheduler/ |
The scheduler provider fires timed messages (heartbeats, cron jobs) into the host message pipeline. It runs host-side only and delivers InboundMessage objects via the onMessage callback registered during start().
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | yes | Unique job identifier |
schedule | string | yes | Standard 5-field cron expr |
agentId | string | yes | Target agent |
prompt | string | yes | Message content sent on trigger |
maxTokenBudget | number | no | Per-job token cap |
| Method | Required | Description |
|---|---|---|
start(onMessage) | yes | Begin timers; register message callback |
stop() | yes | Clear all timers; release resources |
addCron(job) | no | Register a cron job |
removeCron(jobId) | no | Remove a cron job by ID |
listJobs() | no | Return all registered CronJobDef entries |
checkCronNow(at?) | no | Manually trigger cron evaluation (testing) |
recordTokenUsage(n) | no | Feed token count for budget tracking |
listPendingHints() | no | Return hints queued when budget exceeded |
| Provider | File | Timers | Cron | Active Hours | Notes |
|---|---|---|---|---|---|
plainjob | plainjob.ts | yes | yes | yes | Persistent job queue (Kysely DB) with one-shot support |
none | none.ts | no | no | no | No-op; all stubs |
src/providers/scheduler/plainjob.tsscheduleOnce(datetime, prompt) for future-dated single-execution jobsconfig.scheduler.defaultDeliveryagentIdPlainJobSchedulerDeps: accepts optional jobStore (testing), database (shared DatabaseProvider), eventbus, and documents (DocumentStore for HEARTBEAT.md)jobStore for testing, (2) KyselyJobStore with shared DatabaseProvider, (3) standalone SQLite at ~/.ax/data/scheduler.db'scheduler_migration' (prevents collision with storage, cortex, etc.)config.scheduler.heartbeat_interval_min minutes. Reads HEARTBEAT.md from DocumentStore (documents.get('identity', '{agentName}/HEARTBEAT.md')). Suppressed outside active hours.matchesCron() from utils.ts (standard 5-field: min hour dom month dow). Suppressed outside active hours. Filtered by agentName (multi-agent safe).config.scheduler.active_hours.{start,end,timezone}. Uses toLocaleTimeString with the configured timezone. Both heartbeats and cron jobs are gated.schedulerSession(sender) which sets provider: 'scheduler', scope: 'dm'.scheduleOnce(datetime, prompt) for future-dated single-execution jobs via setRunAt(). Rehydrated on startup via listWithRunAt().addCron, removeCron, listJobs, scheduleOnce are all async — they await the underlying KyselyJobStore operations.Prevents duplicate job firing across multiple host replicas:
tryClaim(jobId, minuteKey): Atomic CAS on last_fired_at column — only the replica that wins the UPDATE fires the jobUPDATE...RETURNING semantics__heartbeat__:{agentName} row created on startup for distributed heartbeat dedup. Filtered from listJobs() results.MemoryJobStore uses lastFiredMinute Map (tests only)Prevents overlapping executions when a job takes longer than its interval:
inFlight: Set<string> tracks currently executing jobsif (inFlight.has(jobId)) continueinFlight.add() happens before any async operations (prevents race with rapid heartbeats).finally() on the handler Promiseplainjob.ts, gate it with isWithinActiveHours(), fire via onMessageHandler().checkCronNow(at) to inject a specific Date without waiting for the 60s interval.markRun(). Anything requiring agent execution must go through the message pipeline.isWithinActiveHours() uses toLocaleTimeString with the configured timezone string. Invalid timezones throw at runtime, not at config parse time.matchesCron() calls date.getMinutes(), date.getHours(), etc., which use the host machine's local time -- not the configured timezone. Only the active-hours gate is timezone-aware.tryClaim(): Both cron jobs and heartbeats use tryClaim(jobId, minuteKey) for distributed dedup. Only the winning replica fires.inFlight.add() must happen before documents.get() to prevent duplicate heartbeats when two rapid calls both pass the check.readFileSync() from config.scheduler.agent_dir.src/migrations/jobs.ts: jobs_001_initial (core schema), jobs_002_last_fired_at (dedup column), jobs_003_creator_session_id (workspace sharing).checkCronJobs() filters by agentName via jobs.list(agentName). Each host fires only its own agent's jobs.