Skip to main content

tahuti: ManageBac CLI, Python SDK & Event Engine

An unopinionated, robust toolkit for ManageBac: typed Python SDK, command-line interface, Model Context Protocol (MCP) server for AI assistants, and a near-real-time event streaming and webhook engine.

Supports both international (managebac.com) and China (managebac.cn) instances.


Core Capabilities

  1. Unopinionated Python SDK (ManageBacClient, ManageBacDaemon):
    • Authenticate seamlessly via credentials or saved session cookies (ManageBacClient.from_config()).
    • Programmatic access to tasks, submissions, calendar feeds, weekly timetables, and MNN notifications.
    • Clean separation of concerns: produces pure, typed data with zero vendor-specific assumptions or hardcoded push rules.
  2. Interactive CLI (tahuti login, tahuti list, tahuti view, tahuti class, tahuti grades, tahuti submit, tahuti daemon):
    • Fast terminal workflows for everyday student tasks: listing assignments, checking overall grades and category weights, viewing details, uploading files, checking schedules, and managing background daemons.
    • Smart output formatting: human-friendly colored tables on interactive TTYs, structured JSON when piped to files or other tools (jq).
  3. MCP Server for AI Coding Assistants:
    • Built-in Model Context Protocol server (tahuti-mcp) with 13 tools for AI assistants like Claude Desktop, Gemini, and Cursor to inspect deadlines, grades, and coursework.
  4. Event Streaming & Webhook Engine:
    • In-process async event streaming (async for event in daemon.stream()) for Python bots and background tasks.
    • Background daemon service (tahuti daemon run --webhook-url ...) dispatching typed MBEvent payloads to HTTP webhooks with HMAC-SHA256 signatures, exponential backoff retries, stealth jitter, and active-hours scheduling.
    • For the full event contract and JSON schema, see Event Stream Specification. For operational push notification setups (such as Bark for iOS), see Downstream Notifier Guide.

Delivery is polling-based, not push. No WebSocket or server-sent-event transport exists in tahuti, and the MNN hub endpoint ManageBac publishes is an HTTPS origin rather than a socket URL — so there is nothing to subscribe to. The daemon polls the ManageBac Notification Network (MNN) Hub REST API on a configurable interval — poll_interval_seconds (default 30s) plus a random poll_jitter_seconds (default 0-5s) — and emits events from the delta between successive polls. Expect latency of roughly one poll interval after an event appears on ManageBac. The hub endpoint attribute is scraped from the notifications page and used only to obtain the hub JWT and to derive the REST base URL; it is not a socket URL. See the notification transport findings for the full investigation.


Disclaimer

Use at your own risk. This tool is an unofficial, community-maintained client and scraper. It is not affiliated with or endorsed by Faria Education Group or ManageBac. By using this tool, you acknowledge and accept the following:

Faria/ManageBac's legal documents restrict automated access:

  • robots.txt (managebac.com): Disallows /login, /admin, /api for all user agents.
  • Terms of Use §1.2.6: "Accounts registered by 'bots' or screen scrapers and/or other automated means are not permitted and access will be terminated without notice."
  • Terms of Service §5.5: "Misuse of the Service, including but not limited to reverse engineering... may result in permanent and/or temporary suspension or termination of the School's account."
  • Terms of Service §1.4: Violations may result in account termination without notice.
  • Terms of Service §9.4: Schools exceeding 200 GB/month bandwidth may face caps or additional invoices.

The authors bear no responsibility for any consequences resulting from its use, including account suspension or school-level penalties. You are solely responsible for ensuring your use complies with your school's policies and ManageBac's Terms of Service.


Installation

pip install .

The console commands are tahuti and tahuti-mcp. The pre-rename mb and mb-mcp are kept as aliases, so existing scripts, shell aliases and MCP client configs keep working — this document uses the new names throughout.

The tahuti-mcp MCP server needs one extra dependency. mcp is not a runtime dependency of the tahuti CLI, so a plain pip install . leaves tahuti-mcp failing with ModuleNotFoundError: No module named 'mcp':

