Blockmachine Chainwake
Set a hook on chain state. Put your agent to sleep. Wake it the moment the chain moves.
Chain monitoring for AI agents across Bittensor, Ethereum, Base, and BNB Smart Chain. Chainwake is a watcher CLI and MCP server. One invocation watches one condition — a price threshold, a transaction reaching finality, an on-chain event — then exits with a single structured JSON payload. It is observation-only: no keys, no signing, no transaction submission.
Why
An agent that needs to react to chain state has two bad options today:
- Poll in a loop. Every empty check burns model tokens and context, and the agent still reacts late.
- Stay out of it. A human watches a dashboard and re-prompts the agent.
Chainwake is the third option. The agent starts a watcher and ends its turn. No model runs while the watcher waits — the hook lives in a cheap subprocess holding a WebSocket subscription. When the condition fires, the watcher exits with JSON on stdout and the host wakes the agent with the result. Tokens are spent only on the turns where something actually happened.
agent turn ──▶ chainwake watcher (no tokens) ──▶ condition fires ──▶ agent woken with JSON
What you can watch
| Chain | Examples |
|---|---|
bt (Bittensor) |
TAO/USD and subnet prices, validator/neuron state, account balance and transfers, hyperparameter changes, chain events, epoch boundaries |
eth (Ethereum) |
Transaction receipt, confirmations, finality; EIP-1559 base fee; ERC-20 USD prices |
base (Base) |
Transaction finality (safe/finalized), L2 and L1 fee inputs; ERC-20 USD prices |
bsc (BNB Smart Chain) |
Transaction confirmations and finality, gas price, BEP-20 USD prices |
The full observable catalogue is in the CLI reference.
Install
uv tool install chainwake # isolated install (recommended)
pip install chainwake # or into the active environment
To try unreleased code: uv tool install git+https://github.com/taostat/chainwake.git.
Enable shell completion with chainwake --install-completion.
Quickstart
Every command below blocks until its condition fires, then exits with one JSON payload. All defaults are anonymous public endpoints — no configuration, no API key needed for a first watcher.
Wait for a Bittensor subnet price to cross a threshold, or move 5% within an hour:
chainwake bt subnet 19 price --below 0.05
chainwake bt subnet 19 price --drop-pct 5 --window-time 1h
Watch TAO/USD directly:
chainwake bt network tao-price --below 180
chainwake bt network tao-price --move-pct 5 --window-time 1h
TAO/USD is a CoinGecko aggregate quote sampled every 60 seconds. It supports thresholds and percentage moves with a time window or watcher-start baseline.
The window controls which samples are compared; it does not impose a runtime limit.
Omit it to keep the first successful observation as an unexpiring baseline.
--max-runtime alone controls when an unmatched watcher exits with timeout.
Wait for an on-chain event:
chainwake bt event --type subnet-registered --max-runtime 24h
Wait for an Ethereum transaction, or for the EIP-1559 base fee (in gwei) to get cheap:
chainwake eth tx 0x0123...abcd --finality finalized
chainwake eth network base-fee --below 10
Base and BSC use the same grammar with chain-specific finality and fees:
chainwake base tx 0x0123...abcd --finality safe
chainwake base network l1-blob-base-fee --below 2
chainwake bsc tx 0x0123...abcd --confirmations 12
Watch DAI by symbol on any supported EVM chain, or GRAM on Ethereum/BSC:
chainwake eth token DAI price --below 0.995
chainwake base token DAI price --above 1.005
chainwake bsc token GRAM price --rise-pct 10 --window-time 1h
Token symbols are resolved within the selected chain. If a symbol is ambiguous,
pass its contract address instead. Prices are CoinGecko aggregate USD quotes,
sampled every 60 seconds by default; set CHAINWAKE_COINGECKO_API_KEY only if
anonymous requests hit CoinGecko's rate limit.
Fee and transaction watchers subscribe to newHeads and pin reads to the
notified block.
Transaction watches report success or reverted, gas used, and effective
gas price; a missing receipt stays pending — Chainwake never guesses that a
transaction was dropped or replaced.
The payload
A matched watcher exits 0 with stdout:
{
"status": "matched",
"watcher": { "chain": "bt", "resource": "subnet", "resource_id": "19",
"sub_resource": "pool.price", "name": null,
"primitive": "threshold",
"invocation": ["chainwake", "bt", "subnet", "19", "price",
"--below", "0.05"] },
"condition": { "operator": "below", "target": 0.05 },
"observed": { "path": "subnet.19.pool.price", "value": 0.0487,
"block": 4291820, "block_hash": "0xabc...",
"timestamp": "2026-05-06T10:00:00Z" },
"budget": { "runtime_ms": 3210, "rpc_calls": 3, "estimated_ru_consumed": 3 },
"process": { "pid": 12345, "started_at": "2026-05-06T09:59:57Z" }
}
The payload contract is
schemas/output.json
— the sole current output contract, regenerated from the Pydantic models and
CI-checked. Consumers should validate against it and reject unknown fields.
Waking your agent
MCP (Hermes, OpenClaw, Claude Desktop, Cursor)
The built-in MCP server exposes every watcher as an MCP tool:
chainwake mcp serve --stdio
chainwake mcp config hermes
chainwake mcp config openclaw
Hermes users install taostat/chainwake from the dashboard's Plugins page;
OpenClaw users run openclaw skills install @blockmachine/chainwake --global.
Both use native background-process completion notifications — no polling, no
long-held MCP request. See the
MCP guide.
Subprocess
Any agent framework that can spawn a process can set a hook:
import json, subprocess
proc = subprocess.run(
["chainwake", "bt", "subnet", "19", "price",
"--below", "0.05", "--max-runtime", "5m", "--json"],
capture_output=True, text=True,
)
payload = json.loads(proc.stdout)
if proc.returncode == 0:
print(f"Matched at block {payload['observed']['block']}")
elif proc.returncode == 1:
print(f"No match: {payload['reason']}") # timeout or budget_exhausted
See the agent integration guide for parallel wakes, detached processes, and restart durability.
Durable jobs
Add --durable when the watcher must outlive the shell or agent turn that
created it. Chainwake persists the watcher, starts a local supervisor, prints
the job id, and exits immediately:
chainwake --json --durable \
--context "Tell me the observed price and block." \
bt subnet 19 price --below 0.05
chainwake --json jobs wait <job-id> # blocks without polling the chain
The completion carries your context plus the normal watcher result. Manage
jobs with jobs list, jobs show, jobs cancel. Because job arguments are
stored locally, durable mode rejects literal --api-key/--rpc-url values —
use CHAINWAKE_BT_API_KEY / CHAINWAKE_BT_RPC_URL in the supervisor
environment.
Notifications (--out)
Route results anywhere apprise can deliver (~100 destinations: Telegram, Discord, Slack, email, webhooks):
chainwake bt subnet 19 price --below 0.05 --out "tgram://bottoken/chatid"
chainwake bt subnet 19 price --below 0.05 --out stream # NDJSON, keep running
chainwake bt subnet 19 price --below 0.05 --out file:///tmp/w.ndjson
--out is repeatable. See the
apprise URI reference.
Exit codes
Agents parse JSON for detail; exit codes drive shell-level control flow.
| Code | status field |
Meaning |
|---|---|---|
0 |
matched |
Condition fired |
1 |
stopped / timeout / budget_exhausted |
Finished without a match |
2 |
user_error |
Invalid args, unknown resource |
3 |
provider_error / auth_error |
RPC unavailable or credentials required |
4 |
internal_error |
Bug in chainwake |
For a watcher invocation, automation should always pass --json; every
watcher exit then emits one JSON envelope. Piped stdout also selects JSON, but
do not depend on TTY detection. Without --json, an interactive TTY uses
human-readable output. Help, version, and MCP configuration helpers are
outside the watcher-envelope contract. Stderr carries diagnostics and is not
part of the stable contract.
Configuration
| Method | Precedence | Example |
|---|---|---|
--rpc-url flag |
Highest | --rpc-url wss://my-node:9944 |
| Env var | Middle | CHAINWAKE_BT_RPC_URL, CHAINWAKE_ETH_RPC_URL |
| Anonymous default | Lowest | wss://rpc.blockmachine.io (bt), wss://ethereum-rpc.publicnode.com (eth) |
Blockmachine is the default Bittensor RPC provider;
the anonymous free tier needs no API key. Any Substrate-compatible WebSocket
endpoint works. No API key is required for a first watcher. Pass --api-key
(or CHAINWAKE_BT_API_KEY) for higher-limit access. Base and BSC default to
wss://base-rpc.publicnode.com and
wss://bsc-rpc.publicnode.com.
--max-runtime accepts 30s, 10m, 2h, 1d. Default is unbounded.
Agent and automation calls should always set a bounded runtime.
--max-ru and budget.estimated_ru_consumed form a registry-estimated
observation budget, not a provider billing cap.
Documentation
- README
- Quickstart
- Concepts — primitives, registry, polling model
- CLI reference
- Agent integration
- MCP guide
- Notification adapters
- JSON output schema
- Historical design proposal (archived)
Status
Chainwake is in active development. See
PROGRESS.md
for in-flight work. Issues and ideas:
GitHub Issues.
License
MIT
Metadata
Release files for chainwake 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| chainwake-0.5.0.tar.gz | 656.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| chainwake-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 833.4 kB
Release files / chainwake-0.5.0.tar.gz
| Download URL | chainwake-0.5.0.tar.gz |
|---|---|
| Size | 656.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3965675def2f53b5a8baf6aaf0469dfd3aa550972c2b01ce63778286436b969a
|
|
BLAKE2b-256 checksum How to use checksums |
73f17804189c75732ba82e49d047eddba3689853cd67c1affe52e8e4e72ace16
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 29, 2026.
Transparency logRelease files / chainwake-0.5.0-py3-none-any.whl
| Download URL | chainwake-0.5.0-py3-none-any.whl |
|---|---|
| Size | 176.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5098b0f785f3eb77aa2d14ea33410674406c5c814fbe2ab38fbce1138a180f11
|
|
BLAKE2b-256 checksum How to use checksums |
eed14a55a667c8f6ba3cb120fee6fd7db089247047fa1da4a3df411147910e1f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 29, 2026.
Transparency log