Add reminder run command - #2239
Open
Aaronontheweb wants to merge 9 commits into
Open
Aaronontheweb wants to merge 9 commits into
Aaronontheweb wants to merge 9 commits into
Conversation
A reminder now supports a manual run, separate from its schedule. RunReminderNowCommand asks for Operator authority and starts the reminder now, outside its normal fire time. Each execution now carries a source: scheduled or manual. History records the source. A manual run has no Akka.Reminders envelope, so the tracker and execution actor carry no envelope for it, and settlement skips Ack/Nack, schedule changes, and the scheduled consecutive-failure count. A manual run rejects fast when the reminder is missing, disabled, expired, already active, or scheduling is off. It does not queue.
POST /api/reminders/{id}/run starts a reminder now. It uses the same
Operator authority gate as reminder create. A non-Operator caller
gets a 403.
The endpoint maps manager rejections to matching HTTP codes: 404 for
a missing reminder, 409 when it already runs, and 400 for other
rejections such as disabled or expired.
netclaw reminder run <id> calls the new daemon endpoint and starts a reminder now. An unknown id fails with a clear message and a non-zero exit. A daemon that is not running fails with the same error style as the other reminder subcommands. reminder history and reminder status now show each run's source, manual or scheduled, in a new column. This commit also fixes a pre-existing format bug on the history table's fired_at column: the alignment spec sat after the format specifier, so it printed as part of the date format instead of padding the column.
Add a Manual run section to the scheduling reference: the command, what it does and does not change, and when the agent should (and should not) offer it in conversation. Bump the netclaw-operations skill version.
The manager now sends an accept ack for a run request, then waits for the run to settle before it replies again. The wait has a bound: the execution timeout plus a settlement margin. The execution actor now reports the final reply text to the manager. The reminder channel now subscribes to both Text and TextStreaming output. A provider that sends the whole reply in one chunk, with no streaming deltas, used to leave the reply text empty. A manual run keeps its prior guarantees: it does not touch the schedule, and it does not count toward scheduled failure accounting.
POST /api/reminders/{id}/run now makes two calls to the manager: an
accept ack, then a wait for the run to settle. The response carries
the reminder id, status, start time, duration, session id, delivery
target, the reply text, and the error message on failure.
On timeout, the endpoint returns a clear "still running" result with
the session id. It does not cancel the run.
The existing rejections keep their exact codes and messages: not
Operator, scheduling disabled, not found, disabled, expired, and
already executing.
`netclaw reminder run <id>` now waits for the daemon and prints the result: status, duration, session, delivery target, and the reply or the error. It prints the `netclaw chat --resume <id>` line so the operator can open the session. Exit code is 0 for an ok run, and non-zero for a failed or timed-out run. `--json` prints the result as a JSON object. The CLI's HTTP client timeout for this call now exceeds the daemon's own wait, so the CLI does not give up before the daemon replies.
Update the Manual run section: the result block, how to read each field, the exit codes, and the timeout case. Add a subsection on testing a reminder inside a session: an agent can call set_reminder with a short one-shot schedule and delivery kind current_session, and the reminder fires back into the same conversation. Bump the netclaw-operations skill version.
This was referenced Sep 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
netclaw reminder run <id>. This command lets an operator run anexisting reminder now, so they can test it without a wait for its
schedule. It waits for the run to finish and prints the result.
POST /api/reminders/{id}/runuses the same Operator-only authoritygate as reminder create (
ResolveReminderAuthorizationContext/PrincipalClassification.Operator). A non-Operator caller gets a403.
target, through the same execution path a scheduled run uses.
reminder id, source (
manual), status (ok/failed/timed_out), start time, duration, session id, delivery target (ornone), the session's final assistant reply text (trimmed to asane length, with a flag when it trimmed), and the error message on
failure.
(
ReminderExecutionActor.ExecutionAttemptTimeout, one hour) plus asettlement margin. If the run has not settled by then, the endpoint
returns a
timed_outresult with the session id. It does notcancel the run.
delivery, reply or error) and the exact
netclaw chat --resume <id>line to open the session. Exit code is 0 for
ok, non-zero forfailedortimed_out.--jsonprints the result object. TheCLI's HTTP client timeout for this call exceeds the daemon's own
wait.
ReminderExecutionActorsubscribedonly to
OutputFilter.TextStreaming. A provider that returns itswhole reply in one chunk, with no incremental deltas, never filled
the reply text. It now subscribes to both
TextandTextStreaming;ExecutionOutputAccumulator's existing guardagainst double counting keeps a provider that streams both correct.
its original fire time. An interval or cron reminder keeps its next
fire time.
netclaw reminder history <id>andnetclaw reminder status <id>show it in a new column.
consecutive-failure limit (auto-disable).
error. It does not queue, and it does not reintroduce the global
concurrency cap that fix(reminders): remove execution cap so reminders never skip on capacity #1839 removed.
netclaw-operationsskill's scheduling reference: theManual run section now covers the result block, how to read each
field, the exit codes, and the timeout case. Added a subsection on
testing a reminder inside a session with
set_reminderanddelivery_kind=current_session. Bumped the skill version twice onthis branch (2.75.3 -> 2.76.0 -> 2.77.0).
Design choice to check
A manual run's settlement (
SettleManualExecutioninReminderManagerActor) logs success or failure but does not post achannel failure notice the way a scheduled failure does. The operator
now gets the full result directly from the CLI, so a duplicate channel
post felt like noise for a run the operator asked for directly. Flag
if you want manual failures to also post to the reminder's channel.
Validation
dotnet build Netclaw.slnx -c Release: 0 errors, 0 new warnings(one pre-existing
ASPIRE010warning, unrelated to this change).dotnet test src/Netclaw.Actors.Tests -c Release --filter "FullyQualifiedName~Reminder":210 passed, 0 failed.
dotnet test src/Netclaw.Daemon.Tests -c Release --filter "FullyQualifiedName~Reminder":20 passed, 0 failed.
dotnet test src/Netclaw.Cli.Tests -c Release --filter "FullyQualifiedName~Reminder":6 passed, 0 failed.
dotnet slopwatch analyze: 0 issues.pwsh ./scripts/Add-FileHeaders.ps1 -Verify: all files have headers.NETCLAW_HOME,HOME, and daemonport (57199); the smoke LLM server as the model. Ran an interval
reminder with
netclaw reminder run <id>and confirmed the printedresult block:
Status: ok, the real reply text ("Netclaw smokeresponse."), the session line, and exit 0. Ran it again with
--jsonand confirmed the result object, includingreplyText.Pointed the main model at an unreachable provider (the daemon
picked up the change through its normal config-watch restart),
ran the same reminder again, and confirmed
Status: failed, theconnection-refused error message, and exit 1. Ran
netclaw reminder run does-not-existand confirmed a clearnot-found message and exit 1.
reminder history <id>showed allthree manual runs with their correct status. All processes stopped
after the run; the real
~/.netclawand the default daemon port(5199) were never touched.
This PR adds no tests, at the maintainer's request.
Refs #1511. Replaces draft #1527 (stale — see that PR for the original
requirements; not modified here).