pip install "tahuti[mcp]"

Or install in editable mode for local development:

pip install -e .
pip install -e ".[mcp]"

This is also a uv project, with the test dependencies kept out of the published runtime environment in a dev dependency group:

uv sync --group dev     # pytest + requests-mock + the mcp extra
uv run pytest

Python SDK Quickstarts

📖 Full Library Reference: For complete method signatures, parameter types, status enums, MNN Hub integration, and production recipes, see docs/library.md.

1. Basic Client Usage (ManageBacClient)

Use ManageBacClient for synchronous fetching and actions:

from tahuti import ManageBacClient

# Option A: Authenticate automatically from saved local CLI credentials
client = ManageBacClient.from_config()

# Option B: Explicit authentication
# client = ManageBacClient(school="your-school", domain="managebac.com")
# client.login("student@example.com", "your-password")

# 1. Fetch upcoming tasks and coursework
tasks_data = client.crawl_all(fetch_details=True)
for task in tasks_data.get("upcoming", []):
    print(f"[{task.get('due_date')}] {task.get('title')} ({task.get('class_name')})")

# 2. View one task in detail
task_detail = client.get_task_detail("/student/classes/1000024/core_tasks/1000025")
if task_detail:
    print(task_detail.get("description"))

# 3. View calendar events
events = client.get_calendar_events(start="2026-09-01", end="2026-09-07")

# 4. Fetch weekly timetable
timetable = client.get_timetable()

# 5. Upload homework file to assignment dropbox
client.submit_file(
    class_id="1000023",
    task_id="1000026",
    file_path="homework.pdf",
)

2. Async Event Streaming (ManageBacDaemon)

Use ManageBacDaemon.stream() to consume ManageBac events asynchronously in your Python application. Events are produced by polling on the interval you configure, so treat the first event after a change as arriving within one poll cycle rather than instantly:

import asyncio
from tahuti import ManageBacClient, ManageBacDaemon

async def main():
    # Load authenticated client
    client = ManageBacClient.from_config()

    # Create daemon instance (crawling runs in worker threads, non-blocking)
    daemon = ManageBacDaemon(client, poll_interval_seconds=60)

    print("Subscribed to ManageBac event stream (Ctrl+C to stop)...")
    async for event in daemon.stream():
        print(f"\n[Event: {event.event} @ {event.timestamp}]")
        
        if event.event == "task_created":
            print(f"  📝 New Task: {event.data.get('title')}")
            print(f"     Class: {event.data.get('class_name')}")
            print(f"     Due: {event.data.get('due_date')}")
            print(f"     URL: {event.data.get('url')}")
            
        elif event.event == "deadline_approaching":
            print(f"  ⏰ Deadline Warning: {event.data.get('title')}")
            print(f"     Threshold: {event.data.get('reminder_threshold')}")
            print(f"     Remaining: {event.data.get('time_remaining_minutes')} mins")
            
        elif event.event == "task_graded":
            print(f"  📊 Grade Released: {event.data.get('title')}")
            print(f"     Score: {event.data.get('grade_letter')} {event.data.get('grade_score')}")

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("\nDisconnected from event stream.")

Event Webhook Engine

tahuti includes a background daemon that dispatches polled events to HTTP webhook receivers (e.g. local scripts, microservices, or custom bots):

# Run daemon in foreground with webhook dispatching
# Pass the secret via the environment so it does not appear in `ps` output
# or your shell history.
export MB_WEBHOOK_SECRET="your-hmac-secret"
tahuti daemon run --webhook-url http://127.0.0.1:8000/webhook --secret "$MB_WEBHOOK_SECRET"

# Or configure webhook URL persistently and run daemon.
# `start` only detaches when you pass -b/--background; without it the loop runs
# in the foreground and dies with your terminal.
tahuti daemon configure-webhook http://127.0.0.1:8000/webhook
tahuti daemon start -b --interval 1800 --active-hours-start 7 --active-hours-end 23

