What's new in staypresent v1.6.0 — a built-in status page, heartbeat hang detection, bot-less/web-less run modes, and static file exclusions.
StayPresent v1.6.0: Status Dashboard, Hang Detection, and Flexible Deployment Modes
StayPresent v1.6.0 is the biggest release the package has had, adding a genuinely new category of capability rather than just tuning existing behavior: a built-in status dashboard, hang detection for bots that are technically running but actually frozen, and new deployment modes that decouple the web server from the bot entirely. Here's a tour of what's new, with links to deeper coverage of each feature.
Table of Contents
- The Built-In Status Page
- Hang Detection with
heartbeat() - New Run Modes: Bot-Only and Web-Only
- File Exclusions for Static Routes
- Status Page Customization Per Route
- Captured Bot Output
- Notable Bug Fixes
- Behavioral Changes Worth Knowing About
- Upgrading
- FAQs
- Conclusion
The Built-In Status Page
The headline feature: staypresent.web.status() generates a real, auto-updating status page in a single function call — a per-service list, rolling uptime figures (24h, 7d, 30d, and lifetime), and incident history pulled directly from what StayPresent already tracks internally.
staypresent.web.status(
title="Groundflare Bot Status",
copyright="Groundflare Inc.",
footer_links=[{"label": "Support", "url": "https://support.groundflare/support"}],
)
You don't even need to call it explicitly — a status page is now served at /status by default, right alongside /health and /. The function call is only needed if you want to customize the title, footer, or move it to a different path.
Public visitors see overall status, uptime, and friendly incident descriptions. Admin-level detail — exit codes, recent stdout/stderr tails — sits behind an api_key-gated login, rate-limited to 5 attempts per 15 minutes. If you don't set a key, StayPresent generates a random one per session and logs it; pass api_key="" to disable the admin view entirely.
Hang Detection with heartbeat()
Crash detection has always caught a bot that actually exits. It's never been able to catch a bot that's technically still running but completely stuck — a deadlock, a frozen loop, a hung network call that never times out. staypresent.heartbeat() fixes this:
# worker.py
import staypresent
while True:
staypresent.heartbeat()
do_work()
# app.py
import staypresent
staypresent.run("worker.py", heartbeat_timeout=30)
If the worker stops calling heartbeat() for longer than heartbeat_timeout seconds, StayPresent logs the issue, terminates the process, and handles it exactly like a regular crash — restart logic and all.
New Run Modes: Bot-Only and Web-Only
Two new modes decouple the bot and the HTTP server, which previously always ran together:
Bot supervision, no HTTP server at all:
staypresent.run("bot.py", web_server=False)
HTTP server only, no bot:
staypresent.run()
The second case is genuinely new — StayPresent can now be a standalone status/health-check service with nothing running underneath it, useful for a dedicated monitoring deployment separate from the bots it's watching.
File Exclusions for Static Routes
web.html() and web.markdown() now accept exclude to block specific files, extensions, or glob patterns from being served alongside the target file:
staypresent.web.html(
"templates/index.html",
exclude=[".env", ".git", "*.py", "secrets.json"],
)
Excluded requests return a clean 404. This directly addresses the "whole directory is exposed" caveat that existed in earlier versions — see the security-focused deep dive linked at the end of this post.
Status Page Customization Per Route
Every route-registering function — text(), json(), html(), markdown(), and the new status() — now accepts status=True/False to control whether it gets its own row on the status page. Bots are shown by default unless explicitly opted out, and services_name/services_description let you rename or describe a row instead of showing a raw path.
Captured Bot Output
Bot stdout/stderr are now captured into a ring buffer rather than only being echoed to the console — still visible live in the parent process as before, but now also feeding the status page's admin log tail, giving crash incidents useful surrounding context instead of just an exit code.
Notable Bug Fixes
-
Embedded ports in pings: host strings like
"localhost:5000"previously defaulted tohttpsincorrectly and could conflict with an explicitport=argument. Mismatches now log a warning and are reconciled correctly. -
IPv6 URL formatting: IPv6 literals like
::1are now properly bracketed ([::1]:8080) in generated URLs. - Unified directory exclusions: if multiple routes serve files from the same directory, exclusions now merge globally, closing a gap where a secondary route could bypass another route's exclusions.
Behavioral Changes Worth Knowing About
-
/,/health, and/statusare now served as implicit virtual default routes. Functionally unchanged, butget_all()andpaths()now correctly list them instead of hiding them. - Bot subprocesses are now launched with piped output streams to support live log capture — meaning a bot checking
sys.stdout.isatty()now seesFalseinstead of the parent terminal's actual value. Worth checking if your bot branches on that.
Upgrading
pip install --upgrade "staypresent[prod]"
Existing run() calls, web.* calls, and ping()/cron() usage all continue working unchanged — everything above is additive.
FAQs
Do I need to change any existing code to get the status page?
No — /status is served by default with no configuration required. web.status() is only needed for customization.
Does hang detection replace crash recovery, or add to it?
It adds to it — restart_on_crash still handles processes that actually exit; heartbeat_timeout catches the separate case of a process that's alive but stuck.
Is the admin log view secure by default?
A random API key is generated and logged if you don't set one yourself, and login attempts are rate-limited — reasonably safe by default, though setting your own key explicitly is recommended for anything public-facing.
Conclusion
StayPresent v1.6.0 turns the package from "keep-alive server plus process supervisor" into something closer to a full lightweight monitoring stack for bots — a real status page, hang detection for frozen processes, and deployment modes flexible enough to run the web server and the bot completely independently.
pip install "staypresent[prod]"
Top comments (0)