darkob
Fast, stable async Python for the Rubika & Shad platforms.
Bots and userbots that stay up — with an API verified against the real server.
Docs · AI context · PyPI · Roadmap
pip install darkob
from darkob import Bot, Keyboard
bot = Bot(token="YOUR_BOT_TOKEN")
@bot.on_command("start")
async def start(bot, event):
await event.reply(
"Welcome 👋",
inline_keypad=Keyboard().row("Docs", "Support"),
)
bot.run()
Why darkob
A fork of maxrubika, rebuilt so failures are visible, the fast paths are actually fast, and the API surface matches the server.
| Inherited problem | What darkob does |
|---|---|
| Contacted PyPI at import time | Importing performs no network I/O |
| TLS verification disabled everywhere | Verification on by default, opt-out explicit |
Bare except: swallowed KeyboardInterrupt |
Narrowed to Exception, and logged |
| Background handler crashes vanished at GC | Logged the moment they happen |
| Every event scanned all handlers | Indexed dispatch, built once |
Retries were endpoints × max_retries |
Bounded budget with jitter and 429 handling |
| A new TLS handshake per download | Pooled sessions everywhere, including files |
| Saved sessions opened but never read | Credentials restored; sessions survive restarts |
| A corrupt session file was deleted | Quarantined, never destroyed |
| Keypad editing called a non-existent endpoint | Fixed by live testing, pinned by a regression test |
What's inside
|
Two surfaces, one library
|
Async first, sync friendly Every method works with |
|
Handlers, filters, routers Decorators, 42 filters composing with |
Conversations
|
|
Keyboards for every button type
|
Message helpers
|
|
Iterators, not pagination loops
|
Testing toolkit
|
Reliability
Six primitives that most bot libraries leave to the user:
| Primitive | What it buys you |
|---|---|
Retry(attempts=, backoff=, jitter=) |
A policy you can reason about, honoured by both surfaces |
RateLimiter(rate=, per_chat_rate=) |
Token buckets globally and per chat, applied to every attempt |
CircuitBreaker |
A dead data centre stops burning your retry budget |
SendQueue(path=) |
Messages survive a dropped connection and flush on reconnect |
ProtocolTracker |
Reports when Rubika reshuffles its endpoints |
| Resumable downloads | Byte-range resume that survives an interrupted file |
from darkob import Bot, RateLimiter, Retry, SendQueue
bot = Bot(
token="...",
retry=Retry(attempts=4, backoff=0.5),
rate_limiter=RateLimiter(rate=20, per_chat_rate=3),
)
outbox = SendQueue(bot, path="outbox.json")
outbox.start()
Performance
Measured with benchmarks/benchmark_suite.py against maxrubika 1.17.0 on
the same machine, each case in a fresh process:
| Benchmark | darkob | maxrubika | Result |
|---|---|---|---|
Read event.text ×20,000 |
13.9 ms | 20.3 ms | 1.5× faster |
| Nested key lookup ×20,000 | 3.0 ms | 17.0 ms | 5.7× faster |
| Filter evaluation ×5,000 | 5.7 ms | 6.5 ms | 1.2× faster |
| Route an update, 50 handlers | 5.3 ms | 8.1 ms | 1.5× faster |
| Route an update, 500 handlers | 5.4 ms | 8.0 ms | 1.5× faster |
Three things carry the difference:
- Lookups are indexed. Every payload builds a key index on first
access, so
event.text— which searchestextthencaption— no longer walks the structure on every read. - Dispatch is an index, not a scan. Handlers are grouped by update name once, so routing cost stays flat whether a bot registers 50 handlers or 500.
- The update name and waiter list are cheap.
capitalize()is memoised and a pendingask()costs one integer check per update.
Verified against the real API
The Bot API documents 19 endpoints. All are implemented, and 18 were
exercised against a live server — including the full file round-trip
(requestSendFile → uploadFile → getFile → sendFile → download) and
byte-range resume.
That testing caught three things static reading could not:
editInlineKeypad— the docs' own cURL — answersINVALID_INPUT: Invalid Method. The working endpoint iseditMessageKeypad.- A bare
Paymentbutton is rejected;Button.payment()now demands its fields instead of failing at send time. Bot.download_filewas opening its own HTTP session, paying a fresh TLS handshake per file.
The remaining two gaps are documented rather than guessed: getChatMember
needs a group chat to verify, and setCommands has no read-back, so
testing it would destroy your command list.
Documentation
Full site: manitheferfri.github.io/darkob
| Quickstart | Install to running bot in five minutes |
| Handlers · Filters | Every decorator and all 42 constraints |
| Routers | Split a bot into modules, with scoped middleware |
| Conversations | State, storage backends, StateFilter |
| Keyboards | All button types and formatting |
| Composing messages | MessageBuilder and formatting together |
| Errors | Retries, breaker, rate limiting, queue |
| Bot API · Messenger API | Generated from the package |
Built for AI-assisted development
Most darkob bots are written by an assistant, so the docs are built to be read by a model.
https://manitheferfri.github.io/darkob/llms-full.txt
One file, one fetch: hard rules, every guide, and the complete API with full docstrings for all 688 methods.
llms.txt— curated mapapi.json— every method as JSON- Every page is also served as raw Markdown: append
.mdto any URL - The API reference is generated from the installed package, so it cannot drift
Development
git clone https://github.com/ManiTheFerfri/darkob.git
cd darkob
pip install -e ".[dev]"
pytest --cov=darkob # 463 tests, no network required
ruff check . # lint
mypy darkob/router.py darkob/retry.py darkob/builders.py \
darkob/keyboards.py darkob/formatting.py darkob/testing.py
The suite never opens a socket: HTTP goes through fake transports, and a
subprocess test asserts that importing darkob cannot reach the network.
Two extra tools live in scripts/:
benchmark.py— micro-benchmarks for the hot paths, no network.conformance.py— exercises every Bot API method against a real token, cleans up after itself, and exits non-zero on failure.
Roadmap
See docs/roadmap.md — milestones 1–3 and P0–P2 are closed. It records what is proven, what is impossible, and why.
License
MIT. Derived from maxrubika, copyright MEHRAB Farahmand; the original MIT notice is preserved in LICENSE.
Maintained by Mani Keikhosravi.
Not affiliated with Rubika or Shad. Use responsibly and in line with the platforms' terms of service.
Metadata
Release files for darkob 0.17.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 | Actions |
|---|---|---|---|---|
| darkob-0.17.0.tar.gz | 258.8 kB | With provenance | Details for darkob-0.17.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| darkob-0.17.0-py3-none-any.whl | Python 3 | none | any | Details for darkob-0.17.0-py3-none-any.whl |
Total release size: 657.9 kB
Release files / darkob-0.17.0.tar.gz
| Download URL | darkob-0.17.0.tar.gz |
|---|---|
| Size | 258.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7bd9b386e8987f47de94d347d4581e1e594dbe5a185aca174c8e3421cb197f95
|
|
BLAKE2b-256 checksum How to use checksums |
04d18eef3873fe2063da0ffb344aaec9241f818738e4c7921aac5c252752bdc8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 6, 2026.
Transparency logRelease files / darkob-0.17.0-py3-none-any.whl
| Download URL | darkob-0.17.0-py3-none-any.whl |
|---|---|
| Size | 399.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c35d13cc2912b0817f3a7178369bd847f312f6aee64c93bc9834a1aefe2c5919
|
|
BLAKE2b-256 checksum How to use checksums |
85490a4a49866d21096893031b916291df9d24395f0d83ccfd62154536faa2cf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 6, 2026.
Transparency logSecurity for darkob 0.17.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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for darkob-0.17.0.tar.gz
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 Nov 6, 2026.
Transparency logA 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.
To learn more about protecting yourself from malicious actors, visit our package security documentation.