Tinfoil Python Library
A Python client for secure AI model inference through Tinfoil.
Installation
# With uv
uv add tinfoil
# With pip
pip install tinfoil
Usage
The Tinfoil SDK automatically selects a router enclave and verifies it against the official GitHub repository. You just need to provide your API key:
import os
from tinfoil import TinfoilAI
client = TinfoilAI(
api_key=os.getenv("TINFOIL_API_KEY")
)
chat_completion = client.chat.completions.create(
model="llama3-3-70b",
messages=[
{
"role": "user",
"content": "Hi",
}
],
)
print(chat_completion.choices[0].message.content)
Inspecting verification
The verified release, measurements, attested keys, verifier version, and local verification completion time are available from the client:
document = client.get_verification_document()
print(document.release_tag) # None for pinned or bundled verification
print(document.release_digest)
print(document.code_fingerprint)
print(document.enclave_fingerprint)
print(document.verifier)
print(document.verified_at)
verified_at is recorded from the local clock after every successful
verification or re-verification. It is not an attested evidence timestamp or a
freshness guarantee.
Audio Transcription with Whisper
You can transcribe audio files using OpenAI's Whisper model:
import os
from tinfoil import TinfoilAI
client = TinfoilAI(
api_key=os.getenv("TINFOIL_API_KEY")
)
with open("audio.mp3", "rb") as audio_file:
transcription = client.audio.transcriptions.create(
file=audio_file,
model="whisper-large-v3-turbo",
)
print(transcription.text)
Async Usage
Simply import AsyncTinfoilAI instead of TinfoilAI and use await with each API call:
import os
import asyncio
from tinfoil import AsyncTinfoilAI
client = AsyncTinfoilAI(
api_key=os.getenv("TINFOIL_API_KEY")
)
async def main() -> None:
stream = await client.chat.completions.create(
model="llama3-3-70b",
messages=[{"role": "user", "content": "Say this is a test"}],
stream=True,
)
async for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content is not None:
print(chunk.choices[0].delta.content, end="", flush=True)
print()
asyncio.run(main())
Functionality between the synchronous and asynchronous clients is otherwise identical.
Low-level HTTP Endpoints
You can also perform arbitrary GET/POST requests that are verified:
import os
from tinfoil import NewSecureClient
api_key = os.getenv("TINFOIL_API_KEY")
tfclient = NewSecureClient()
# GET example
resp = tfclient.get(
"https://example.com/health",
headers={"Authorization": f"Bearer {api_key}"},
params={"query": "value"},
timeout=30,
)
print(resp.status_code, resp.text)
# POST example
payload = {"key": "value"}
resp = tfclient.post(
"https://example.com/analyze",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
},
json=payload,
timeout=30,
)
print(resp.status_code, resp.text)
Prompt Cache Scoping
The inference router partitions prompt-prefix caches using both the authenticated API identity and user_cache_secret. Cache reuse requires the same identity, secret, model, and matching prompt prefix. Changing the identity or secret selects a different cache namespace, so those requests do not share cache entries or cache-hit timing.
user_cache_secret is sensitive application data used only for cache partitioning. It is not an API credential or encryption key. Do not log or expose it unnecessarily: a caller who can send requests with the same API identity and secret joins that cache namespace and can observe its cache-hit timing. The SDK adds it to eligible request bodies before they are protected for transport to the verified enclave.
By default, the SDK generates a random secret and persists it at ~/.tinfoil/user_cache_secret, requesting mode 0600 where supported. Tinfoil SDKs using the same home directory reuse this value. This default is suitable for a single-user application, but it does not separate end users who share one application process or home directory. You can control the scope explicitly:
from tinfoil import TinfoilAI
# Pin a stable, non-empty, opaque secret for this client.
client = TinfoilAI(api_key=api_key, user_cache_secret=secret)
# Or provision it via the environment
# TINFOIL_USER_CACHE_SECRET=<secret> use this value
# Multi-user services should scope every request to its end user;
# a non-empty string field set here wins over the client-level secret:
chat_completion = client.chat.completions.create(
model="llama3-3-70b",
messages=[{"role": "user", "content": "Hi"}],
extra_body={"user_cache_secret": per_user_secret},
)
AsyncTinfoilAI and NewSecureClient accept the same user_cache_secret parameter. Resolution order is a non-empty per-request string, a non-empty client value, a non-empty TINFOIL_USER_CACHE_SECRET, then the generated default. Empty client or environment values are treated as unset, and an empty per-request string is replaced with the resolved client value. The SDK leaves non-string values unchanged, and applications should not use them for cache scoping.
Multi-user services must provide a stable, non-empty, opaque value for each user (or group whose members may share cache-hit timing) on every eligible request. Do not use a raw user identifier, API key, or encryption key. A single client, environment, or generated value groups all requests using it under the same API identity. If persistence is unavailable, the SDK uses an in-memory value and cache continuity ends when the process exits.
Security
Please report security vulnerabilities by emailing security@tinfoil.sh.
We aim to respond to (legitimate) security reports within 24 hours.
Development
Install uv before following these instructions.
# Set up the development environment and install the package
uv sync
# Run all tests (requires the TINFOIL_API_KEY environment variable)
export TINFOIL_API_KEY="..."
uv run pytest
# Run unit tests
uv run pytest -m "not integration"
# Run integration tests (requires the TINFOIL_API_KEY environment variable)
export TINFOIL_API_KEY="..."
uv run pytest -m integration
Metadata
Release files for tinfoil 0.14.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 | |
|---|---|---|---|
| tinfoil-0.14.0.tar.gz | 682.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tinfoil-0.14.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 784.8 kB
Release files / tinfoil-0.14.0.tar.gz
| Download URL | tinfoil-0.14.0.tar.gz |
|---|---|
| Size | 682.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b88838a80210582c7dd6b307cd83e581ea21b245fb0dad79ac57202b2e9f2968
|
|
BLAKE2b-256 checksum How to use checksums |
5f9c367219d98e901f7fd6597cbeb4954242e6751e0266943ceb6ec42ea9d118
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
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 Aug 4, 2026.
Transparency logRelease files / tinfoil-0.14.0-py3-none-any.whl
| Download URL | tinfoil-0.14.0-py3-none-any.whl |
|---|---|
| Size | 102.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f04e1c0ed98e22619c03e6fc8b9a2cab60a4e9ed2001ffec58ab5cd848d77642
|
|
BLAKE2b-256 checksum How to use checksums |
91885e6e1e3ec922e2d6027d519e9ff2b7d7855dee179af607f546c30cdf38fb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
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 Aug 4, 2026.
Transparency log