Overview
Callbacks let you hook into the SmolVM command lifecycle. You subclassCallback, override the hooks you care about, and pass instances to SmolVM(callbacks=[...]). Every other hook is a no-op by default.
For a task-oriented walkthrough, see Run callbacks and safety hooks.
Callback
Base class for SmolVM command-lifecycle callbacks. Subclass it and override only the hooks you need.Hooks
Each hook receives a singleRunContext argument.
on_pre_run
run(). Raise CommandBlockedError for an explicit, typed block.
A blocked command keeps the SSH or vsock connection open, so the next allowed run() call reuses it.
on_post_run
ctx.result is populated. Observer hook — exceptions are logged and swallowed so a faulty observer cannot break a command that already ran.
on_run_error
ctx.error is populated. Observer hook — exceptions are logged and swallowed, and the original transport error still propagates from run().
RunContext
Dataclass passed to every hook for a singleSmolVM.run() call. Using one object means new fields can be added later without changing any callback’s method signature.
str
The VM the command targets.
str
The shell command as passed to
run().str
Execution mode —
"login" or "raw".int
Per-command timeout in seconds.
CommandResult | None
default:"None"
The command result.
None until on_post_run. See CommandResult.Exception | None
default:"None"
The transport error raised during execution.
None unless the hook is on_run_error.CommandBlockedError
Exception type for vetoing a command fromon_pre_run. Inherits from SmolVMError.
str
required
Human-readable reason for the block.
str | None
default:"None"
ID of the VM the command targeted. Stored on the exception and in
details.str | None
default:"None"
The blocked command string. Stored on the exception and in
details.vm_id(str | None): The VM the command targeted.command(str | None): The blocked command string.message(str): Reason passed to the constructor.details(dict): Containsvm_idandcommand.
