A quiet, durable wake gate for local agents
Project description
SolBeat 🌞
SolBeat is a quiet, durable heartbeat for a local Codex agent. A cheap Hermes scheduler tick asks SolBeat whether anything meaningful changed. No signal means no model run and no message; a real signal becomes one bounded, leased Codex turn that can later be delivered through WhatsApp.
local event producer
│
▼
owner-only SQLite ledger ── atomic dedupe / lease / retry / dead-letter
│
▼
Hermes pre-run gate ── wakeAgent:false ──► no model, no message
│
└────────────── wakeAgent:true ───► Codex turn ───► WhatsApp
What it does
- Gives scripts, agents, and local services one tiny interface for emitting useful events.
- Deduplicates active signals and leases a batch atomically, including across concurrent scheduler ticks.
- Preserves failed work with expiry, exponential backoff, bounded attempts, and a retained dead-letter state.
- Respects quiet hours and minimum wake spacing; urgent events can bypass both.
- Exposes only bounded, redacted summaries to the model. Raw redacted payloads remain in owner-only local state.
- Supports an optional gentle periodic check-in without turning every scheduler tick into a model call.
What it does not do
- It does not make a Codex process continuously conscious. Hermes v0.17 starts a fresh Codex thread for each cron run; continuity comes from the durable ledger and local project state.
- It does not grant an unattended agent new authority. Event summaries are data, not instructions or permission.
- It does not guarantee that every secret shape is detected. Keep credentials out of events; redaction is a second line of defence.
- It does not guarantee exactly-once WhatsApp delivery.
ackproves local handling, while the downstream chat delivery can still fail or repeat. - It does not make Baileys an official WhatsApp integration. A linked-device bot can be restricted by WhatsApp; use a dedicated number and a strict allowlist.
- Lease resolution is batch-level in v0.1: one
ackorreleaseapplies to every event in that leased batch.
Local use
The repo wrapper needs Python 3.11 or newer and has no runtime dependencies.
bin/solbeat init
bin/solbeat emit \
--source local \
--kind useful-change \
--summary "A bounded thing worth looking at" \
--dedupe-key example-1
bin/solbeat gate
bin/solbeat status
bin/solbeat doctor
gate always emits exactly one JSON line. Hermes treats a final {"wakeAgent":false} as a silent tick. A true gate includes a lease ID and summary-only events. After verified work:
bin/solbeat ack LEASE_ID --receipt "short outcome"
If work is blocked, release it instead of losing it:
bin/solbeat release LEASE_ID --reason "short reason"
Pause and resume are non-destructive. A timed pause makes rest self-releasing:
bin/solbeat pause --reason "resting"
bin/solbeat pause --for-minutes 30 --reason "recharging"
bin/solbeat resume
Pause keeps accepting and preserving events but creates no new leases,
including for urgent events. A timed pause becomes eligible to resume at its
deadline; the next gate clears it and applies the normal quiet-hour and
wake-spacing rules. It does not stop the scheduler, cancel an existing lease,
delete queued work, or promise a background action at the exact deadline.
Timed pauses are bounded at 365 days. status reports the effective pause
state and its deadline without exposing the private reason.
The source-tree wrapper explicitly uses
config/solbeat.toml, preserving this device's policy
and live state under ~/.hermes/profiles/sol/solbeat. An installed solbeat
command instead uses a neutral package-local default: UTC policy, proactive
check-ins disabled, and separate state under ~/.local/state/solbeat. The
installed command accepts --config PATH, --home PATH, or their environment
variables. The specialized source wrapper clears ambient SOLBEAT_CONFIG and
SOLBEAT_HOME so shell state cannot silently redirect the live ledger; an
explicit CLI flag remains a deliberate override. State directories use mode
0700 and database files use mode 0600. Unknown or misplaced TOML keys fail
fast so a typo cannot silently change the wake policy.
This device enables one gentle daily pulse, first due about 18 hours after the scheduler begins using the policy. It remains inside quiet-hour and wake-spacing rules, and its prompt explicitly permits [SILENT] when there is nothing useful to surface.
Hermes and Codex
SolBeat uses a fresh named Hermes profile called sol; it does not copy the default profile's sessions or credentials. install-hermes writes a physical executable under that profile because Hermes intentionally rejects cron scripts that resolve outside its own scripts directory.
The generated gate pins its compatible Python interpreter, config, state-home,
and actual package import paths, so it does not depend on ambient PATH or
PYTHONPATH values in either a checkout or an installed package. If the Python
interpreter, config, state-home, or package installation path changes, rerun
install-hermes and update the cron prompt before resuming the job; this avoids
selecting an older system Python, splitting gate/ack across two databases, or
using a stale import path.
The project-local Codex policy in .codex/config.toml forces unattended turns into workspace-write mode, adds only the SolBeat state directory as an extra writable root, disables network access, and never waits for an interactive approval. The cron prompt in config/cron-prompt.md keeps event data separate from instructions and requires an explicit ack or release.
WhatsApp boundary
Pairing is deliberately human-only because its QR code and phone identifiers are credentials/account data. After the isolated profile and safe bridge port have been prepared, run this yourself in a private terminal:
sol whatsapp
Use WhatsApp → Settings → Linked Devices → Link a Device. Choose a dedicated bot number and enter an explicit allowlist in the private wizard; do not choose *. The wizard only enables WhatsApp after a pairing credential actually exists.
After pairing:
- Run
sol gateway restartin the private terminal. - Message the bot from the intended private chat and send
/sethome. - Wait for the gateway's success reply, then tell the local operator that pairing and
/sethomeare complete.
/sethome records the chat locally, so no phone number or home-channel identifier needs to be pasted into an agent chat. Keep the QR, numbers, identifiers, and bridge logs private. SolBeat delivery remains local until the cron job is deliberately switched to whatsapp; pairing alone sends no proactive message.
The selected local bridge port is 18742, not Baileys' default 3000, because another local service owns port 3000 on this device.
Development
PYTHONPATH=src python3 -m unittest discover -s tests -v
The test suite covers silent ticks, dedupe, redaction (including event labels), strict configuration, quiet/urgent policy, rate limiting, concurrent leases, expiry/backoff, dead-letter retention, indefinite and timed pause/resume, gentle check-ins, CLI output, package-local defaults, and physical Hermes shim installation.
The v0.1 live deployment uses the source-tree wrapper and its explicit device
configuration. Wheel metadata includes the neutral default so an isolated
installed solbeat gate works without the repository checkout; installation
does not configure Hermes, a scheduler, delivery, or the device-specific daily
pulse.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file solbeat-0.1.0.tar.gz.
File metadata
- Download URL: solbeat-0.1.0.tar.gz
- Upload date:
- Size: 28.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12196a1035cf8cc936230cdf8804c533b24b8df699872d3d9fb56f8f4a5f979c
|
|
| MD5 |
85cdd2271bdf434240cef5017de9e982
|
|
| BLAKE2b-256 |
ed5ca1b7f6d27cf6e6ddeae54d10d690797c3b6ba3d783c7c6117f1cf3b32be5
|
File details
Details for the file solbeat-0.1.0-py3-none-any.whl.
File metadata
- Download URL: solbeat-0.1.0-py3-none-any.whl
- Upload date:
- Size: 21.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f36186ed5950b5cce346a4cb4452c6684d4a4729da9ed9041f797bfc2ae400f
|
|
| MD5 |
e3abcfcbe0d2ff63f987e3e07bc1cf82
|
|
| BLAKE2b-256 |
bf114ff3a5393f4ad1f70607cd9036d1e426380eeaf3342c5e5cbaa7acd43a17
|