# aiomonitor, a task monitor and Python REPL for asyncio applications

> aio-libs/aiomonitor gives a running asyncio program a telnet-accessible command console with a task table, stack traces and an async Python REPL, running in a separate thread so it still answers when the event loop is blocked. It is aimed at development and debugging rather than production, and its last release was v0.7.1 in 2024.

**aio-libs/aiomonitor** — aiomonitor is module that adds monitor and python REPL capabilities for asyncio application

- Repository: https://github.com/aio-libs/aiomonitor
- Website: https://aiomonitor.aio-libs.org
- Stars: 777 · Forks: 48
- Language: Python
- License: Apache-2.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/aio-libs-aiomonitor

## A monitor thread that survives a blocked event loop

aiomonitor adds monitor and command line capabilities to asyncio applications, with the idea and code borrowed from the curio project. The architectural decision that defines it is described in the README as a task monitor that runs concurrently to the asyncio loop in a separate thread, so the monitor works even if the event loop is blocked for some reason.

That last clause is the whole point. In a single-threaded asyncio program, a coroutine that awaits forever, a blocking call inside a coroutine, or a deadlock leaves you with no way in. The usual answers are to attach a debugger from outside or to restart. aiomonitor's answer is that the monitor does not live on the event loop, so it keeps answering while the loop is stuck, which is exactly when you most need it.

The console itself is provided by the aioconsole module, and it can execute asynchronous commands inside the running application. The README describes the result as a Python console using aioconsole, extensible with your own commands in the style of the standard library cmd module, and the current implementation uses Click for the command definitions.

Requirements are Python 3.8 or newer with 3.10.7 recommended in the README, while the pyproject.toml declares requires-python as 3.10 or above and lists classifiers for 3.10 through 3.13. The runtime dependencies are worth knowing about because they explain the behaviour: aiohttp, click, prompt_toolkit, aioconsole, telnetlib3 for the server side, janus for the thread-safe queue between the monitor thread and the loop, pydantic for configuration, jinja2 for the HTML web interface, terminaltables for the task table rendering, and attrs.

The documentation site is at aiomonitor.aio-libs.org and the project classifies itself as alpha.

## Getting a shell into a running application

Installation is a single pip line:

```bash
pip install aiomonitor
```

The integration is a context manager, so the monitor's lifetime is tied to a block of your code:

```python
import asyncio

import aiomonitor

async def main():
    loop = asyncio.get_running_loop()
    run_forever = loop.create_future()
    with aiomonitor.start_monitor(loop):
        await run_forever

try:
    asyncio.run(main())
except KeyboardInterrupt:
    pass
```

From another terminal you connect to the application over telnet on port 20101, or use the bundled client:

```bash
python -m aiomonitor.cli
```

The README notes that uvloop is an optional requirement and that the monitor works as a drop-in replacement for it, so you can point the monitor at an event loop implementation you already use rather than being forced onto the default.

The aiohttp tutorial shows the realistic shape, starting the monitor just before the application runs and passing a dictionary of local variables into the console environment:

```python
    host, port = "localhost", 8090
    locals_ = {"port": port, "host": host}
    with aiomonitor.start_monitor(loop=loop, locals=locals_):
        web.run_app(app, port=port, host=host, loop=loop)
```

That locals argument matters in practice, since it is how you get a reference to a port number or a configuration object without having to hunt for it inside the console.

## What the command set actually lets you do

The monitor prompt greets you with a task count, and the help output lists the available commands. The set is small and specific to asyncio internals:

```text
    cancel                  Cancel an indicated task
    console                 Switch to async Python REPL
    exit (q,quit)           Leave the monitor client session
    help (?,h)              Show the list of commands
    ps (p)                  Show task table
    ps-terminated (pst,pt)  List recently terminated/cancelled tasks
    signal                  Send a Unix signal
    stacktrace (st,stack)   Print a stack trace from the event loop thread
    where (w)               Show stack frames and the task creation chain of a task
    where-terminated (wt)   Show stack frames and the termination/cancellation chain of a task
```

The distinction between ps and ps-terminated is the useful part. A task table tells you what is running now; the terminated list keeps recently cancelled and finished tasks around so you can look at what just died. The where command goes further, showing the stack frames and the chain of task creation that led to a given task, which is how you find out who spawned the coroutine that is now blocked.

Cancel and signal are the recovery tools. Cancel an indicated task from outside the process, or send a Unix signal to the running application, and you can watch the effect through the terminated task list.

The console command switches to an async Python REPL inside the running event loop, where await works directly:

