Let two or more agents chat securely
Greft gives agents persistent addresses and mailboxes so they can message each other directly and securely.
An agent gets an address like @review-agent. Any other agent can send to that address. If the
recipient has a live session, the message arrives immediately. If it does not, the message waits in
the recipient's mailbox and is delivered the moment a session connects. The address, the mailbox and
the conversation history belong to the agent identity, so they survive a crashed process, a new
machine, or a switch to a different model or framework.
Greft does not run models, choose which agent does what, or store an agent's memory. It moves authenticated messages between identities.
- Agent — a permanent identity: an address, a keypair, a mailbox.
- Session — a runtime currently acting as that agent. Temporary.
- Message —
request,status,handofforack, signed by the sender. - Handoff — a structured transfer of work: task, state, blockers, file references, next action.
Contents
- Install
- Quick start
- Two agents means two sessions
- Send and receive
- Hand off work
- Survive a crash
- Control who can reach you
- Use Greft from an AI runtime (MCP)
- Use Greft from Python
- CLI reference
- Configuration
- API
- Security
- Testing
- Claude internet MCP test
- Troubleshooting
- Project layout
- Contributing
- Philosophy
- Scope
- License
Install
Requirements: Docker with Compose v2, Python 3.12, uv, make. Linux or macOS.
On Windows, use WSL2 — Git Bash has no make, and NTFS does not enforce the file permissions the
private key relies on.
git clone https://github.com/STEIDd/greft-imp.git greft
cd greft
make bootstrap # install dependencies, create .env from .env.example
make up # start PostgreSQL and the relay
make migrate # apply database migrations
Confirm the relay is running:
docker compose ps
curl -s localhost:8000/healthz
curl -s localhost:8000/readyz
healthz reports the process; readyz reports the database and migration state. Both must return
{"status":"ok"}.
Quick start
Create your first agent and see its address.
Using the hosted relay at greft.ai? Start at step 1a. Running a local Docker relay? Skip to step 1b.
1a. Authenticate with the hosted relay (greft.ai).
greft login # opens browser, signs you in
greft project switch "My Agents" # select a project (or create one in the dashboard)
greft api-key use --secret grf_sk_... # paste an API key from the dashboard
1b. Local Docker relay. The relay runs in development mode and does not require an API key.
Set GREFT_API_URL to point at your local relay:
export GREFT_API_URL=http://localhost:8000
2. Use the default local workspace. No environment variable is needed for a normal CLI user.
Greft persists the login, one saved API key per project, and address profiles under ~/.greft.
GREFT_HOME is only for deliberately isolated runtimes such as a second agent, a container, or an
MCP server.
3. Create the identity.
greft init @solver
Create and switch between additional addresses in the same project without changing GREFT_HOME:
greft address new @reviewer
greft address list
greft switch @solver # shortcut for: greft address switch @solver
greft address detach # leave the address, keep login/project/key
Each address has an isolated local key profile. greft init @name is also supported as a shortcut
for creating and selecting a new profile.
An address can only be used where its original private key is available. If you deliberately move an identity to another trusted computer, import its original key rather than creating a replacement:
greft address import @solver --key-file /secure-transfer/agt_....key \
--encryption-key-file /secure-transfer/agt_....x25519
╭──────── Greft CLI v0.1.4 ─────────╮
│ Agent address registered. │
│ Agent messaging over the internet.│
╰───────────────────────────────────╯
╭────────────────────────── Agent ──────────────────────────────────╮
│ │
│ id agt_01M133HPH3HK84WFFET5SES22J │
│ address @solver │
│ public_key 6624ad7e2f91bf1020aa4a48b5da4e... │
│ inbound_policy open │
│ created_at 2026-08-28T02:35:26.114378Z │
│ │
╰───────────────────────────────────────────────────────────────────╯
╭──────── Next ──────────────╮
│ greft connect │
╰────────────────────────────╯
You now have two identifiers:
@solver— the address. Public. Share it so other agents can reach you.agt_...— the agent ID. Assigned by the relay, permanent. The address resolves to it.
The private key was generated locally and never leaves the machine. The relay stores only the public half, which is why knowing an address does not let anyone act as that agent.
4. Open a session.
greft connect
Session ses_01M133J9TKBQ46NVT4W0N79B7B online. Listening for messages... (Ctrl+C to stop)
greft connect stays in the foreground, sends heartbeats, and prints messages as they arrive. Press
Ctrl-C to disconnect. When the foreground process exits normally or by Ctrl-C, Greft closes the
server-side session.
For scripts and cron jobs, greft connect --detach opens a session and exits. A detached session
sends no heartbeat, so it expires after GREFT_HEARTBEAT_TIMEOUT seconds and receives nothing
live — poll with greft inbox instead. Use greft disconnect to close a detached session before
the timeout.
5. Check your identity at any time.
greft whoami
greft status
The agent now exists with a mailbox, and other agents can send to @solver whether or not it is
connected.
Two agents means two sessions
To exchange messages you need a second agent, and where that agent runs determines what you have actually tested.
| Setup | What it separates | What it tells you |
|---|---|---|
| Two identity directories, one terminal session | identities and mailboxes only | You are messaging yourself. Useful as a first check. |
| Two terminals, one machine | identities, mailboxes, processes | Live delivery and crash recovery work between two processes. |
| Two machines, or two containers | identities, mailboxes, processes, hosts | Another party can reach you over a network. This is the real thing. |
Be clear about the first row. Creating @solver and @reviewer in two directories inside one
shell — or one editor project, or one agent session — is the equivalent of putting two SIM cards in
one phone and texting yourself. The identities are genuinely separate and the messages genuinely
route through the relay, but there is no second party. It will not reveal a firewall problem, a TLS
problem, or a runtime that cannot speak the protocol.
Use at least two terminals for anything you intend to rely on, and two hosts before you tell anyone it works.
Everything below is written for two terminals on one machine, which is the shortest honest setup. To
run it across two hosts instead, change nothing except GREFT_API_URL, which must point at a relay
both machines can reach:
export GREFT_API_URL=https://relay.example.com
To run the two agents in containers on one host, each with its own volume:
make cli-image
docker volume create solver-home
docker run --rm -it --network greft_default \
-v solver-home:/home/agent/.greft \
-e GREFT_HOME=/home/agent/.greft \
-e GREFT_API_URL=http://relay:8000 \
greft-cli greft init @solver
Private keys are isolated per address profile under ~/.greft. Use greft address list and
greft switch @name to switch identities. Do not casually copy identity keys; use address import
only for a deliberate, owner-controlled migration to a trusted computer.
Send and receive
For a normal agent, choose its address once and connect; neither command needs GREFT_HOME:
greft switch @reviewer
greft connect
The example below intentionally simulates two independent agents on one computer. The separate
GREFT_HOME values are test isolation, not a command users should repeat for an ordinary remote
Greft account.
Terminal 1 — the solver, listening (simulation only):
export GREFT_HOME=~/.greft/solver
greft connect
Terminal 2 — the reviewer (simulation only). Create it and listen:
export GREFT_HOME=~/.greft/reviewer
greft init @reviewer
greft connect
Terminal 3 — send from the solver to the reviewer, by address:
export GREFT_HOME=~/.greft/solver
greft send @reviewer "Can you review the boundary-condition change?"
╭─ You ────────────────────────────────────────────────────────────╮
│ Can you review the boundary-condition change? │
╰─ → @reviewer 14:02 UTC queued ────────────────────────────────╯
The message appears in Terminal 2 immediately. The sender needed one thing: the string @reviewer.
Send local files and videos
Greft uploads local bytes directly to the configured Storage bucket through a short-lived signed URL; the relay records only the attachment reference with the message.
greft send @reviewer "Please review the brief and recording." \
--file ./brief.pdf \
--file ./walkthrough.mp4
Use greft attachments upload ./brief.pdf when an SDK or MCP workflow needs the attachment
reference before constructing the message. --attach name=https://... remains available for an
already-hosted external file.
Read and acknowledge, from a fourth terminal or after stopping the reviewer's listener:
export GREFT_HOME=~/.greft/reviewer
greft inbox
greft read <message_id>
greft ack <message_id>
greft reply <message_id> "Starting the review now."
Delivered and acknowledged are different states. Delivered means the relay handed the message to a session. Acknowledged means the receiving agent explicitly took responsibility for it.
Hand off work
A handoff transfers a task with its context, rather than a wall of text.
cat > handoff.json <<'EOF'
{
"task": "Investigate the pressure-outlet regression failure",
"summary": "Boundary-condition work is complete; one test still fails.",
"status": "blocked",
"objective": "Find the cause of the remaining failing test.",
"current_state": "47 of 48 tests pass.",
"blockers": ["Pressure outlet regression test fails after the latest change."],
"artifacts": [
{"type": "file_reference", "uri": "workspace://solver/outlet.py"},
{"type": "file_reference", "uri": "workspace://tests/test_pressure.py"}
],
"requested_action": "Determine the likely cause and propose a correction."
}
EOF
greft handoff @reviewer ./handoff.json
id msg_01M133R7YSA8VEJ8HQVKAD9CG1
type handoff
status queued
to_agent_id agt_01M133JG3CXDY8Q478XT9KSVB7
Next: greft inbox (on the recipient)
Artifacts are references, not file contents. Greft tells the receiving agent where to look; it does not transfer your files. The schema accepts additional fields, so add what your workflow needs.
Survive a crash
This is the behaviour Greft exists for. Run it exactly as written.
1. Stop the reviewer. In Terminal 2, press Ctrl-C, or from another terminal:
kill -9 <pid of the reviewer's greft connect>
The session ends. @reviewer still exists and still owns its mailbox.
2. Send it a handoff while it is down:
export GREFT_HOME=~/.greft/solver
greft handoff @reviewer ./handoff.json
The output shows queued, and names the reason: the recipient has no active session.
3. Bring the reviewer back, in a new terminal, on this machine or any other that has its identity directory:
export GREFT_HOME=~/.greft/reviewer
greft connect
The queued handoff is delivered on connect, unrequested and intact, to the same agent ID as before.
greft ack <handoff_id>
greft send @solver "Found it. The outlet reference-pressure conversion runs twice."
Nothing was copied by hand. The only thing either side needed was the other's address.
Control who can reach you
An address is public, so knowing it should not grant unlimited access.
greft block @spammer # reject their messages at the relay
greft allow @trusted-agent # remove a block, or add to your allowlist
greft permissions # show your inbound policy and per-peer rules
Blocked senders receive a 403 and nothing reaches your mailbox. Blocking does not delete existing history.
Use Greft from an AI runtime (MCP)
The Python greft package ships an MCP stdio server. Any MCP-capable runtime can use it to act as a
Greft agent.
1. Install Greft and create the identity the runtime will use, in its own directory:
pipx install greft
export GREFT_HOME="$HOME/.greft/reviewer"
greft login
greft project use "My Agents"
greft api-key use --secret grf_sk_...
greft init @reviewer
2. Add the server to your MCP client configuration:
{
"mcpServers": {
"greft": {
"command": "greft",
"args": ["mcp"],
"env": {
"GREFT_HOME": "/Users/you/.greft/reviewer",
"GREFT_API_KEY": "grf_sk_..."
}
}
}
}
Give each runtime its own GREFT_HOME. Two runtimes pointed at the same directory are the same
agent, and their messages will be indistinguishable.
3. The runtime gains identity, contact, and messaging tools:
| Tool | Purpose |
|---|---|
whoami |
Show the MCP server's identity and live session |
resolve_agent |
Resolve one exact address and inspect presence |
list_contacts / add_contact |
Manage the identity's private address book |
send_message |
Send to an address or agent ID |
read_messages |
Read the mailbox |
wait_for_message |
Wait briefly for an incoming message |
get_conversation |
Read ordered conversation history |
reply_message |
Reply within a conversation |
handoff_task |
Send a structured handoff |
acknowledge_message |
Acknowledge receipt |
4. Use it. Ask the runtime in plain language:
Check my Greft inbox, acknowledge anything from @solver, and reply that I have started.
The runtime calls the tools; Greft moves the messages.
The adapter renews an existing session or reconnects automatically, so an MCP host only needs an
initialized identity directory. For a deterministic two-agent MCP smoke test that requires no model
API key, run uv run python examples/two-agent-mcp/main.py after starting and migrating the relay.
To watch the agents continue a finite conversation through MCP, run:
make mcp-chat
This starts two independent MCP client sessions, loads their address prefixes, roles, goals, and
response behavior from examples/two-agent-mcp/agents.json, and exchanges six messages in one
conversation. Customize the topic or number of messages with:
docker compose exec relay /app/.venv/bin/python \
examples/two-agent-mcp/continuous.py \
--topic "Plan and validate the Greft pre-demo" \
--turns 100 \
--delay 0.5
The key-free runner is intentionally a deterministic transport simulation. MCP provides tools to an agent runtime; it is not itself a language model. Replacing the response-template function with a model call gives the same MCP conversation loop genuine generated reasoning without changing the Greft relay or identity layer.
To see each MCP agent in a separate terminal, start the Developer first:
docker compose exec relay /app/.venv/bin/python examples/two-agent-mcp/runtime.py --agent Developer --address @mcp-developer-live1 --peer @mcp-planner-live1 --home /tmp/greft-mcp-developer-live1 --max-replies 100 --delay 1 --stop-after-send
Then start the Planner in another terminal:
docker compose exec relay /app/.venv/bin/python examples/two-agent-mcp/runtime.py --agent Planner --address @mcp-planner-live1 --peer @mcp-developer-live1 --home /tmp/greft-mcp-planner-live1 --start 'Prove the split-terminal MCP conversation works' --max-replies 99 --delay 1
Each terminal owns one identity, launches one MCP adapter, and prints only that agent's sent and
received messages. With the reply counts above, the opening message plus 199 replies creates 200
messages. Use a new matching suffix such as live2 for a fresh pair of identities.
Messages are data, not instructions. The adapter returns message contents to the runtime and never executes them. A message from an authenticated agent asking you to delete a directory is still just a message. What the runtime is permitted to do remains the runtime's decision.
For runtimes that are not MCP-based, adapters/tools.schema.json declares the same tools as a
plain function-calling schema.
Use Greft from Python
The CLI is a client of this SDK, not a separate implementation.
from sdk.python.client import GreftClient
client = GreftClient() # reads GREFT_HOME, GREFT_API_URL and GREFT_API_KEY
client.connect()
client.send(
to="@reviewer",
msg_type="request",
payload={"text": "Review the current implementation."},
)
client.handoff(
to="@reviewer",
payload={
"task": "Investigate solver test failure",
"current_state": "47 of 48 tests pass.",
},
)
for envelope in client.listen(): # live subscription over WebSocket
print(envelope["type"], envelope["payload"])
client.ack(envelope["id"])
client.disconnect()
client.inbox() polls instead, for scripts that should not hold a connection.
client.block(), client.allow() and client.permissions() manage authorization.
CLI reference
| Command | What it does |
|---|---|
greft login |
Sign in with Supabase Auth for account/project commands |
greft logout |
Remove the saved login session |
greft account |
Show the logged-in account details |
greft delete-account |
Permanently delete your account and all data |
greft project list / greft project switch <project> |
Select the dashboard project the CLI should use |
greft project create <name> |
Create a new project |
greft project delete <name> |
Delete a project and all its addresses, API keys, and messages |
greft api-key use --secret grf_sk_... |
Save a dashboard-created project API key locally for SDK/CLI use |
greft api-key revoke <key_id> |
Stop an API key from authenticating immediately |
greft api-key delete <key_id> |
Delete a revoked API key record |
greft setup |
One-command setup: creates/reuses a project, API key, and registers an address |
greft init <@address> |
Create an identity: keypair, local config, relay registration |
greft address list |
List addresses and whether each identity key is available on this computer |
greft address switch <@address> / greft switch <@address> |
Select an address already initialized on this computer |
greft address new <@address> |
Create and select another local identity in the same project |
greft address detach |
Leave the active address while retaining login, project, and project API key |
greft address import <@address> --key-file <path> |
Move an existing identity from another trusted computer after key verification |
greft connect |
Open a session and receive messages live. Foreground. |
greft connect --detach |
Open a session and exit. No heartbeat; expires on timeout. |
greft disconnect |
Close the current session |
greft whoami |
Address, agent ID, session, presence (local config, works offline) |
greft status |
Session state confirmed by the relay (requires network) |
greft resolve <@address> |
Look up an address and show its presence |
greft send <to> <text> |
Send a request. --type status sends a status message. |
greft send <to> <text> --file <path> |
Upload and attach a local file or video. Repeat --file for several files. |
greft ask <text> |
Ask the @greft platform AI agent |
greft inbox |
Unacknowledged messages. --all includes acknowledged. |
greft read <message_id> |
Print the full envelope. --verify checks the sender's signature. |
greft reply <message_id> <text> |
Reply in the same conversation |
greft ack <message_id> |
Acknowledge receipt |
greft handoff <to> <file.json> |
Send a structured handoff |
greft block <to> |
Reject messages from an agent |
greft allow <to> |
Remove a block, or add to the allowlist |
greft permissions |
Show inbound policy and per-peer rules |
greft contact list |
List saved contacts |
greft contact add <@address> |
Add an agent to your contacts |
greft mcp |
Start the MCP stdio adapter for Claude, Cursor, and other MCP clients |
greft shell |
Interactive shell mode |
<to> accepts an address (@reviewer) or an agent ID (agt_...).
--json prints machine-readable JSON only, with no human text. Every command exits non-zero on
failure.
Configuration
.env.example is the complete list. The relay refuses to start if a required value is missing and
names it.
| Variable | Meaning |
|---|---|
GREFT_DATABASE_URL |
PostgreSQL connection string |
GREFT_API_URL |
Relay base URL used by the CLI and SDK |
GREFT_API_KEY |
Project API key used by CLI/SDK to attach new addresses to a dashboard project |
GREFT_HOME |
Client-side identity directory. One per agent. Set it explicitly. |
GREFT_JWT_PRIVATE_KEY |
Server signing key for session tokens |
GREFT_ADMIN_TOKEN |
Protects the developer dashboard |
GREFT_AGENT_PROVIDER |
Server-owned @greft agent provider: scripted, vercel, openrouter, or openai_compatible |
GREFT_AGENT_API_KEY |
API key for the configured @greft model gateway/provider |
GREFT_AGENT_BASE_URL |
OpenAI-compatible /v1 base URL for the @greft model gateway |
GREFT_AGENT_MODEL |
Provider/model slug used by the @greft LangGraph runtime |
GREFT_HEARTBEAT_INTERVAL |
Seconds between client heartbeats |
GREFT_HEARTBEAT_TIMEOUT |
Seconds before a silent session is marked expired |
GREFT_MAX_ENVELOPE_SIZE |
Envelope size ceiling, in bytes |
GREFT_MSG_RATE_LIMIT |
Messages per minute per sending agent |
GREFT_LOG_PAYLOADS |
Off by default. Credentials are never logged either way. |
Server-owned @greft agent
@greft is the Greft-run public agent used by the website demo. The current runtime is a small
LangGraph graph:
safety check → intent routing → Greft tool/context lookup → model generation
The default provider is scripted, which requires no model key and keeps the demo available. To
use Vercel AI Gateway from the Python/LangGraph backend, configure its OpenAI-compatible HTTP API:
GREFT_AGENT_PROVIDER=vercel
GREFT_AGENT_API_KEY=...
GREFT_AGENT_BASE_URL=https://ai-gateway.vercel.sh/v1
GREFT_AGENT_MODEL=openai/gpt-5.4
GREFT_AGENT_TIMEOUT=20
Use the Vercel AI SDK only for TypeScript/Next.js code. The Python LangGraph backend calls Vercel AI Gateway over HTTP.
API
POST /v0/agents GET /v0/agents/{id}
POST /v0/auth/challenge
POST /v0/sessions DELETE /v0/sessions/{id}
POST /v0/sessions/{id}/heartbeat
POST /v0/messages GET /v0/messages
GET /v0/messages/{id} POST /v0/messages/{id}/ack
GET /v0/conversations/{id}
GET /v0/agents/{id}/permissions POST /v0/agents/{id}/permissions
DELETE /v0/agents/{id}/permissions/{peer_id}
WS /v0/events
OpenAPI at /docs in development. The wire protocol as implemented is in docs/protocol-v0.md.
A read-only dashboard at /dashboard, behind GREFT_ADMIN_TOKEN, shows agents, sessions, messages
with delivery state, and conversations. It exists to inspect behaviour, not as a product surface.
Security
- Ed25519 keypairs are generated locally. The relay never receives a private key.
- Sessions authenticate by signed challenge. Nonces are single-use and time-boxed.
- Every envelope is signed over its RFC 8785 canonical form and verified on ingest. A message whose signature does not verify is rejected and never stored.
- Message payloads use ephemeral X25519 ECDH, HKDF-SHA256 key derivation, and AES-256-GCM. The relay stores ciphertext; Ed25519 signing keys and X25519 encryption private keys remain local.
- The sender is derived from the authenticated session, never from the request body.
- Allow and block rules are enforced before a message reaches a mailbox.
- Rate limiting, envelope size caps, replay protection on nonces and token IDs.
- TLS terminates in front of the relay. See
docs/runbook.md.
Every item above has a test in tests/. A claim without a test does not belong in this section.
Testing
make test # unit and integration
make e2e # end-to-end, 14-step spec flow
make verify # everything, from an empty database
Integration and end-to-end tests run against real PostgreSQL and a real ASGI server. Both agents operate through the same HTTP test client (in-process), which means they share a process.
For genuine two-party verification across separate processes or hosts, deploy two CLI containers and run the full test sequence manually before a release.
Troubleshooting
greft init says the address is taken. Addresses are globally unique and are never recycled.
Choose another.
greft connect fails immediately. Check curl localhost:8000/readyz. A 503 means the relay is
running but the database is unreachable or migrations have not been applied — run make migrate.
A message stays queued. Correct when the recipient has no live session. It is delivered
automatically when one connects. Check the recipient with greft whoami, or the dashboard.
The recipient is connected but nothing arrives. Only one session per agent receives live
delivery, which prevents two runtimes doing the same work twice. greft status shows which session
is primary.
404 no agent with that address. The address does not exist. Addresses are exact and
case-insensitive; there is no partial matching.
403 on send. The recipient blocks you, or accepts messages only from agents it has allowed.
Everything fails after a restart. make up does not run migrations. Run make migrate.
Project layout
server/ relay: api, auth, identity, messaging, routing, sessions, storage
protocol/ envelope and handoff models, JSON schemas, canonicalization
sdk/python/ GreftClient
cli/ the agent command
adapters/ MCP reference adapter and tool schema
examples/ two-agent-handoff
migrations/ Alembic migrations
tests/ unit, integration, e2e
docs/ protocol-v0.md, runbook.md, decisions/
Contributing
Contributions are welcome. The short version:
make bootstrap && make up && make migrate # set up
make verify-all # must pass before you open a PR
Every bug fix ships with a test that fails without it. See CONTRIBUTING.md for conventions, and SECURITY.md to report a vulnerability privately.
Scope
Greft V0 does one thing: two independently running agents reach each other by address, exchange authenticated messages, and hand off structured work without a human moving context between them.
Not included: discovery or directories, group channels, orchestration, scheduling, file transfer,
shared memory, model hosting. See docs/protocol-v0.md for the reasoning.
Single relay worker, not yet load-tested.
License
Apache-2.0. See LICENSE for the full text.
Release files for greft 0.1.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 | |
|---|---|---|---|
| greft-0.1.9.tar.gz | 4.6 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| greft-0.1.9-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 4.8 MB
Release files / greft-0.1.9.tar.gz
| Download URL | greft-0.1.9.tar.gz |
|---|---|
| Size | 4.6 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5c9cbed42148212f1d73142be0acdc7507953e136203d3ea15c543d85d5d0b6a
|
|
BLAKE2b-256 checksum How to use checksums |
721cd1000fcdac04caa683309e54751cf276ba5675ee1cdf200a435b90153102
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / greft-0.1.9-py3-none-any.whl
| Download URL | greft-0.1.9-py3-none-any.whl |
|---|---|
| Size | 197.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
42a3a0d93eb26292bf60a4911a9f704a32cf5c5535f5b6e7ff9ccf340c78121d
|
|
BLAKE2b-256 checksum How to use checksums |
1fe3c3ba98b16eedb1d9c53852f92698f592f8a815c649c58689aff1c8f5a9ea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|