# Test the webhook connection with a mock ping
tahuti daemon test-webhook http://127.0.0.1:8000/webhook

Verify the signature. The daemon signs every payload with HMAC-SHA256, but a receiver that ignores X-MB-Signature accepts forged events from anything that can reach its port. The bundled receiver in extras/mb-notifier/ requires --secret (or MB_WEBHOOK_SECRET) and refuses unsigned, replayed, or stale pushes. Write your receiver the same way.

Webhook HTTP Contract

  • Method: POST

  • Headers:

    • Content-Type: application/json; charset=utf-8
    • User-Agent: tahuti-daemon/1.0
    • X-MB-Event: <event_type> (e.g. task_created, task_graded)
  • Signing: X-MB-Signature: sha256=<hex_hmac> (when --secret is configured).

    BREAKING PROTOCOL CHANGE. The HMAC covers the timestamp and the body:

    signed_material = f"{X-MB-Timestamp}.".encode("utf-8") + request_body
    expected = "sha256=" + hmac.new(secret, signed_material, hashlib.sha256).hexdigest()
    

    Previously it covered the body alone, which left X-MB-Timestamp unauthenticated: anyone who captured a single POST could replay it indefinitely by rewriting that header, because the original digest still validated and the receiver's freshness check passed. Receivers built against the body-only construction reject every payload until they add the timestamp to the signed material. The bundled receiver in extras/mb-notifier/ is updated in the same commit; check any receiver of your own against the construction above. The . delimiter keeps ts=17 + body="89ab" from colliding with ts=1789 + body="ab".

  • Retry Mechanism: Exponential backoff (1s, 2s, 4s) on network or server errors (5xx, 408, 429). Other 4xx are permanent and are not retried.

  • Specification: See docs/events.md for full payload schemas and documentation.

Latency and polling interval. Events are detected by polling, so a receiver sees a new task or grade after the daemon's next cycle, not at the moment ManageBac publishes it. Inside an active window the cycle sleeps poll_interval_seconds + random(0, poll_jitter_seconds) (defaults 30s and 5s, so 30-35s); the jitter keeps request timing irregular rather than a fixed cadence. tahuti daemon run sets this with --poll-interval, tahuti daemon start with --interval. Lower it if you want tighter detection, but each cycle issues authenticated requests to ManageBac — an aggressive interval raises the risk of rate limiting or account flagging. There is no push channel to subscribe to instead; see the notification transport findings in docs/events.md.

Active hours gate the polling, they do not throttle it. With no active_windows configured the daemon polls around the clock. Set --active-hours-start / --active-hours-end (or an active_windows entry in the daemon JSON) and the loop sleeps outside the window instead of polling — useful for keeping a school-hours-only notifier from hammering ManageBac overnight. --once ignores the window: one cycle always runs.


Interactive CLI Reference

# Authentication & Session
tahuti login --school your-school --domain managebac.com -e student@example.com
tahuti login --keep-credentials            # also save the password for silent renewal
tahuti login --keep-credentials --keychain # keep it in the OS keychain, not a file
tahuti login --no-remember-me              # omit remember_me from the login POST
tahuti --version                       # print the installed version and exit
tahuti logout                             # forget this profile's session + password
tahuti logout --all                       # every profile's, plus the legacy file
tahuti logout --keep-credentials          # keep the saved password
tahuti logout --purge                     # ...and forget the profile's school/domain/email

# Tasks & Coursework
tahuti list                             # list upcoming tasks
tahuti list --view past                 # past tasks
tahuti list --subject "Math"            # filter by class/subject
tahuti list --view overdue --details    # overdue tasks with full descriptions
tahuti view 1000025                    # view single task by ID
tahuti view 1000025 --feedback         # view single task with teacher feedback inline
tahuti view "https://your-school.managebac.com/student/classes/1000024/core_tasks/1000025"