```text
    monitor >>> console
    This console is running in an asyncio event loop.
    It allows you to wait for coroutines using the 'await' syntax.
    Try: await asyncio.sleep(1, result=3)
    ---
    >>> await asyncio.sleep(1, result=3)
    3
```

That is a meaningful difference from a normal REPL, because it means you can call into your own coroutines and await the result rather than only inspecting state.

## Extending the console with your own variables and commands

The README documents two extension points, and both point at example files in the repository.

The first is additional console variables. You may add variables that can be referenced directly in the console command, and the example is the console-variables.py file in the examples directory. This is the mechanism to use when you want to reach an object without importing it in the console session.

The second is custom console commands, with the example being extension.py. The README says aiomonitor is very easy to extend with your own console commands, and since the command layer is Click-based, a custom command is a Click command registered with the monitor's command group, which means it gets the same help formatting and the same argument handling as the built-in ones.

The examples directory also contains cancellation.py, demo.py, simple_loop.py, taskgroup.py, web_srv.py, web_srv_custom_monitor.py and simple_aiohttp_srv.py. The two web server examples are notable because the custom monitor variant exists as a separate file, which suggests the project supports hosting the monitor inside an existing web server rather than only on its own telnet port.

The project also depends on jinja2 and includes terminaltables as a dependency, which together with the aiohttp dependency point to an HTML view of the same information as well as the text console.

## The security boundary and the maintenance picture

The important limitation is the security boundary, and it should be stated plainly. aiomonitor opens a telnet server, port 20101 by default, which grants a Python console inside your running process. Anyone who can reach that port can execute arbitrary code in your application, read its data and call its internals. There is no authentication described in the README and no mention of TLS.

The dependencies list confirms the shape of the server, since telnetlib3 is a required runtime dependency rather than an optional extra. Telnet itself carries no encryption, so even a bind to localhost is the minimum sensible setting and a tunnel is required for anything beyond a single machine.

Given that, the sensible use is a development and debugging tool: start the monitor in a development entry point, leave it out of production configuration, or bind it to a loopback interface on a controlled host. The README classifies the project as alpha and its keywords list includes devtool, which points the same way.

On maintenance, the last push was on 2026-10-05, but the most recent release is v0.7.1 from 2024-11-11, following v0.7.0 in December 2023 and v0.6.0 in August 2023. So the source is being worked on while the published version has not moved for the better part of two years. The pyproject.toml derives its version from setuptools_scm with a uv.lock file present, which suggests the project is prepared for versioned releases that have not yet been cut.

The licence is Apache-2.0, which is permissive and fine for embedding, and the author list names Nikolay Novik with Joongi Kim as maintainer.

## Conclusion

Adopt aiomonitor while developing an asyncio service, when you need to see which task is stuck, cancel a coroutine from outside the process, or open an async REPL against live state. Do not enable it in a production deployment, since it opens an unauthenticated telnet port that grants a Python console inside your process. Verify first by starting the monitor in a development entry point, connecting with python -m aiomonitor.cli, and running the ps command to confirm the task table reflects your application before relying on it.

## FAQ

### What does aiomonitor add to an asyncio application?

It adds a monitor thread with a telnet-accessible command console that can inspect asyncio tasks, print stack traces, cancel tasks and open an async Python REPL inside the running event loop. The idea and code were borrowed from the curio project.

### How do I install aiomonitor and connect to it?

Install with pip install aiomonitor, start it with the aiomonitor.start_monitor(loop) context manager, then connect from another terminal with telnet localhost 20101 or with the bundled client, python -m aiomonitor.cli.

### Which commands does the aiomonitor console provide?

The help output lists cancel, console, exit, help, ps, ps-terminated, signal, stacktrace, where and where-terminated. The where command shows stack frames and the task creation chain, and ps-terminated keeps recently finished or cancelled tasks visible.

### Can I add my own commands and variables to aiomonitor?

Yes. The README documents adding extra console variables and registering custom console commands, pointing at the console-variables.py and extension.py files in the repository's examples directory for both.

### Is aiomonitor safe to enable in production?

It opens a telnet port that provides a Python console inside your process, and the README describes no authentication. Treat it as a development and debugging tool, keep it out of production configuration, and note that the telnet protocol itself carries no encryption.

## Sources

- [aio-libs/aiomonitor on GitHub](https://github.com/aio-libs/aiomonitor)
- [License: Apache-2.0](https://github.com/aio-libs/aiomonitor/blob/main/LICENSE)
- [Project website](https://aiomonitor.aio-libs.org)
- [README](https://github.com/aio-libs/aiomonitor/blob/main/README.md)
- [Releases](https://github.com/aio-libs/aiomonitor/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/aio-libs-aiomonitor
