๐ strands-icloud
One Strands tool for the entire Apple ecosystem. Mail, Calendar, Messages, Contacts, Photos, Notes, Reminders, Find My โ local-first on macOS, remote-capable via standard protocols, exposable over MCP.
Built for Strands Agents. Battle-tested inside devduck.
use_apple(action="messages.search", query="flight")
use_apple(action="mail.unread", limit=10)
use_apple(action="photos.search", query="drone") # โ returns REAL image blocks the model can SEE
use_apple(action="findmy.locate", device="iPhone")
Table of Contents
- Architecture
- Installation
- CLI
- Permissions Setup (macOS)
- Credentials & Keychain
- Action Reference
- MCP Server
- Parameter Reference
- Response Format
- Design Decisions
- Performance Notes
- Troubleshooting
- Security Model
- Known Limitations
Architecture
Two access layers, one dispatch surface:
flowchart TB
A["๐ use_apple(action=...)"]:::hub
A --> L
A --> R
A --> C
subgraph L["๐ฅ LOCAL ยท on-Mac ยท zero auth"]
direction TB
AS["AppleScript bridge<br/>Mail ยท Calendar ยท Contacts<br/>Notes ยท Reminders ยท Messages (send)"]
FS["Direct file access<br/>chat.db (SQLite, read-only)<br/>Photos library (osxphotos)"]
end
subgraph R["๐ REMOTE ยท anywhere ยท app-specific password โ"]
direction TB
IMAP["IMAP :993<br/>imap.mail.me.com"]
CAL["CalDAV<br/>caldav.icloud.com"]
CARD["CardDAV<br/>contacts.icloud.com"]
end
subgraph C["โ๏ธ CLOUD ยท pyicloud ยท real password + 2FA"]
FM["Find My<br/>devices ยท locate ยท play sound"]
end
classDef hub fill:#0a84ff,stroke:#0a84ff,color:#fff,font-weight:bold
classDef default fill:#1c1c1e,stroke:#3a3a3c,color:#f5f5f7
style L fill:#0e2a12,stroke:#32d74b,color:#f5f5f7
style R fill:#0b1f33,stroke:#0a84ff,color:#f5f5f7
style C fill:#2a0e1a,stroke:#ff375f,color:#f5f5f7
flowchart LR
subgraph clients["Consumers"]
DD["๐ฆ devduck<br/>(pipx inject)"]
SA["Strands Agent<br/>(pip install)"]
CC["Claude Code / Desktop<br/>Cursor ยท Kiro<br/>(MCP)"]
TERM["Terminal<br/>(uvx strands-icloud)"]
end
DD --> UA["use_apple"]
SA --> UA
CC -->|"strands-icloud-mcp<br/>stdio / HTTP"| UA
TERM -->|"CLI"| UA
classDef default fill:#1c1c1e,stroke:#3a3a3c,color:#f5f5f7
style UA fill:#0a84ff,stroke:#0a84ff,color:#fff,font-weight:bold
style clients fill:#000,stroke:#3a3a3c,color:#98989d
Why local-first? Your Mac already syncs everything via iCloud. Reading local data means zero auth, zero rate limits, zero Apple-breaking-the-API risk, and full history (Messages back to day one). Remote protocols are the fallback for headless/off-Mac deployments; pyicloud is only used where there is no local equivalent (Find My).
Module layout
strands_icloud/
โโโ __init__.py # exports use_apple
โโโ use_apple.py # @tool dispatch + all local backends (~850 lines)
โโโ remote.py # IMAP / CalDAV / CardDAV clients (stdlib imaplib + caldav + raw DAV)
โโโ mcp.py # MCP server entrypoint (strands-icloud-mcp)
โโโ cli.py # terminal CLI (strands-icloud / uvx strands-icloud)
Installation
Into devduck (pipx)
pipx inject devduck strands-icloud
# or from a local clone:
pipx inject devduck /path/to/strands-icloud
Register the tool (add to ~/.zshrc):
export DEVDUCK_TOOLS="$DEVDUCK_TOOLS;strands_icloud:use_apple"
Standalone (any Strands agent)
pip install strands-icloud
from strands import Agent
from strands_icloud import use_apple
agent = Agent(tools=[use_apple])
agent("what's on my calendar this week?")
Dependencies
| Package | Used for | Required? |
|---|---|---|
strands-agents |
@tool decorator |
yes |
osxphotos |
Photos library access | photos.* only |
pyicloud |
Find My | findmy.* only |
caldav |
CalDAV calendar client | caldav.* only |
keyring |
macOS Keychain credential lookup | optional (falls back to env) |
strands-mcp-server |
MCP entrypoint | MCP only |
Everything imports lazily โ a missing optional dep only disables its domain, never the whole tool.
CLI
Every action, straight from your terminal โ no agent required. Ships as the strands-icloud console script:
uvx strands-icloud reminders.list # zero-install, straight from PyPI
strands-icloud messages.search --query flight # or the installed script
Examples
# Messages
strands-icloud messages.chats -n 10
strands-icloud messages.search -q "baklava"
strands-icloud messages.send --to "+15517274110" --text "hey from the terminal"
# Mail โ local (Mail.app) or remote (IMAP, faster on big inboxes)
strands-icloud mail.unread -n 10
strands-icloud imap.search -q invoice --folder INBOX -n 5
strands-icloud imap.read -q 4762 # read by message ID
# Calendar โ local or CalDAV (syncs to all devices)
strands-icloud calendar.events --days 14
strands-icloud caldav.create --title "Dentist" --start "2026-07-25 14:30" --calendar Home
# Photos โ save image files locally
strands-icloud photos.search --label dog -n 3 --save ./out
strands-icloud photos.recent -n 5 --no-images # metadata only
# Everything else
strands-icloud contacts.search -q mom
strands-icloud notes.read -q "meeting"
strands-icloud findmy.locate --device iPhone
strands-icloud actions # list every available action
strands-icloud mcp --http --port 8010 # start the MCP server
# Machine-readable output
strands-icloud reminders.list --json | jq '.content[0].text'
CLI flags
| Flag | Maps to | Notes |
|---|---|---|
--query / -q |
query |
search text or message/note ID |
--limit / -n |
limit |
default 20 |
--chat / --folder |
chat |
chat filter (messages) or IMAP folder |
--calendar |
calendar_name |
|
--save DIR |
โ | write photo images to disk |
--no-images |
with_images=False |
metadata only, saves tokens/time |
--json |
โ | structured output (image bytes omitted) |
| all others | same-named param | --to --text --subject --body --title --start --end --due --days --person --label --device --from-date --to-date |
Exit code is 0 on success, 1 on error โ safe for scripting.
Permissions Setup (macOS)
macOS gates each data source separately. You need:
1. Full Disk Access (required: Messages, speeds up Mail)
System Settings โ Privacy & Security โ Full Disk Access โ add the app that hosts the Python process:
- Running in Terminal/iTerm/Ghostty โ add that terminal app
- Running as a launchd service โ add the Python binary itself
- Running inside an IDE โ add the IDE
Restart the process after granting. Without FDA, messages.* fails with unable to open database file.
2. Automation permissions (per-app, auto-prompted)
First time you call each domain, macOS shows "...wants to control Mail.app" โ click OK. One prompt per (host app ร target app) pair. These land in System Settings โ Privacy & Security โ Automation.
If you accidentally denied one:
tccutil reset AppleEvents # resets ALL automation grants
3. Photos library access
osxphotos reads the Photos SQLite directly โ covered by Full Disk Access. Export of edited/iCloud-offloaded originals may trigger a Photos permission prompt on first use.
Credentials & Keychain
App-specific password (IMAP / CalDAV / CardDAV)
Generate at account.apple.com โ Sign-In and Security โ App-Specific Passwords. Format: xxxx-xxxx-xxxx-xxxx.
Store it in macOS Keychain (recommended):
security add-generic-password -a "you@icloud.com" -s "strands-icloud" -w "xxxx-xxxx-xxxx-xxxx"
Then only the username goes in your shell config:
# ~/.zshrc
export ICLOUD_USERNAME="you@icloud.com"
Credential resolution order for remote protocols:
ICLOUD_PASSWORDenv var (if set โ e.g. CI, containers)- Keychain service
strands-icloud(viakeyring) - Keychain service
pyicloud(legacy compat) - โ error with instructions
Real password (Find My only)
pyicloud drives the iCloud web API, which uses Apple's GSA/SRP handshake โ app-specific passwords do not work there. If you want Find My:
security add-generic-password -a "you@icloud.com" -s "strands-icloud-real" -w "YOUR_REAL_PASSWORD"
Resolution order: ICLOUD_PASSWORD_REAL env โ keychain strands-icloud-real โ keychain pyicloud.
First login triggers 2FA once (run any findmy.* action interactively, or use the icloud CLI that ships with pyicloud). The session cookie is cached in ~/.pyicloud and lasts ~weeks.
Action Reference
Every action returns {"status": "success"|"error", "content": [{"text": ...}, ...]}. Photos actions append image blocks after the text block.
๐ฌ Messages
Backend: direct SQLite read of ~/Library/Messages/chat.db (opened mode=ro โ never locks Messages.app), AppleScript for sending. Full history, fast, works even if Messages.app is closed.
| Action | Params | Description |
|---|---|---|
messages.list |
chat (optional filter: name/number/email substring), limit |
Recent messages, chronological. chat matches chat_identifier, display_name, or handle |
messages.search |
query (required), limit |
Full-text LIKE search over all message text, all time |
messages.chats |
limit |
Conversations sorted by most recent activity, with message counts |
messages.send |
to (phone/email), text |
Sends via Messages.app. Tries iMessage participant first, falls back to generic buddy (SMS relay if configured) |
use_apple(action="messages.list", chat="+31638236164", limit=50)
use_apple(action="messages.search", query="baklava")
use_apple(action="messages.send", to="cagataycali@icloud.com", text="hey from my agent")
Timestamps are converted from Apple epoch (nanoseconds since 2001-01-01) automatically.
๐ง Mail (local โ Mail.app)
Backend: AppleScript. Mail.app must be running (open -gja Mail launches it hidden/background).
| Action | Params | Description |
|---|---|---|
mail.unread |
limit |
Unread from inbox. Scans newestโoldest, capped at 400 most recent (see Performance) |
mail.search |
query (required), limit |
Subject OR sender contains query. Uses Mail's whose filter โ slow on huge inboxes |
mail.read |
query (subject substring) |
Full body (plain text) of first matching email |
mail.send |
to, subject, body |
Composes and sends immediately via default account |
use_apple(action="mail.unread", limit=10)
use_apple(action="mail.read", query="Run failed: CI")
use_apple(action="mail.send", to="x@y.com", subject="hi", body="sent by agent")
๐ Calendar (local โ Calendar.app)
Backend: AppleScript across all calendars.
| Action | Params | Description |
|---|---|---|
calendar.events |
days (default 7), limit |
Upcoming events across every calendar |
calendar.create |
title, start (YYYY-MM-DD HH:MM), end (optional, default +1h), calendar_name (optional, default first writable) |
Creates event |
use_apple(action="calendar.events", days=14)
use_apple(action="calendar.create", title="Dentist", start="2026-07-25 14:30", calendar_name="Home")
๐ค Contacts (local โ Contacts.app)
| Action | Params | Description |
|---|---|---|
contacts.search |
query (name substring), limit |
Name, all phones, all emails |
๐ผ Photos โ osxphotos with image blocks
Backend: osxphotos reading the Photos library database directly. The killer feature: results include Bedrock Converse-API image content blocks, so the model literally sees the photos (same mechanism as strands_tools.image_reader).
| Action | Params | Description |
|---|---|---|
photos.search |
query, person, label, from_date/to_date (YYYY-MM-DD), limit, with_images |
All filters AND-combined. query matches filename/title/description/labels/persons/albums. person = Photos face names. label = Apple's on-device ML labels (e.g. "Baklava", "Document", "Sea") |
photos.recent |
limit, with_images |
Newest photos |
photos.albums |
โ | All album names |
use_apple(action="photos.search", person="mom", from_date="2026-01-01")
use_apple(action="photos.search", label="dog", limit=5)
use_apple(action="photos.recent", limit=3, with_images=False) # metadata only
Image pipeline: export original โ if HEIC/oversized, convert via sips to JPEG (quality 80, max edge 1600px) โ attach as {"image": {"format": ..., "source": {"bytes": ...}}}. Hard caps: max 5 images per response, 4 MB per image (context window protection). Exports land in /tmp/apple_photos_export/.
๐ Notes โ Notes.app
| Action | Params | Description |
|---|---|---|
notes.list |
limit |
Titles + modification dates (default account) |
notes.read |
query (title substring) |
Full plaintext of first match |
notes.create |
title, body |
New note in default account |
โ๏ธ Reminders โ Reminders.app
| Action | Params | Description |
|---|---|---|
reminders.list |
limit |
Incomplete reminders with due dates |
reminders.create |
title, due (optional) |
New reminder. Due date support is limited by AppleScript date quirks โ title always works |
๐ฑ Find My โ pyicloud
Requires real Apple ID password (see Credentials). Session cached after first 2FA.
| Action | Params | Description |
|---|---|---|
findmy.devices |
โ | All devices: name, model, battery %, coordinates |
findmy.locate |
device (name substring) |
Coordinates + Apple Maps link + accuracy + timestamp |
findmy.play_sound |
device |
Ping the device (the classic "find my phone in the couch") |
use_apple(action="findmy.locate", device="iPhone")
# ๐ รaฤatay's iPhone: (52.37403, 4.88969)
# https://maps.apple.com/?ll=52.37403,4.88969
๐ IMAP (remote โ imap.mail.me.com)
Backend: Python stdlib imaplib, SSL port 993. Works from any machine โ Linux server, container, CI. App-specific password is sufficient.
| Action | Params | Description |
|---|---|---|
imap.folders |
โ | List all mailboxes (INBOX, Archive, Sent Messages, ...) |
imap.search |
query, chat (=folder, default INBOX), limit |
Searches SUBJECT OR FROM OR BODY. Returns message IDs for imap.read |
imap.unread |
chat (=folder), limit |
UNSEEN messages |
imap.read |
query (=message ID from search results), chat (=folder) |
Full body. Prefers text/plain, falls back to tag-stripped HTML. All fetches use BODY.PEEK โ never marks messages as read |
Note:
chatis reused as the folder parameter to keep the tool signature lean.
๐ CalDAV (remote โ caldav.icloud.com)
| Action | Params | Description |
|---|---|---|
caldav.calendars |
โ | List calendars |
caldav.events |
days, limit |
Upcoming events across all calendars, expanded recurrences |
caldav.create |
title, start, end, calendar_name |
Create event โ syncs to all your Apple devices in seconds |
๐ค CardDAV (remote โ contacts.icloud.com)
| Action | Params | Description |
|---|---|---|
carddav.contacts |
query (optional name filter), limit |
Full addressbook via raw DAV: PROPFIND principal discovery โ addressbook-home-set โ REPORT addressbook-query โ vCard parse (FN/TEL/EMAIL) |
MCP Server
Everything above, exposed over the Model Context Protocol โ usable from Claude Code, Claude Desktop, Kiro, Cursor, or any MCP client. Pattern borrowed from strands-cad.
No install needed โ uvx strands-icloud with no arguments is the MCP stdio server:
uvx strands-icloud # stdio MCP server (default when no action given)
uvx strands-icloud mcp --http --port 8010 # streamable HTTP (multi-client)
uvx strands-icloud mcp --http --stateless # stateless HTTP (horizontally scalable)
Claude Code
claude mcp add apple -- uvx strands-icloud
Claude Desktop
{
"mcpServers": {
"apple": {
"command": "uvx",
"args": ["strands-icloud"]
}
}
}
Prefer pip?
pip install strands-icloud
strands-icloud-mcp # dedicated MCP entrypoint
strands-icloud-mcp --http --port 8010 # HTTP mode
strands-icloud-mcp --agent-invocation # also expose invoke_agent
strands-icloud-mcp --debug # verbose logging (stderr)
If installed inside a pipx venv, use the absolute path:
~/.local/pipx/venvs/devduck/bin/strands-icloud-mcp.
Implementation notes (learned the hard way in strands-cad)
- stdout is sacred in stdio mode โ it's the protocol channel. All logging goes to stderr.
- The server calls the raw tool function (
mcp_server._tool_func), notagent.tool.mcp_server(...). Going throughagent.tool.*marks the agent as mid-invocation; since stdio blocks forever, every nested tool call would then be rejected by the SDK. --agent-invocationis off by default: tools-only surface. Enable it to let MCP clients run full agentic conversations against an embedded Strands agent.
Verified handshake
initialize โ serverInfo: strands-agent (1.27.x)
tools/list โ ["use_apple"]
tools/call use_apple(action="reminders.list")
โ โ๏ธ 3 open reminders: ...
Parameter Reference
Full signature โ every param is optional except action:
| Param | Type | Default | Used by |
|---|---|---|---|
action |
str | โ | everything (required) |
query |
str | None | search actions, mail.read, notes.read, imap.read (=msg ID) |
to |
str | None | messages.send, mail.send |
text |
str | None | messages.send |
subject, body |
str | None | mail.send, notes.create |
title |
str | None | calendar.create, notes.create, reminders.create, caldav.create |
chat |
str | None | messages.list (chat filter), imap.* (folder name) |
person, label |
str | None | photos.search |
device |
str | None | findmy.* |
calendar_name |
str | None | calendar.create, caldav.create |
start, end |
str | None | event creation, YYYY-MM-DD HH:MM |
due |
str | None | reminders.create |
from_date, to_date |
str | None | photos.search, YYYY-MM-DD |
days |
int | 7 | calendar.events, caldav.events |
limit |
int | 20 | all list/search actions |
with_images |
bool | True | photos.* โ set False for metadata-only (saves tokens) |
Response Format
# text-only actions
{
"status": "success",
"content": [{"text": "๐ง 5 unread:\n- [...] ..."}]
}
# photos with images โ text block first, then image blocks
{
"status": "success",
"content": [
{"text": "๐ผ 3 photos:\n- IMG_4321.HEIC | 2026-07-21 12:59 | labels: Baklava, ..."},
{"image": {"format": "jpeg", "source": {"bytes": b"..."}}},
...
]
}
# errors are never raised โ always structured
{
"status": "error",
"content": [{"text": "chat.db not found at ..."}]
}
Design Decisions
- One mega-tool, dot-namespaced actions (
use_apple(action="messages.search")) instead of 25 separate tools. Keeps the agent's tool list small, matches theuse_aws/use_spotify/adbconvention, and lets one docstring teach the model the entire surface. - Local-first, remote-fallback. AppleScript + direct file reads beat any network API for latency, history depth, and reliability. Remote protocols exist for off-Mac deployment of the same tool.
- Read-only by default at the storage layer. chat.db opens with
?mode=ro; IMAP fetches useBODY.PEEK. Writes only happen through explicit send/create actions via Apple's own apps/APIs. - Graceful degradation. Optional deps import lazily inside the action branch. No osxphotos? Photos actions error cleanly with install instructions; everything else works.
- Structured errors, never exceptions. The agent can read the failure and route around it (e.g., fall back from
mail.unreadtoimap.unread). - Image budget. Max 5 images ร โค4 MB, auto-downscaled to 1600px JPEG q80. A photo dump should never blow up the context window.
Performance Notes
| Operation | Cost | Notes |
|---|---|---|
messages.* (read) |
~10 ms | Direct SQLite, indexed |
mail.unread |
2โ30 s | AppleScript iteration, newest-first, capped at 400 recent messages. The naive whose read status is false filter took >120 s on a 16k inbox โ that's why it scans instead |
mail.search |
10 sโ3 min | Uses Mail's whose filter (server-side in Mail), acceptable but not instant on big inboxes. Prefer imap.search for speed |
imap.search |
1โ3 s | iCloud does the searching |
calendar.events |
5โ60 s | AppleScript iterates every calendar; slow with many calendars. caldav.events is usually faster |
photos.search |
5โ30 s first call | osxphotos loads the library DB once per call; big libraries pay upfront. Filtering itself is in-memory and fast |
caldav/carddav |
1โ5 s | Plain HTTPS |
Rules of thumb: Messages โ local always. Mail search โ IMAP. Calendar list โ CalDAV. Photos โ local (only option). Sends โ local (Apple handles delivery).
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
unable to open database file on messages.* |
No Full Disk Access | Grant FDA to host app, restart the process |
Timeout on mail.* |
Mail.app not running or gigantic inbox | open -gja Mail, wait for index; use imap.* instead |
Not authorized to send Apple events |
Automation permission denied | System Settings โ Automation, or tccutil reset AppleEvents |
PyiCloudFailedLoginException on findmy.* |
Using app-specific password | pyicloud needs the real password (keychain strands-icloud-real) |
| 2FA loop on findmy | Expired session | Re-auth interactively once; check ~/.pyicloud is writable |
imap.* AUTHENTICATIONFAILED |
Bad/revoked app-specific password | Regenerate at account.apple.com, update keychain entry |
| Photos export returns nothing | Original offloaded to iCloud ("Optimize Mac Storage") | Tool retries with use_photos_export=True (slower, downloads); ensure disk space |
| Keychain prompt blocks headless run | keyring needs UI unlock | security unlock-keychain in session, or use env vars for that host |
| MCP client sees no tools | stdout polluted by a print | Run with --debug, check nothing but JSON-RPC goes to stdout |
Nuclear option for AppleScript weirdness: quit and relaunch the target app.
Security Model
- App-specific password (keychain
strands-icloud): grants mail/calendar/contacts via legacy protocols. Revocable at account.apple.com anytime without touching your real password. Cannot be used to log into iCloud web, change account settings, or access Find My. - Real password (keychain
strands-icloud-real, optional): only needed for Find My. Never written to disk by this tool; keychain access requires your login session. - No plaintext secrets in dotfiles: only
ICLOUD_USERNAMElives in~/.zshrc. - Local data never leaves the machine except as tool results into your model provider (mind what you query if using a cloud LLM โ that's the actual data boundary here).
- chat.db is opened read-only; the tool physically cannot modify or delete message history.
Known Limitations
- macOS only for local actions (AppleScript, chat.db, osxphotos). Remote actions (
imap.*,caldav.*,carddav.*) run anywhere Python does. reminders.createdue dates: AppleScript date construction is unreliable across locales; reminders are created without due dates for now.messages.sendrequires Messages.app signed in; SMS relay needs an iPhone with Text Message Forwarding enabled.mail.unreadscans the 400 most recent inbox messages โ unread mail older than that won't appear (useimap.unreadfor exhaustive).- Group chat display names in Messages may be empty (falls back to chat identifier).
- pyicloud is an unofficial client of a private API โ Apple can (and occasionally does) break it. Local + DAV paths are unaffected.
- HEIC โ JPEG conversion via
sipsloses HDR/depth metadata (irrelevant for model vision).
Development
git clone git@github.com:cagataycali/strands-icloud.git
cd strands-icloud
uv venv && source .venv/bin/activate
uv pip install -e .
# smoke test without an agent
python -c "
from strands_icloud.use_apple import use_apple
fn = getattr(use_apple, '_tool_func', use_apple)
print(fn(action='reminders.list', limit=3))
"
# reinject into devduck after changes
pipx inject devduck . --force
License
MIT ยฉ รaฤatay รalฤฑ
Metadata
Release files for strands-icloud 0.2.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 | |
|---|---|---|---|---|
| strands_icloud-0.2.0.tar.gz | 26.7 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| strands_icloud-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 55.2 kB
Release files / strands_icloud-0.2.0.tar.gz
| Download URL | strands_icloud-0.2.0.tar.gz |
|---|---|
| Size | 26.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f0044dec5a9a8d7e13b18e0adc587e3bb5d51308d5ee27c36cbf21faaf33f48c
|
|
BLAKE2b-256 checksum How to use checksums |
a805845ef93489a52c8699f4afeebd4aae8aaa9b0392a2b1127e1c1d90aee47a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.11
|
Release files / strands_icloud-0.2.0-py3-none-any.whl
| Download URL | strands_icloud-0.2.0-py3-none-any.whl |
|---|---|
| Size | 28.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
58c310cd6fb30595ff1a956944b7cee1c087bcedef49a4be382d045bc0c7bbdd
|
|
BLAKE2b-256 checksum How to use checksums |
887c665fab3a665eff738b75fb7c1ba954c8df1361307125e9985a37bd4cddfa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.11
|
Security for strands-icloud 0.2.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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
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.