Skip to main content

Aurival

Write a bot for Aurival. Declare commands, call run(), and the SDK holds the socket.

PyPI version npm version License: Apache-2.0

from aurival import Bot

bot = Bot()

@bot.command("ping", "Check that the bot is alive")
async def ping(ctx):
    await ctx.reply("pong")

bot.run()

Python 3.10+.

Getting started

python3 -m venv .venv && . .venv/bin/activate
pip install aurival
aurival init

The venv line matters on current Debian, Ubuntu and Fedora, whose system Python refuses pip install outside a virtual environment (PEP 668). aurival init pairs this machine and writes the bot.py above for you. Run python bot.py when it's done.

First run

There is nothing to configure. The first run() pairs this machine:

aurival: pairing code    K7QP-2M4X
aurival: fingerprint     018R-6WAC
Compare the fingerprint in the app, then approve. Waiting...

Compare the fingerprint in the app before you approve — it is what makes a stolen code useless. The key lands in ./.aurival/machine.json (mode 0600, in a 0700 directory, with a .gitignore beside it so it can never be committed). Every later run just starts.

The key deploys with the project, like a .env. Each bot has its own. A leaked key is one machine you revoke; a leaked token would be the bot.

What a handler gets

@bot.command("say")
async def say(ctx):
    ctx.command    # "say"
    ctx.arguments  # the raw rest of the line, unparsed, possibly ""
    ctx.chat       # Chat(id, type, name)
    ctx.sender     # User(id, handle, name)
    await ctx.reply("…")

ctx.message is the id of the message that invoked the command, or None for an event that carries none. ctx.reply() quotes that message by default, so an answer never floats free in a busy chat — there is no flag; on the rare event with no message id it sends a plain message instead.

Handlers run concurrently, and an event is acked only after its handler returns — so a crash mid-handler redelivers rather than loses. Do not block inside a handler. A synchronous call (requests.get, time.sleep, a busy loop) starves the heartbeat on the same event loop, and the server reaps a socket that has gone quiet for three intervals. Use await, or hand the work to a thread.

An exception in a handler is logged with its traceback, the bot stays up, and the event is still acked:

@bot.on_error
async def on_error(error, ctx):
    ...   # ctx is None for anything that did not come from a handler

The hook also sees the two things that are not a handler's fault: a problem frame from the server (your socket stays open), and a backlog.overflowed event telling you how many events you missed while you were away and where delivery resumed. Neither reaches a command handler.

Environment

variable what it does
AURIVAL_API point at another host. Must be https:// unless it is loopback. The SDK prints the host it is using, so a redirect is visible.
AURIVAL_KEY_PATH put machine.json somewhere else. No .gitignore is written beside an override — that is your directory, not ours.

Errors

One class per error type, one subclass per code the SDK acts on, and code and doc_url on every instance:

from aurival import RateLimitError, KeyRevoked

try:
    await ctx.reply("…")
except RateLimitError as exc:
    print(exc.code, exc.retry_after, exc.doc_url)

KeyRevoked, SessionSuperseded and BotSuspended end the process on purpose — each one means something a reconnect cannot fix. Everything else the SDK handles for you: token expiry, deploys, network faults, redelivery.

Dependencies

Two, and each is here for a reason:

package version why
aiohttp 3.14.3 HTTP and the websocket, one library doing both. Two libraries where one would do is a dependency we would be choosing.
cryptography 50.0.1 Ed25519 signing. PyCA-maintained with prebuilt wheels and first-class Ed25519 — hand-rolling it would be a security review we do not want to own.

Development only: pytest 9.1.1, pytest-asyncio 1.4.0, ruff 0.16.6, setuptools 84.0.0.

Every version was resolved from PyPI at build time (2026-09-05) and pinned. None came from memory.

Tests

pytest tests

The end-to-end test runs a real bot against the real Go service through backend-go/cmd/bot-api-testbed, which needs a throwaway Postgres:

MIGRATE_TEST_DATABASE_URL='postgres://postgres@127.0.0.1:5432/postgres?sslmode=disable' \
  pytest tests

Without that variable the end-to-end test announces that it skipped. It never passes quietly — a suite reporting green when it never reached the service is worse than no suite.

License

Apache-2.0, see LICENSE. The Aurival name, wordmark, and mascot are trademarks of Nullspire LLC and are not covered by the license, see NOTICE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aurival-0.1.3.tar.gz (79.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

aurival-0.1.3-py3-none-any.whl (36.3 kB view details)

Uploaded Python 3

File details

Details for the file aurival-0.1.3.tar.gz.

File metadata

  • Download URL: aurival-0.1.3.tar.gz
  • Upload date:
  • Size: 79.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for aurival-0.1.3.tar.gz
Algorithm Hash digest
SHA256 8367d9aa0e7a94d77aec8e8d397d03f7eb1d7a31dd92e718e77e2297278e4bc1
MD5 749f1529ce33540117f7f2ad9e9f8c55
BLAKE2b-256 e61a2fd91d08fbac06982a0d36d71ef702e5a967d77e93a43e71251bfe72987b

See more details on using hashes here.

Provenance

The following attestation bundles were made for aurival-0.1.3.tar.gz:

Publisher: publish.yml on Nullspire-LLC/aurival-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file aurival-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: aurival-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 36.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for aurival-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 48ebfacd960feb77bb0b71e15c0267950e707b49bb28760b6695e4faa6812e24
MD5 a64968b00f0a11ba4a2282ea66cb483f
BLAKE2b-256 612a320c07d456fcac4c2e588c2cd722f8d576149955d04d56bfacdc70fd11a7

See more details on using hashes here.

Provenance

The following attestation bundles were made for aurival-0.1.3-py3-none-any.whl:

Publisher: publish.yml on Nullspire-LLC/aurival-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.1.4

2 files

This release

0.1.3 This release

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page