Scheduling Policy
The scheduling policy controls when workflows can run. Use it to limit agents to business hours, block weekend runs, freeze execution on holidays, or carve out recurring maintenance windows where everything pauses. All checks are timezone-aware via IANA tz names.
For a more expressive window-based variant with multiple per-day windows and compliance-framework mapping, see time-of-day-gating.
Rules
| Rule | Type | Default | Description |
|---|---|---|---|
allowed_hours | object | (none) | {"start": <0-23>, "end": <1-24>} -- workflow must run in [start, end) |
allowed_days | integer[] | (none) | Days of week the workflow may run. 0=Monday, 6=Sunday |
timezone | string | "UTC" | IANA timezone name (e.g. America/New_York) |
blackout_dates | string[] | [] | Specific YYYY-MM-DD dates the workflow cannot run |
maintenance_windows | object[] | [] | Recurring weekly windows -- [{"day": 6, "start": 2, "end": 6}] |
How It Works
The scheduling handler runs at before_workflow. It is cheap (a wall-clock check) and has selectivity_hint = 0.05.
| Phase | What It Checks | Actions |
|---|---|---|
before_workflow | Current time in the configured timezone against allowed_days, allowed_hours, blackout_dates, and maintenance_windows | BLOCK on any violation |
after_workflow | No-op (ALLOW) | ALLOW |
Context Attributes Read
| Attribute | Phase | Purpose |
|---|---|---|
| (none) | before_workflow | The handler reads only wall-clock time -- no context state |
The handler is purely a function of the current time. It does not inspect inputs, workflow type, or any agent state.
Example Policy
{
"name": "Business Hours Only",
"category": "scheduling",
"rules": {
"allowed_hours": {"start": 9, "end": 17},
"allowed_days": [0, 1, 2, 3, 4],
"timezone": "America/New_York",
"blackout_dates": ["2026-12-25", "2026-12-26", "2027-01-01"],
"maintenance_windows": [
{"day": 6, "start": 2, "end": 6}
]
},
"scope": {"agents": ["finance-agent"]},
"enabled": true
}
The example above: New York business hours, Mon-Fri only, blocked on Christmas/Boxing/New Year, and a recurring Sunday 2-6am maintenance window.
SDK Integration
import waxell_observe as waxell
waxell.init()
@waxell.observe(agent_name="finance-agent", enforce_policy=True)
async def reconcile(date: str) -> str:
# before_workflow: blocks if outside business hours, on weekend,
# in blackout, or in maintenance window.
return await run_reconciliation(date)
Observability
| Field | Example |
|---|---|
| Category | scheduling |
| Action | block |
| Reason | "Workflow not allowed at 20:00 (allowed: 9:00-17:00)" |
| Metadata | {"current_hour": 20, "allowed_start": 9, "allowed_end": 17} |
| Field | Example (day violation) |
|---|---|
| Reason | "Workflow not allowed on Saturday. Allowed days: Monday, Tuesday, Wednesday, Thursday, Friday" |
| Field | Example (blackout) |
|---|---|
| Reason | "Workflow blocked on blackout date: 2026-12-25" |
Common Gotchas
allowed_hours.endis exclusive.{"start": 9, "end": 17}allows runs at 9:00:00 through 16:59:59. A run at 17:00 is blocked. To allow up to and including 5pm, setend: 18.- Day numbering: 0=Monday, 6=Sunday. Not the Python
time.struct_timeconvention. The handler usesdatetime.weekday(). - Invalid timezone silently falls back to UTC. A typo in
timezone(e.g."America/New_Yokr") logs a warning and uses UTC. Test with a real tz on first deploy. blackout_datesare evaluated in the configured timezone. A blackout for"2026-12-25"blocks 25 December inAmerica/New_York, not UTC. Cross-tz tenants should set this carefully.- Maintenance windows do not span midnight. A window
{"day": 6, "start": 22, "end": 6}will not block 22:00 Sunday through 06:00 Monday --start > endmeans the window never fires. Use time-of-day-gating for overnight windows. - Only
before_workflowis enforced. A long-running workflow that starts at 16:55 and finishes at 17:10 is not killed when business hours end. Combine with Safetymax_steps/max_tool_callsfor hard runtime caps.
Next Steps
- Time-of-Day Gating -- Multiple windows, overnight windows, mid-execution enforcement
- Operations Policy -- Other operational guardrails
- Policy Categories