v1.3.8

Scheduler & AI Automation

Last updated


This page covers automated scheduling and how to recover a scheduler skill after a bad edit.

Scheduler skills (isolated namespace)


Scheduler-triggered skills live in a separate tree, not scanned by agents.Scanner():
  1. ~/.config/agenvoy/skills/scheduler/<short>-<hash8>/SKILL.md

AspectRegular skillScheduler skill
Path~/.config/agenvoy/skills/<name>/SKILL.md~/.config/agenvoy/skills/scheduler/<short>-<hash8>/SKILL.md
Frontmatter name<name><short>-<hash8> (no scheduler- prefix)
/<name> autocompletionyesno — surfaced as /sched-<name> (warn-purple) at the bottom of the picker
Triggerruntime.MatchSkill (in exec.Prepare) then a synthesized run_skill(a) cron / one-shot fire from daemon runtime.SetRunner, (b) manual /sched-<name> or /schedule from TUI

Creation flow


The scheduler-skill-creator skill is the canonical entry for new schedules. It:
  1. Pre-flight gate (Step 0): if the user message lacks a time token (+5m / HH:MM / etc.) or task token, it must call ask_user first — no defaulting to +10m, no inferring "probably 9am". When both are missing they go out as two questions in one ask_user call rather than one round each.
  2. Runs python3 ~/.config/agenvoy/skills/.system/scheduler-skill-creator/scripts/init_scheduler_skill.py <short> to create the skill dir with hash suffix. The path is absolute on purpose: run_command runs in the user's work directory, not the skill directory, so a relative scripts/... never resolves.
  3. Delegates the body to /skill-creator (its "edit an existing skill" path) instead of patching the SKILL.md inline. The directory and name are already fixed by step 2, so this step only fills in content.
  4. Calls schedules(mode=write) to bind the schedule.

Direct schedules(mode=patch) calls are allowed only for rebinding existing schedules (changing the time of an already-created scheduler skill). mode=write is internal to the creator flow — its skill_name carries a generated hash suffix, so a hand-made one always fails.

Manual execution (/sched-<name>)


The TUI command picker lists each directory under scheduler/ whose cron or one-shot entry is bound to the current session as /sched-<name>. Selecting one reads the body and dispatches it to the current agent with a preamble that blocks weaker models from misreading the SKILL.md-shaped body as a schedule-creation request and re-running the creator. /schedule lists every cron and one-shot entry in one popup: enter fires the selected one through this same path, d deletes it; adding or editing a schedule is done by asking the agent (the former /cron and /task commands were removed). Since v1.2.0 the TUI sends this run to the daemon over its Unix socket, like any other input; while the TUI shows Connecting it is not sent.
The preamble enforces:
  • Execute the existing scheduler skill immediately and output results
  • Do not activate scheduler-skill-creator
  • Do not run init_scheduler_skill.py
  • Do not call schedules(mode=write)

Daemon fire


The daemon calls runtime.SetRunner(app.RunSkill), where app.RunSkill(ctx, sessionID, skillName) is the runner. When the scheduler fires (cron tick or one-shot deadline), the runner:
  1. Reads body via skill.GetSchedule(skillName).
  2. Ensures the session directory and its SQLite row exist.
  3. Runs the body through exec/subagent.Exec — an in-process run in its top-level mode, so it keeps the full tool set except edit_tool, test_tool, edit_skill, schedules and store_secret, and runs as allow-all, not limited to the working directory.

One-shot tasks are removed and the skill dir is trashed after a successful fire.

Recovering from a bad edit


Automatic post-run skill rewriting was removed — a failed run no longer edits the skill behind your back. Recovery runs on the file-level snapshot layer: every change the tools make to a file is recorded, so recovery is explicit:
StepTool
Inspect the recorded versions of a skill or tool filefile_history(mode=list)
Diff the newest recorded version against what is on diskfile_history(mode=read)
Put one version backedit_file(mode=restore, version=...)
Undo everything one task changededit_file(mode=restore, task_id=...)

A removed skill lands in .Trash/ and stays recoverable from there.
中文