# Classes & Grade Composition
tahuti class                            # overview table of all enrolled classes & overall grades
tahuti class calc                       # class metadata, overall grade, category weights & scale
tahuti class view 11516148              # view class grade composition by numeric ID
tahuti grades                           # grades scoreboard across all enrolled classes
tahuti grades -s "Calculus"             # view grade composition for a specific subject
tahuti grades --composition             # full category breakdown across all enrolled classes

# File Submission & Teacher Feedback
tahuti submit 1000026 homework.pdf     # upload file to assignment dropbox
tahuti feedback 1000026                # fetch teacher feedback for a submitted task

# Notifications & Feed
tahuti notifications                    # list MNN notifications (page 1)
tahuti notifications --unread-only      # unread only
tahuti notifications --read 235151424   # mark notification as read
tahuti notifications --unread 235151424  # mark it unread again
tahuti notifications --read-all         # mark all notifications read

# Schedule & Calendar
tahuti calendar                         # calendar events for next 7 days
tahuti calendar --today                 # today's events
tahuti calendar --ical -o calendar.ics  # export raw iCal feed
tahuti timetable                        # view weekly class timetable

# Background Daemon
tahuti daemon run --webhook-url http://127.0.0.1:8000/webhook  # foreground loop, Ctrl+C to stop
tahuti daemon start -b                 # detached background loop (-b / --background)
tahuti daemon start                    # foreground loop; dies with your terminal
tahuti daemon start --once             # run one check cycle and exit
tahuti daemon stop                     # stop background loop
tahuti daemon status                   # show daemon process status
tahuti daemon install                  # register an auto-start service (launchd/systemd)
tahuti daemon uninstall                # remove the auto-start service
tahuti daemon configure-channel qq 123456789  # deliver via a zeroclaw channel instead of HTTP

tahuti daemon start does not background by default. Without -b / --background the polling loop runs in the foreground and terminates when your terminal closes. start -b re-executes itself as tahuti daemon run in a new session, writes the child's PID to ~/.config/tahuti/daemon.pid, and appends output to ~/.config/tahuti/daemon.log (both 0600). Override either location with --pid-file / --log-file: start and status accept both, stop accepts only --pid-file, and install accepts only --log-file.

--interval and --poll-interval are the same flag. daemon start historically spelled it --interval and daemon run --poll-interval; both names are now accepted on both commands, so a command copied between the two keeps working. They share one destination, so passing both is not an error — the last one on the line wins. start -b forwards whichever you used to the detached child as --poll-interval.

--daemon-config is not --config. The daemon subcommands above read their webhook URL, interval, and active-hours window from a separate JSON file selected with --daemon-config — it is not the ManageBac config.json that --config selects, and the two are not interchangeable.

Output Formatting

  • Interactive TTY: Formatted tables with color highlights.
  • Piped / Non-TTY: Structured JSON output.
  • Explicit Override: Add --format pretty or --format json to any command.
  • Environment Override: Set TAHUTI_FORMAT=json or TAHUTI_FORMAT=pretty to pin the shape for a script that runs sometimes with and sometimes without a terminal (cron, CI, tee). --format still wins over the environment, and the environment wins over the TTY probe. The pre-rename MB_CLI_FORMAT is still read as a fallback, so an existing script does not break; if both are set, TAHUTI_FORMAT wins.
  • Streams: Standard output (stdout) is reserved for command data; logs and progress go to standard error (stderr).

Configuration Files

By default, tahuti stores credentials and daemon states in ~/.config/tahuti/:

  • config.json — School domain, preferences, and webhook settings
  • session.json — Authenticated session cookies and tokens
  • creds.json / creds.<profile>.json — Plaintext ManageBac password, written only by tahuti login --keep-credentials, so an expired cookie can be renewed without a prompt. The default profile keeps the plain creds.json name; every other profile gets its own file.
  • snapshot.json — Coursework state cache for delta detection
  • daemon.log / daemon.pid — Background daemon runtime files
  • cache/ — Cached HTTP responses, including grade pages and the MNN hub JWT
  • daemon_state.json — Notification/reminder dedup state

