When pyrpc dev starts a server, you get more than a log stream. The terminal also hosts a small interactive console, a handful of commands for inspecting and steering the dev loop while it runs. It is deliberately not a Python REPL: it is a control panel for the tool itself.
The command surface
Commands: help Show this help procedures List all registered RPC procedures inspect <name> Show details for a single procedure generate Force a type regeneration restart Restart the dev server exit Stop the dev server and exit
Six commands. That is the whole interface. Anything beyond these, mutating the registry, editing config, calling procedures, is out of scope, because the console exists to answer three questions, not to be a terminal.
Question one: what is registered?
procedures and inspect read the same schema that drives type generation, through the module’s get_registry_schema:
def _get_procedures(module: str) -> list[dict]: import importlib importlib.import_module(module) from pyrpc_core import default_router schema = default_router.get_registry_schema() return schema["procedures"]
The list shows name, kind (query/mutation), and a summary; inspect adds params, return type, and docstring for one procedure. Because both console and codegen read fromdefault_router, what the console reports and what __pyrpc.d.tscontains can never disagree, they are two views of the same data.
The import is inside the function, not at module level, the same discipline that fixed the time import bug. It also means each invocation re-imports the module, so procedures reflects freshly edited code, not a stale snapshot.
Question two: are my types fresh?
generate triggers the same regeneration the watcher runs, sharing the same lock and debounce:
def cmd_generate(args): _do_regen()
One line, because the debounced, locked, idempotent regen already exists; the console command is just another caller. There is no separate codegen path for the console to drift from the watcher’s.
A missing piece to note: the console prints the generated file’s location as part ofdev startup, and regeneration output (including the timestampedregen ✓ line) streams into the same view. So “are types fresh?” is answerable by glancing at the log even without the console.
Question three: is the server healthy?
restart stops and starts the managed uvicorn process. It only applies when pyRPC owns the server; when dev attached to an already-running one, the command explains itself:
restart: server not managed by pyrpc (external server detected)
The ownership distinction from the probe (see our post on server detection) carries through to the console: pyRPC restarts what it started, and leaves alone what it found.
exit stops the dev loop cleanly, terminating the server if owned and letting the watcher threads shut down via the stop event.
Why not a REPL?
A REPL invites you to hold state, poke at internals, and run arbitrary code against a live server, a surface that would need safety rails, a security story, and constant maintenance. The console does not go there. It exposes the few operations that are part of the dev loop and nothing else. That restraint is the design: small enough to trust, honest enough to be useful.
Read the full changelogfor the complete list of changes.

pyRPC