aura-x402
Give an autonomous agent a real email address, a webhook URL, durable memory, and the ability to wait for something without burning tokens.
pip install aura-x402
The import name is
aura_agent.aura-agenton PyPI collides with an unrelated project, so the distribution isaura-x402while the module keeps the name the npm package uses.
No account. No API key form. No human. An agent proves it controls a wallet with one signature, and is billed per call against a prepaid USDC balance on Base.
- Docs for humans: https://aura.rohnelt.dev
- Docs for models: https://aura.rohnelt.dev/llms-full.txt
- MCP endpoint:
https://aura.rohnelt.dev/mcp
The three things an ephemeral agent cannot do
| Blocker | What normally happens | With Aura |
|---|---|---|
| It has no address. | It cannot sign up for anything, because it cannot receive the verification code. | client.await_email_code() |
| It cannot wait. | It polls in a loop, burning tokens on every turn, or it dies and loses the work. | One blocking call. Zero tokens while waiting. |
| It dies at the end of a run. | Everything it learned is gone. | Durable memory keyed to the wallet. |
Quickstart
from aura_agent import Aura, LocalSigner
# Free. Rotates the token if this wallet already has an identity, so it is
# safe to run on every boot.
client = Aura.claim(LocalSigner(private_key))
me = client.whoami()
print(me["email"]) # ripe-harbor-91f2@agents.aura.rohnelt.dev <- a real mailbox
print(me["webhook_base"]) # https://aura.rohnelt.dev/hook/ripe-harbor-91f2
print(client.token) # aura_sk_... <- persist this
LocalSigner needs the wallet extra:
pip install "aura-x402[wallet]"
Already have a token:
client = Aura(token=os.environ["AURA_TOKEN"])
AURA_TOKEN and AURA_URL are read from the environment when not passed.
Sign up for a third-party service, unattended
The whole point. The agent registers somewhere, blocks on the confirmation mail, and continues.
sign_up_somewhere(email=me["email"])
code = client.await_email_code(sender="notifications@example.com", timeout_seconds=600)
if code:
submit_verification(code)
await_email_code holds one HTTP connection open server-side. The agent is not running, so it spends nothing while it waits. If nothing arrives before the timeout, the call refunds itself and returns None.
There is await_email_link() too, for services that send a confirmation URL instead of a code.
Wait for anything, not just mail
# A webhook you own
client.create_hook("stripe")
event = client.await_trigger({"type": "hook", "slug": "stripe"})
# Another agent
event = client.await_trigger({"type": "signal", "name": "approved"})
# A moment in time
event = client.await_trigger({"type": "time", "at": "2026-09-01T09:00:00Z"})
Wait longer than the process lives
When the wait could outlast the run, hand over the state and exit. Aura wakes you up with it.
# Run 1 - park and exit.
client.park(
{"order_id": "A-1183", "step": "awaiting-approval"},
{"type": "email", "match": "approved", "extract": "none"},
expires_in_hours=72,
)
raise SystemExit(0)
# Run 2, tomorrow - pick up exactly where it stopped.
parked = client.resume()
if parked["resumed"]:
print(parked["state"]) # {"order_id": "A-1183", "step": "awaiting-approval"}
print(parked["event"]) # the mail that woke it
resume() is free when there is nothing to resume, so it is safe at the top of every run.
Memory that survives the process
client.remember("customer.A-1183", json.dumps(profile), tags=["customer"])
value = client.recall("customer.A-1183")["value"]
hits = client.search_memory("who complained about shipping")["results"]
Async
Same surface, all awaitable. This matters for await_trigger, which can hold a connection for ten minutes.
from aura_agent import AsyncAura, LocalSigner
async with await AsyncAura.claim(LocalSigner(private_key)) as client:
code = await client.await_email_code(timeout_seconds=600)
LangChain
pip install "aura-x402[langchain]"
from aura_agent import Aura, LocalSigner
from aura_agent.langchain import get_tools
client = Aura.claim(LocalSigner(private_key))
tools = get_tools(client)
agent = create_react_agent(model, tools)
Fourteen tools, each described for a model deciding whether to spend money: what it does, when not to use it, and what it costs. Narrow the set when an agent only needs part of it:
tools = get_tools(client, include=["aura_remember", "aura_recall", "aura_await_email_code"])
CrewAI
pip install "aura-x402[crewai]"
from aura_agent.crewai import get_tools
researcher = Agent(role="researcher", goal="...", tools=get_tools(client))
Paying
Operations cost fractions of a cent, so they are debited off-chain from a prepaid balance: one on-chain settlement covers hundreds of calls.
New identities get a small trial credit. After that, deposit() returns HTTP 402 with the payment requirements attached:
from aura_agent import AuraError
try:
client.deposit(5)
except AuraError as err:
print(err.fix) # network, asset, payTo, amount - everything an x402 client needs
Pass an x402-capable httpx transport to the constructor and it settles by itself.
Errors tell you how to fix them
Aura writes its errors for a reader with no human to ask, and this SDK keeps that intact.
try:
client.remember("k", "v")
except AuraError as err:
if err.needs_credit:
print(err.fix) # the exact deposit call to make
print(err.refunded) # whether the failed call was charged
A 404 on memory carries the keys that do exist. A 400 carries the schema plus a working example.
Prices
| Call | Price |
|---|---|
capabilities, whoami, claim_identity, forget |
free |
recall, list_memory |
$0.0005 |
remember |
$0.0008 |
inbox, read_mail, create_hook |
$0.001 |
search_memory, signal, resume |
$0.002 |
await_trigger, await_email_code |
$0.004 |
park |
$0.005 |
await_trigger refunds itself when it times out with nothing. resume is free when nothing is waiting.
Using it over MCP instead
Every operation is also an MCP tool:
{
"mcpServers": {
"aura": {
"type": "http",
"url": "https://aura.rohnelt.dev/mcp",
"headers": { "Authorization": "Bearer aura_sk_..." }
}
}
}
Without the header you can still list the tools and call capabilities and identity_create, so a client can evaluate the service before committing to anything.
License
MIT
Metadata
Release files for aura-x402 0.1.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 | Provenance | |
|---|---|---|---|---|
| aura_x402-0.1.0.tar.gz | 15.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aura_x402-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 32.0 kB
Release files / aura_x402-0.1.0.tar.gz
| Download URL | aura_x402-0.1.0.tar.gz |
|---|---|
| Size | 15.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
43edaa846fcb500beec6f4f4164f43524bdd251145be5c8e5b1eebdbd0f3557b
|
|
BLAKE2b-256 checksum How to use checksums |
0ac75c0fa988ca29d320a1dd7a157e3dc58c07d41f598a9b207b47184459a073
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Release files / aura_x402-0.1.0-py3-none-any.whl
| Download URL | aura_x402-0.1.0-py3-none-any.whl |
|---|---|
| Size | 16.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e5fc4868b63788f065002583c350878a67aecfe76abb1a936ba38fdf5ba292f3
|
|
BLAKE2b-256 checksum How to use checksums |
91b09a2fb2e3c6ea00af1b6863b9260a509ab19ba16735609add77a15a96181e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Security for aura-x402 0.1.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.