Every file holding a credential or personal data is written with 0600 and the directory with 0700. On startup tahuti warns on stderr if a creds file, session.json, or config.json is found group- or world-readable, since file permissions are the only barrier protecting a cleartext password. Set MANAGEBAC_NO_PERM_WARN=1 to silence it.

The session is saved; the password is not, unless you ask. Every successful tahuti login writes session.json (the cookie), so you are not asked for your password on every command. Nothing writes your password to disk unless you pass --keep-credentials:

Command session.json password
tahuti login written not written
tahuti login --keep-credentials written written
tahuti login --no-remember-me written not written

--no-remember-me only omits remember_me from the login POST, so the cookie's lifetime is ManageBac's default rather than a requested persistent one. It is a server-side setting and composes with --keep-credentials.

The cost of the default is one password when the cookie expires: with no stored password, a command run after that fails with missing_credentials naming tahuti login --keep-credentials rather than prompting (a prompt would hang a daemon or a CI job). Pass --keep-credentials once and later commands renew the session by themselves.

tahuti logout deletes creds.json and any OS-keychain entry, as well as clearing the session cookie and the response cache. Pass logout --keep-credentials if you want silent re-login preserved instead.

None of those touch configuration itself: the school, domain, email and defaults in config.json survive a logout, so the next command still knows which school to talk to. tahuti logout --purge removes those settings too, so the machine forgets the saved account completely. --purge implies credential deletion, so combining it with --keep-credentials is refused rather than silently doing one or the other.

To keep the password out of the cleartext file entirely, combine --keep-credentials with the OS keychain:

tahuti login --keep-credentials --keychain   # or: MANAGEBAC_KEYCHAIN=1

This stores the password in the macOS Keychain or Linux Secret Service via the security / secret-tool helpers already on the system — no extra dependency, and nothing is stored if you do not ask for it. --keychain decides only where a kept password goes, never whether it is kept. If the keychain is unavailable (for example a headless Linux box with no secret service), tahuti falls back to the cleartext file with a warning rather than losing the credential. See SECURITY.md for the limits of both backends.

--config <file> and --session-file <file> override the default config and session paths, as do the environment variables MANAGEBAC_CONFIG, MANAGEBAC_SESSION, and MANAGEBAC_CREDS_PATH. These come from the shared auth-flag helper, so they exist on the task, calendar, and submission commands — and on daemon run / daemon start, which do log in to ManageBac. They are not on the purely process-level daemon commands, which act on the daemon and its own JSON settings rather than on your login. Where those need a path they take --daemon-config (on run, stop, test-webhook, configure-webhook, and configure-channel) and/or --pid-file / --log-file (start and status take both, stop takes only --pid-file, install takes only --log-file); uninstall takes no path flag at all.

Secrets may also be supplied through the environment, which keeps them out of your shell history and out of ps output:

  • MB_WEBHOOK_SECRET — HMAC secret for signing webhook payloads. Preferred over --secret when both are set.
  • MANAGEBAC_PASSWORD — ManageBac password.
  • MANAGEBAC_COOKIE — _managebac_session cookie value.
  • MANAGEBAC_KEYCHAIN — set to 1 to keep a password stored by --keep-credentials in the OS keychain instead of the cleartext creds file (equivalent to tahuti login --keychain). Decides where, never whether.
  • MANAGEBAC_NO_PERM_WARN — set to 1 to silence the loose-permission warning.

The old MB_CRAWLER_* spellings still work. MB_CRAWLER_CONFIG, MB_CRAWLER_SESSION, MB_CRAWLER_CREDS_PATH, MB_CRAWLER_PASSWORD, MB_CRAWLER_COOKIE, MB_CRAWLER_KEYCHAIN and MB_CRAWLER_NO_PERM_WARN are read as deprecated fallbacks, so an existing systemd unit, CI job or shell profile keeps authenticating. The new name wins when both are set, and an exported-but-empty value counts as unset either way. They are deprecated and will go; move to MANAGEBAC_* when convenient.

MANAGEBAC_PASSWORD and MANAGEBAC_COOKIE are read back as input as well as exported into the daemon child, so a non-interactive run needs no prompt:

