diff --git a/README.md b/README.md index ce4e186..03f8ab2 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Claude Code as a model provider without an API key. | OpenAI-compatible provider | `extensions/Volcanic.AgenticCore.Extensions.OpenAI` | OpenAI, OpenRouter, Groq, Ollama, llama.cpp, vLLM | | Claude Code (subscription) provider | `extensions/Volcanic.AgenticCore.Extensions.ClaudeCode` (+ `.Bridge`) | Spawns `claude -p`, MCP "proposal" bridge | | Google Calendar (tool + connect commands) | `extensions/Volcanic.AgenticCore.Extensions.GoogleCalendar` | `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`; one account per chat | +| Scheduler (reminders, scheduled prompts, watcher scripts) | `extensions/Volcanic.AgenticCore.Extensions.Scheduler` | Cronos; per-chat jobs in `/scheduler/jobs.json`; see [docs/telegram-bot.md](docs/telegram-bot.md#scheduling) | | Telegram bot | `hosts/Volcanic.AgenticCore.Telegram` | Chat with the agent from Telegram; long polling, Claude Code, allow-list | | Reference headless host | `samples/Volcanic.AgenticCore.Sample.Headless` | Prompt in, JSON events out | | Tests | `tests/` | xunit; no test calls a paid API | diff --git a/docs/superpowers/specs/2026-09-26-scheduler-design.md b/docs/superpowers/specs/2026-09-26-scheduler-design.md index 240fb18..4f4630d 100644 --- a/docs/superpowers/specs/2026-09-26-scheduler-design.md +++ b/docs/superpowers/specs/2026-09-26-scheduler-design.md @@ -61,7 +61,10 @@ same chat. - **Scheduled agent prompts are queued as follow-ups, never as steering.** When the chat is idle a prompt job starts a run. When a run is active (a user request, or another job), the prompt goes in with `StreamingBehavior.FollowUp`: the current work finishes first, then the job's prompt is handled in the same run. A clock-driven prompt shouldn't - redirect what the user is doing mid-turn. User messages keep steering as they do today. + redirect what the user is doing mid-turn. User messages keep steering as they do today. This also holds when a run + starts between `PromptAsync`'s idle check and its run gate: the core's `StartRunAsync` gets the caller's + `StreamingBehavior`, and a `FollowUp` prompt joins the active run as a follow-up (with a `QueueUpdate`), not as + steering. - **Cron parsing uses Cronos** (`Cronos` on NuGet, Hangfire, MIT, no dependencies). It parses standard 5-field expressions and macros (`@daily`, `@hourly`, …). `GetNextOccurrence(DateTimeOffset, TimeZoneInfo)` works in a given zone and has defined DST semantics: a time skipped when clocks go forward fires at the transition, and an ambiguous @@ -72,7 +75,10 @@ same chat. sets a 1-minute floor for watchers. - **Each chat has its own time zone.** It applies to cron, to displayed times, to the session's system prompt, to the local-time header on each prompt, and to the `TZ` of the chat's `bash`, watcher and `claude -p` processes (§8). An `at` without an offset is read in the chat's zone, because - models often leave the offset out. An `at` with an offset is used as given. The zone is a chat setting, not a + models often leave the offset out. An `at` with an offset is used as given. The date is required and only ISO 8601 is + accepted (`yyyy-MM-dd`, or `yyyy-MM-dd[T| ]HH:mm[:ss[.fff]]` with an optional `Z`/offset): a bare `09:00` or a culture + format such as `09/10/2026` is rejected with a readable error, because it would be resolved against the machine's + clock rather than the chat's. The zone is a chat setting, not a scheduler setting, because the system prompt and `bash` need it with the scheduler disabled too: - **Stored by the host**, in a small per-chat settings store outside every workspace: `/telegram/chat-settings.json` (§7). Not in `jobs.json` (the scheduler can be off) and not in the session @@ -93,7 +99,9 @@ same chat. fires immediately. If it's more than 60 s late, direct text gets `(due