Skip to main content

Lights-Out Scheduling

Lights-out scheduling turns AgentXchain from a tool you invoke into a system that runs itself. You configure schedules in agentxchain.json, start the daemon, and governed runs execute on cadence without a human typing agentxchain run.

This is the narrow, repo-local first step toward the strategic end state: dark software factories where governed agent teams operate over long horizons with human oversight, not human steering.

When to use scheduling

Use scheduling when you want agents to:

  • run nightly code reviews, refactoring passes, or maintenance sweeps
  • execute governed test/QA cycles on a fixed cadence
  • process accumulated intake signals (CI failures, git changes) without waiting for a human to trigger a run
  • keep a governed project moving forward while the team sleeps

Scheduling is not a replacement for agentxchain run. It is the autonomous layer on top of it. Everything the daemon does, you could do manually — the daemon just does it on a clock.

Configuration

Schedules live in agentxchain.json under a top-level schedules object:

{
"project": "my-project",
"roles": { ... },
"workflow": { ... },
"schedules": {
"nightly_review": {
"enabled": true,
"every_minutes": 1440,
"auto_approve": true,
"max_turns": 10,
"initial_role": "qa",
"trigger_reason": "Nightly governed code review"
},
"hourly_intake_sweep": {
"enabled": true,
"every_minutes": 60,
"auto_approve": true,
"max_turns": 5,
"trigger_reason": "Process accumulated intake signals"
}
}
}
FieldDefaultDescription
enabledtrueWhether the schedule is eligible to run
every_minutesrequiredFixed interval cadence in minutes
auto_approvetrueWhether scheduled runs auto-approve gates
max_turns50Safety limit passed to the governed run
initial_roleconfig-drivenOptional first-turn role override
trigger_reasonschedule:<id>Human-readable provenance recorded in run history

You can define multiple schedules with different cadences. Each schedule is identified by its key (e.g., nightly_review, hourly_intake_sweep).

Checking schedule status

Before starting the daemon, verify your schedule configuration:

# List all configured schedules with due status
agentxchain schedule list

# Check a specific schedule
agentxchain schedule list --schedule nightly_review

# Machine-readable output
agentxchain schedule list --json

The list command shows:

  • whether each schedule is enabled
  • when it was last run
  • when it is next due
  • any skip reasons from the last evaluation

Running due schedules

You can run due schedules without starting the daemon:

# Evaluate all schedules once and run any that are due
agentxchain schedule run-due

# Run only a specific schedule if it is due
agentxchain schedule run-due --schedule nightly_review

This is useful for:

  • cron-based execution (run agentxchain schedule run-due from a system cron job)
  • CI-triggered runs (run it from a GitHub Action or other CI system)
  • manual one-off evaluation

Starting the daemon

The daemon polls for due schedules on a fixed interval and runs them automatically:

# Start with default 60-second poll interval
agentxchain schedule daemon

# Custom poll interval
agentxchain schedule daemon --poll-seconds 300

# Limit the number of poll cycles (useful for testing)
agentxchain schedule daemon --max-cycles 10

# Run only a specific schedule
agentxchain schedule daemon --schedule nightly_review

The daemon runs in the foreground. To run it in the background:

# Background with nohup
nohup agentxchain schedule daemon --poll-seconds 300 > schedule.log 2>&1 &

# Or use tmux/screen for a persistent session
tmux new-session -d -s agentxchain-daemon 'agentxchain schedule daemon --poll-seconds 300'

Daemon health monitoring

The daemon writes a heartbeat file at .agentxchain/schedule-daemon.json on every poll cycle. Check its health:

agentxchain schedule status
StatusMeaning
runningHeartbeat is recent (within poll_seconds * 3 or 30 seconds, whichever is greater)
staleHeartbeat file exists but is older than the staleness threshold
not_runningState file exists but is malformed or missing heartbeat data
never_startedNo daemon state file found

For automation:

agentxchain schedule status --json

Returns pid, started_at, last_heartbeat_at, last_cycle_result, poll_seconds, and stale_after_seconds.

The doctor command also checks daemon health when schedules are configured:

agentxchain doctor

Safety behavior

Scheduled runs follow strict safety rules:

  1. No double-runs. If the project is already active or paused, the scheduler records a skip reason and moves on. It does not start a second concurrent run.

  2. No hijacking. If a run is blocked (waiting for operator recovery), the scheduler does not auto-recover it. A human must explicitly recover blocked runs.

  3. Start from clean state only. Scheduled runs start only from a fresh repo with no run state yet, or from idle / completed status.

  4. Provenance tracking. Scheduled runs use trigger: "schedule" in run history, so you can always distinguish scheduled runs from manual ones.

  5. Budget enforcement. If budget.on_limit is pause_and_escalate, a scheduled run that exhausts its budget will block and escalate — the daemon will skip it on subsequent cycles until an operator intervenes. If budget.on_limit is warn, the run continues past budget with observable warnings.

Combining with intake

Scheduling pairs naturally with the continuous delivery intake surface. A common pattern:

  1. Intake records signals continuously — CI failures, git ref changes, manual records
  2. A scheduled run processes accumulated intents — the initial role triages, plans, and executes work from the intake backlog
  3. The daemon ensures this happens on cadence — no human needs to remember to run it

Example configuration:

{
"schedules": {
"process_intake": {
"enabled": true,
"every_minutes": 120,
"auto_approve": true,
"max_turns": 15,
"initial_role": "pm",
"trigger_reason": "Process intake backlog every 2 hours"
}
}
}

Multi-repo boundary

This scheduling surface is repo-local only. It runs inside a governed project rooted by agentxchain.json. It does not run from a coordinator workspace rooted by agentxchain-multi.json, and it does not fan out across child repos for you.

If you need multi-repo automation today, schedule each child governed repo independently, then reconcile coordinator state separately with agentxchain multi step.

See Multi-Repo Orchestration for the coordinator surface. Do not treat schedule daemon as a coordinator scheduler. That capability does not ship today.

Monitoring scheduled runs

After the daemon runs governed cycles, inspect the results:

# See run history including scheduled runs
agentxchain history

# Filter for schedule-triggered runs
agentxchain events --json | grep '"trigger":"schedule"'

# Compare two scheduled runs
agentxchain diff <run_id_1> <run_id_2>

Operational patterns

Nightly code review

{
"schedules": {
"nightly_review": {
"every_minutes": 1440,
"initial_role": "qa",
"max_turns": 8,
"trigger_reason": "Nightly code quality review"
}
}
}

Hourly CI failure triage

{
"schedules": {
"ci_triage": {
"every_minutes": 60,
"initial_role": "pm",
"max_turns": 5,
"trigger_reason": "Triage CI failures from intake"
}
}
}

Weekly maintenance sweep

{
"schedules": {
"weekly_maintenance": {
"every_minutes": 10080,
"initial_role": "dev",
"max_turns": 20,
"trigger_reason": "Weekly dependency updates and cleanup"
}
}
}

What this is not

Scheduling is repo-local and daemon-based. It is not:

  • a hosted orchestration service (that is the future .ai surface)
  • a distributed job queue
  • a coordinator-workspace scheduler
  • a replacement for CI/CD pipelines
  • an auto-recovery mechanism for blocked runs

It is the simplest possible path from "I run agentxchain run manually" to "AgentXchain runs governed cycles on its own." Everything more sophisticated belongs in the managed cloud layer.