MANAGEBAC_PASSWORD=... tahuti daemon run       # no prompt, secret not in argv
MANAGEBAC_COOKIE=... tahuti list --format json # cookie straight from the env

A password from the environment is never written to disk. It is input for this run, not a request to store it: only tahuti login --keep-credentials writes a password, whatever the source. So MANAGEBAC_PASSWORD=... tahuti list authenticates and leaves no creds.json behind — and, by the same token, does not leave a renewal path behind either.

An explicit --password / --cookie takes precedence over the environment, and an exported-but-empty value is treated as unset. tahuti daemon start -b still copies them into the detached child's environment so the secret never travels in argv. The trade-off: a leaked environment variable is now directly usable as a credential, and a process's environment is readable by its own user.


MCP Server (AI Coding Assistants)

tahuti includes a built-in Model Context Protocol (MCP) server for integration with Claude Desktop, Cursor, Gemini, and other AI agents:

tahuti-mcp

Example Claude Desktop Configuration

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "managebac": {
      "command": "tahuti-mcp"
    }
  }
}

The MCP server exposes 13 tools: list_tasks, view_task, submit_file, delete_submission, get_teacher_feedback, get_notifications, mark_notification, mark_all_notifications_read, get_calendar_events, get_ical_feed, get_timetable, list_classes, and get_class_grades.


Downstream Integrations

tahuti intentionally avoids coupling itself to specific push providers, notification line limits, or personal course naming conventions. Instead, downstream consumers subscribe to events and apply customized logic:

  • Event Stream Specification: Full specification of the event data contract, lifecycle states, and JSON payloads.
  • Downstream Notifier Guide: Operational guide for deploying extras/mb-notifier (Bark push alerts, 3-field / 4-line mobile screen budgeting, course aliases, and sound customization).
  • HTTP Revalidation Findings: Which endpoints answer If-None-Match with 304 and which never can, why the server's ETag is useless on the Rails HTML pages, and the six nonce classes a client-side content hash has to strip to be stable.

Stability Note

This tool interfaces with ManageBac via automated HTTP requests and HTML parsing. If ManageBac updates its frontend layout, CSS selectors, or internal API structures, scrapers may require updates.


Changelog & Security

Release history follows Keep a Changelog in CHANGELOG.md. For reporting a vulnerability privately, see SECURITY.md — it also documents exactly which credentials are stored on disk and in what form.


License

MIT

Metadata

Release files for tahuti 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tahuti 0.5.0
File Size Uploaded Provenance Actions
tahuti-0.5.0.tar.gz 441.4 kB With provenance Details for tahuti-0.5.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for tahuti 0.5.0
File Interpreter ABI Platform Actions
tahuti-0.5.0-py3-none-any.whl Python 3 none any Details for tahuti-0.5.0-py3-none-any.whl

Total release size: 622.8 kB

Release files / tahuti-0.5.0.tar.gz

Download URL tahuti-0.5.0.tar.gz
Size 441.4 kB
Tags Source
SHA-256 checksum
How to use checksums
0e963b52879312c0e6256e641e0f66400c95969d85a608b6e82d130051113d14
BLAKE2b-256 checksum
How to use checksums
660c86abe5daf5844b688f8eab1b6e890453ec0d1d69ac7763763f044c82e6a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.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 Sep 23, 2026.

Transparency log

Release files / tahuti-0.5.0-py3-none-any.whl

Download URL tahuti-0.5.0-py3-none-any.whl
Size 181.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
00190408964c6b3b29827228ca53d9f1ffeb7460764c572ad188798c157555d3
BLAKE2b-256 checksum
How to use checksums
583895f0b2b15f8c5c12e8371a93bd4814c286b46fcc9973002d3980589eab87
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.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 Sep 23, 2026.

Transparency log

Security for tahuti 0.5.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.

Select from 2 files

Attestation for tahuti-0.5.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 Sep 23, 2026.

Transparency log

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.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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