한국어 · English
https://github.com/user-attachments/assets/04fa87b7-be54-4ff2-8064-503125abb336
handback
Previously developed as agent-relay; legacy state is detected with migration guidance.
A local tool for handing work between coding-agent apps and bringing the results back to the conversation where you started.
First task · Use-your-own-project guide · Detailed setup · Changelog
What is handback?
handback connects coding agents running on your computer. You work with one main conversation, called the Lead, and let it send a defined task to another conversation, called a worker. The relay creates the worker conversation, sends the task, and saves its reply in a local inbox for the Lead to review.
For example, you can discuss a change with Claude, have a Codex worker inspect the relevant code, and review its findings back in Claude. The apps perform the reasoning and coding; handback handles task delivery, result collection, and recovery.
When to use it / when not to
Use it to hand bounded tasks between different agent apps when results must survive interruptions without duplicate submission. Within one app, prefer its built-in subagents. This tool is not for teams, multiple machines, or parallel writes to one checkout.
Delegating heavy reading, investigation, and implementation to workers helps keep the Lead conversation small.
Why it exists
handback started from a simple wish: let the agent apps already on my computer talk to each other while I can still watch every conversation in the apps themselves. That is why a worker is a real conversation inside its own app, not a hidden subprocess. You can open it at any time and follow the work as it happens.
Working across multiple coding agents creates repeated handoffs: send the task, remember which conversation is working on it, find the answer, and bring it back to the original discussion. If a conversation closes or a wait times out, it can also become unclear whether a task finished or should be sent again.
handback gives each request an identity and keeps its result on disk. The Lead can retrieve an existing request after an interruption and mark a reviewed result as handled. This makes the handoff easier to follow and reduces the risk of submitting the same work twice.
It is intended for developers who already use multiple supported coding-agent apps and want to coordinate bounded tasks in their own projects. You still decide what work is allowed and review the results. A message from an agent is task information, never user authorization.
How a task moves
- You give the Lead a goal and limits, such as reviewing a module without changing files.
- The Lead delegates a task to a worker. The worker receives its own conversation and a brief describing the work.
- The relay collects the reply into an inbox. The saved result remains available if the Lead closes or collection is interrupted.
- The Lead reviews the result and acknowledges it. An acknowledgement, or ACK, marks it as handled so it stops replaying. The original message is retained.
You can also run these steps from a terminal. The first example below uses terminal commands so you can check the complete handoff before relying on automatic reception in an app.
Examples
Each worker is an ordinary conversation in its own app. While a task runs, you can open the Claude conversation and the Codex conversation side by side and read both as they work.
Delegate an investigation. Keep the Lead conversation small by sending the heavy reading to a worker.
Use the handback skill. Ask a Codex worker to read <module-path> and report how errors propagate, without changing files.
Cross-review a change. Have a different model check the work.
Use the handback skill. Send my last change to a Codex worker for review. Ask for concrete bugs only, with file and line.
Debate an idea to sharpen it. Two models with different blind spots argue the same question, and the Lead relays the rounds. In one real session, Claude and Codex compared two game-prototype plans over three rounds:
- Claude reviewed a planning document Codex had written. Codex accepted part of the review, rejected part of it, and left some points open pending tests.
- Claude, as Lead, sent a reply through handback to the Codex conversation that was already open. The reply marked each point as accepted, conditional, or still disputed, and asked four questions. Codex answered point by point. Both sides withdrew a weak claim. Three disputes remained, and Claude accepted Codex's wording for each.
- Claude asked Codex to write the agreement into the document. Then Claude checked the result against checksums taken before the edit and acknowledged both requests.
The outcome was a revised document with an agreement table and four open questions that only the user could answer. During the debate, the user could read each round in the Codex app as Codex wrote it. To try this, give the Lead the question, a round limit, and the format for the last answer:
Use the handback skill. Debate <topic> with the Codex conversation <thread-id> for at most three rounds. Each round, mark every point as agreed, disputed, or needing my decision. Don't edit files until the last round.
Supported combinations
| Lead | Workers | Result reception |
|---|---|---|
| Claude | Codex, Antigravity, or both | Monitor and explicit inbox reads; session recovery hooks where available |
| Codex | Antigravity only | External Codex queue, inbox, and ACK |
Start with Claude Lead → Codex worker. Claude workers, Codex Lead → Codex worker, Antigravity Lead, and automatic quota fallback are unsupported.
Windows has live integration coverage. macOS and Linux are unverified. App queue, transcript, and hook contracts can change with updates; see the verification summary for tested behavior and remaining gaps.
Install on Windows (no Python)
- Download
handback-<version>-setup.exefrom GitHub Releases. - Run it. If SmartScreen warns (the installer is unsigned), click 추가 정보 → 실행. No admin rights needed; it installs to
%LOCALAPPDATA%\Programs\handback, installs the agent skills, and offers two options: start with Windows (on by default) and a desktop icon (off). - handback opens when the install finishes. Next time, open handback from the Start menu.
handback.exe in the install folder is the command-line tool that agents and hooks use. The installer adds that folder to your user PATH, so handback works in any terminal opened after the install. Terminal users can run handback setup (also --yes, --dry-run).
Use it
-
Open your project in Claude (the Lead) and ask it to use the handback skill, for example:
Use the handback skill. Ask one Codex worker to review error handling in <module-path> without changing files, then summarize its findings here.
-
Open the handback app (the dashboard) to see running tasks and unread results. handback lives in the notification area (the ^ arrow near the clock), not on the taskbar: left-click its icon to show or hide the dashboard, right-click it for the menu, and choose 종료 there to exit. Right-click the dashboard for settings: 설정 (install or repair skills and recovery hooks in one place), start with Windows, install check, update, and per-project roles. The dashboard can set only Claude as Lead; set a Codex or Antigravity Lead from that app.
-
To check that the round trip works, right-click a project → 연결 테스트. This runs one real Codex worker task and uses model quota.
Update
The dashboard checks GitHub Releases once a day. When a newer version exists, right-click › 업데이트 설치 downloads the installer, verifies it against the release's SHA256SUMS.txt, upgrades in place, and reopens the dashboard (turn the check off under 보기 설정). You can also run the new handback-<version>-setup.exe yourself; it closes the dashboard and upgrades in place. Either way, setup reinstalls the skills and recovery hooks. To uninstall, use Windows 설정 › 앱 › handback. This removes autostart, the PATH entry, and handback's own hooks and skills (Claude, Codex and Antigravity); your ~/.handback data is kept.
Verify the download
Compare the installer's SHA256 with SHA256SUMS.txt on the release page:
Get-FileHash .\handback-<version>-setup.exe -Algorithm SHA256
Check the build provenance with the GitHub CLI:
gh attestation verify .\handback-<version>-setup.exe --repo Femur-0607/handback
For developers
Install with Python 3.10+ (pip, pipx, uv) or run from a source checkout. The sections through "Use it on your own project" are the CLI walkthrough.
Install from PyPI or source
Install the published package from PyPI:
pip install handback
From a source checkout, use pip install . to install the package, or run python handback.py directly without installation. For an isolated tool environment, uv tool install handback or pipx install handback also works; use . in place of handback to install the checkout. uv can provision Python when needed.
After installing the package, preview and install the agent skills:
handback install-skills --dry-run
handback install-skills
No runtime dependencies are installed. The optional handback-dashboard GUI requires a Python build with Tk support. handback --version prints the installed version.
handback install-skills --dry-run --target-home <absolute-test-home> previews an isolated installation without consulting host PATH or CODEX_HOME. Existing skills get timestamp backups. Claude is always installed; Codex and Antigravity require app detection, and Antigravity also requires a registered skill directory. Without --target-home, detection checks the known Windows app paths and PATH on all platforms. handback uninstall-skills [--dry-run] removes only the skill files that still point at this installation.
Packaged skills and hooks use the environment's absolute Python executable with -m handback. A direct, uninstalled checkout uses its absolute entry script instead, so hooks and workers also run from other project directories. Keep that environment (or checkout) available, and reinstall skills/hooks if you move it. Existing hook ownership manifests still support removing or upgrading old script-based hooks.
The source-only walkthrough below remains supported; install.ps1 is a thin wrapper around python handback.py install-skills. Package users can replace python "$relayScript" in later examples with handback.
Try your first task
Start with Claude Lead → Codex worker. Have these ready:
- Windows, PowerShell, and Python 3.10 or newer available as
python. - Git if you clone the repository, or an extracted source archive.
- Claude and Codex installed and signed in; start the apps before testing.
After installation, run this from your project in a normal terminal, outside an agent sandbox:
handback try
# From an uninstalled source checkout:
python handback.py try
try checks configuration and Codex detection, creates one read-only worker, sends a reply-only task, verifies its saved RELAY_OK result and request identity, then ACKs it. It prints the worker handle, request ID, elapsed time, result, and ACK status. It does not install skills or hooks. App detection alone does not verify login or queue compatibility; the task checks the round trip.
Use --root <path> for another project, --lead claude:<session-id> when selecting a new topology, --timeout 300 for the wait limit (default; 0 waits indefinitely), --keep to leave the result unread, or --json for machine output. An existing topology with a Codex worker is reused; an incompatible one is left untouched with a suggested use command. On timeout or unknown delivery, run the printed wait --request ... command; never resubmit.
What `try` does, step by step (manual setup and recovery)
The manual route below includes optional skill setup. Keep the same state home and PowerShell session throughout.
1. Get the tool and check your setup
git clone https://github.com/Femur-0607/handback.git
Set-Location handback
$relayRoot = (Get-Location).Path
$relayScript = Join-Path $relayRoot 'handback.py'
python --version
python "$relayScript" doctor --root "$relayRoot"
powershell -NoProfile -ExecutionPolicy Bypass -File .\install.ps1 -DryRun
If you downloaded an archive, open its extracted handback folder in PowerShell and continue from $relayRoot = .... No pip install is required. Review the diagnostic output and planned installation paths. doctor checks app availability; it does not prove a task can complete. See setup and troubleshooting if it reports a missing app or an existing-state warning.
2. Install the skills and select the Lead inbox
powershell -NoProfile -ExecutionPolicy Bypass -File .\install.ps1
$leadAddress = "claude:lead"
python "$relayScript" use --root "$relayRoot" --lead "$leadAddress" --workers codex
python "$relayScript" status --root "$relayRoot"
Check that status shows the Claude Lead and Codex worker combination. claude:lead is an inbox address for this first test; you do not need to discover a real Claude session ID to read its results manually. Session-specific recovery hooks require a real session ID later.
The installer writes agent skills and backs up existing skill files. It does not start the apps, a Lead conversation, or a watcher. Keep the checkout after installation because the installed skills refer to its files. The Windows default state home is %USERPROFILE%\.handback; if you already set HANDBACK_HOME, keep the same value throughout.
3. Send one small task
This command creates a real Codex worker conversation and sends one task:
python "$relayScript" new --worker codex --cwd "$relayRoot" --name "relay first task" --sandbox read-only --text "Do not modify files or delegate. Reply with RELAY_OK in this conversation." --no-wait
Save the returned JSON, especially request_id and handle. With --no-wait, a successful exit means the task was accepted; its result may still be pending. A detached collector gathers the reply.
4. Collect and review the answer
Replace the placeholder with the request_id returned above:
$requestId = "<request_id from the previous command>"
python "$relayScript" wait --root "$relayRoot" --request "$requestId" --timeout 300
python "$relayScript" inbox list --root "$relayRoot" --for "$leadAddress"
Check that the result belongs to this request and contains RELAY_OK. If waiting times out, keep this request ID and follow the recovery section below. Do not send the task again.
5. Mark the result as handled
Use the same request ID after reviewing its result:
python "$relayScript" inbox ack --root "$relayRoot" --for "$leadAddress" --request "$requestId"
python "$relayScript" inbox list --root "$relayRoot" --for "$leadAddress"
The handled result should disappear from the pending list while its original file stays on disk. You have now checked task submission, collection, review, and acknowledgement.
Use it on your own project
Install the relay once, then select the project you want to work on. The relay installation folder and your working project are separate paths. Keep $relayScript pointing to the installed tool, and set $projectRoot to your existing source folder:
$projectRoot = (Resolve-Path "<path-to-your-existing-project>").Path
python "$relayScript" use --root "$projectRoot" --lead "$leadAddress" --workers codex
python "$relayScript" status --root "$projectRoot"
Open that project in your Lead app and confirm the installed handback skill is available. Here is an example request to give a Claude Lead; replace both paths and the module name:
Use the handback skill for the project at <absolute-project-path>.
The relay script is <absolute-relay-installation>/handback.py.
Use claude:lead as the Lead inbox and Codex as the worker.
Ask one worker to review error handling in <module-path> without changing files.
Collect its result, review the findings, summarize them here, and ACK the result after review.
For terminal commands, use --cwd "$projectRoot" when creating a worker and --root "$projectRoot" for topology, status, waiting, and inbox commands. The worker works on that project. Use one worker conversation per unit of work and run units sequentially when they share a checkout. Send corrections to the same worker only after its previous request finishes.
For automatic results in a Claude conversation, have the Lead run inbox watch through its Monitor tool. A watcher in an ordinary terminal prints only to that terminal. Started with --idle-exit 1200, the watcher stops after 20 idle minutes; re-arm Monitor only while requests are open. If Monitor is unavailable, use explicit wait and inbox list commands. Fresh skill auto-loading and global recovery hook loading remain incompletely verified; the detailed setup guide covers these limits and the exact watcher command.
For Antigravity, register your working project in its app, enable its adapter, and install its relay hooks before selecting it. Follow the Antigravity setup; the Codex-only test above does not configure that combination.
Choose models and reasoning for each role
Codex Lead and worker defaults can be set separately for each project. The dashboard exposes the current combination's settings from a project row's context menu → 모델·추론 설정. From a terminal:
handback configure --root "<absolute-project-path>" --agent codex --role lead --model "<model-id>" --reasoning-effort ultra
handback configure --root "<absolute-project-path>" --agent codex --role worker --model "<model-id>" --reasoning-effort high
These defaults apply to new relay-created conversations. new --model ... --reasoning-effort ... overrides the selected role for one new conversation; Codex send accepts the same options and records the selection for subsequent relay turns. The native settings are persisted before queueing; changing the actual next turn of a conversation already loaded in the desktop app remains unverified because the app can retain runtime settings. Existing saved conversation settings take precedence over later role-default changes. Use --clear-model or --clear-reasoning-effort with configure to remove that role's override and inherit the shared agent setting or Codex's native configuration.
Role settings are saved outside the repository in project state. Shared defaults can also be set in <state-home>/config.json or project .handback.json using agents.codex.model and agents.codex.reasoning_effort; role overrides use agents.codex.lead and agents.codex.worker objects with the same fields. Relay command options take precedence over saved conversation settings, followed by role defaults, shared defaults, and native Codex configuration. Recognized effort values are none, minimal, low, medium, high, xhigh, max, and ultra; availability depends on the selected model and installed Codex build.
Antigravity workers support --model flash_lite|flash|pro for new conversations, including configure --agent antigravity --role worker --model pro. Its current agentapi interface exposes no reasoning option or model change for an existing conversation. Claude Lead settings remain in the Claude app. Settings for user messages entered directly in an app are controlled by that app; relay options describe relay creation and delivery.
Delivery and recovery
Submission, completion, Lead delivery, and ACK are separate events. An asynchronous submission returning success means the request was accepted. It does not mean the task finished.
Result did not come back
Start with doctor, then explain --request for the saved request ID. Both are read-only; explain ends with one next action and never sends, collects, or ACKs:
python "$relayScript" doctor --root "$projectRoot"
python "$relayScript" explain --root "$projectRoot" --request "<saved-request-id>"
python "$relayScript" wait --root "$projectRoot" --request "<saved-request-id>" --timeout 300
python "$relayScript" inbox list --root "$projectRoot" --for "$leadAddress"
Use the same project, Lead inbox, and state home as the original request. For the first test above, use $relayRoot instead of $projectRoot. wait recovers the existing request without submitting it again. Reading a result does not ACK it.
doctor prints OK/WARN/FAIL checks and one next step for each warning/failure (exit 5 for FAIL, 0 otherwise). doctor --json preserves the original JSON interface; explain --json provides the timeline as JSON. For an issue, copy the redacted block from doctor --report. status --stats --days 30 summarizes local request outcomes, latency, additional delivery attempts, and unACKed results without telemetry. Collection timeouts, recovery via wait, and explicit redeliveries are not independently recorded and cannot be counted reliably.
The detailed guide covers timeouts, replay, custom state homes, cleanup, and uninstall; the Korean manual describes the full command set and adapter limits.
Optional dashboard
Run handback-dashboard after package installation, or pythonw dashboard.pyw from a source checkout. The compact widget shows up to two lines of project names, running tasks, and unacknowledged results. +N turns yellow when the remaining projects have unread results. It checks activity every three seconds and preserves unchanged content and tooltips.
Drag the widget anywhere on the monitor, including over the taskbar and right to the screen edges. It follows the pointer freely, even when starting docked. Release inside a visible top or bottom taskbar with at least half of the widget overlapping it to snap into the taskbar's height and colour. Passing near the taskbar does not dock it, and pulling it out returns to floating placement. The floating widget has rounded corners and a grey outline on Windows; docking removes the outline and keeps the taskbar's separator visible. Only its initial position has an 8-pixel DPI-scaled margin above the taskbar. Position and docking state survive refresh and restart. When docked, it stays clear of the notification area when there is enough space. Both floating and docked widgets restore their position above Explorer if the taskbar covers them. The compact widget hides while a full-screen window covers its monitor, then returns when the window no longer covers it.
- Drag anywhere on the compact widget, including status counts. Clicking a count without dragging opens its conversation or selection menu. Click the widget background to open or close the expanded panel, and a project name in the panel to inspect running work and recent unread results. Long panels scroll, including pinned panels.
- Right-click → 보기 설정 to choose a floating widget (작은 위젯, the default), taskbar placement (작업표시줄에 넣기), or a pinned panel (펼친 패널 고정), change expanded-panel rows (펼친 패널 표시 줄 수), restore hidden projects, or reset the order. The compact widget stays at up to two lines.
- A project's context menu also offers 모델·추론 설정 ▶, 미확인 결과 모두 확인 처리 (ACK all unread results), and handback 등록 해제… (move inactive project state to
released/after confirmation). Display preferences, widget position, and docking state are saved in<state-home>/dashboard.json.
Left/right and auto-hide taskbars do not support docked mode; floating placement can use the full monitor. Multi-monitor placement and exclusive full-screen Direct3D behavior have unit-test coverage only. Conversation links open Codex threads; Claude and Antigravity links are disabled. See the dashboard limitations.
The dashboard is optional. handback dashboard --once prints a snapshot as JSON. handback dashboard --autostart on starts it at Windows login; --autostart off removes that shortcut. This does not start the Lead or its Monitor.
Dashboard memory measurements
The optional dashboard was measured on October 8, 2026, using Windows, Python 3.13.15, and Tk 8.6.15. These figures describe the dashboard process, excluding the separately running agent apps.
| Check | Observed result | Conditions |
|---|---|---|
| GUI footprint | About 33 MiB working set and 19 MiB private memory | A fresh process with a hidden window, 5 projects, no unread results, normal 3-second refresh, and a 15-second observation |
| Context-menu leak fix | Menu widgets, Tcl commands, Windows GUI resources, and handles stayed constant from 100 to 500 menu openings | Real Tk widgets with native popup display suppressed; the previous menu tree and its callbacks are destroyed before replacement |
| Large unread inbox | About 60.3 MiB peak additional Python heap; 2.7 seconds median per snapshot | Snapshot only, without Tk: 1,000 unread results with 60 KiB bodies plus 1,000 completed requests; 5 timed runs |
The large-inbox figure measures Python allocations, not total process memory, and timing can vary with concurrent filesystem activity. Refreshes scan stored history and load unread message bodies; showing fewer rows does not cap that work. Usage therefore depends on the amount of stored data and the environment. These short checks do not establish a memory limit or guarantee leak-free operation over hours or days.
Menu regression tests cover repeated menu creation, callback cleanup, current settings, and closing the dashboard. They use hidden Tk windows and skip when Tk or a display is unavailable.
Limitations
- Long-running Lead and reused worker conversations accumulate context; use bounded units and documented stage handoffs.
- Replacing the Lead preserves old requests' return addresses; explicitly read and ACK the old inbox.
- Windows has live verification; operation is local to one computer and OS user, with restricted agent combinations.
- App updates, uncertain delivery, and Monitor expiry require deliberate diagnostics and recovery; Antigravity cannot enforce read-only access.
- Shared-checkout work should be sequential, and dashboard scan cost grows with history. See known limitations and workarounds for details and commands.
Development
Implementation lives in handback/, the CLI entry point is handback.py, and tests are in tests/.
python -m unittest
Unit tests use isolated fixtures. They do not establish compatibility with a current app build; live integration results are tracked separately in the verification summary. See Contributing for test and bug-report requirements.
License
MIT. The license covers this repository's code; the agent applications are separately installed and retain their own licenses and terms.
Migrating a previous local installation
HANDBACK_HOME selects the state directory. Defaults are %USERPROFILE%\.handback
on Windows, ~/Library/Application Support/handback on macOS, and
${XDG_STATE_HOME:-~/.local/state}/handback on Linux. AGENT_RELAY_HOME is never
used as the new state setting. handback doctor warns about legacy state and prints
handback migrate-state --from '<old-state-path>'. Stop requests, collectors, and
watchers before copying. Migration verifies copied bytes, retains the original files,
and adds a MOVED.json receipt to prevent accidental writes to the old store.
Chained receipts are recognized when checking legacy stores, including an old
MSIX location moved through .agent-relay to .handback; keep HANDBACK_HOME
pointing to the final state home. This check does not migrate data automatically.
Reinstall hooks and skills with handback install-hooks and handback install-skills;
legacy hooks are recognized and original skill files receive timestamp backups.
Copy a legacy .agent-relay.json project policy to .handback.json. Until then the
legacy policy is read with a warning; when both exist, .handback.json takes precedence.
Metadata
Release files for handback 0.3.9
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 | |
|---|---|---|---|---|
| handback-0.3.9.tar.gz | 369.1 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| handback-0.3.9-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 625.3 kB
Release files / handback-0.3.9.tar.gz
| Download URL | handback-0.3.9.tar.gz |
|---|---|
| Size | 369.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5f1334627f6667c90782b0133e7e49959f77cce2236c00b9c788ba158768f607
|
|
BLAKE2b-256 checksum How to use checksums |
7f21a5859cdc3f05684f8addd3695ec6e0426147a2fdf1fbb22bdc579a88b6ff
|
| 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 Oct 19, 2026.
Transparency logRelease files / handback-0.3.9-py3-none-any.whl
| Download URL | handback-0.3.9-py3-none-any.whl |
|---|---|
| Size | 256.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
44af67ab0306a8739e8a6609d29617779d213a0265c59e563b23bc1601005fa6
|
|
BLAKE2b-256 checksum How to use checksums |
7957394c98366ba8d91f3c6eb61cbe6e67ec8c140ed8b627438efc8d89fd5e20
|
| 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 Oct 19, 2026.
Transparency logSecurity for handback 0.3.9
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 handback-0.3.9.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 Oct 19, 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.