This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
TensorLake SDK — a Python SDK for document ingestion (DocumentAI) and serverless agentic applications. Users define applications using decorator-based APIs and deploy them to TensorLake Cloud or run locally.
# Install dependencies and build
make build
# Format code (Black + isort)
make fmt
# Check formatting without modifying
make check
# Run all tests (requires TENSORLAKE_API_URL env var)
make test
# Run a specific test suite
cd tests && ./run_tests.sh --applications
cd tests && ./run_tests.sh --function-executor
cd tests && ./run_tests.sh --document-ai
cd tests && ./run_tests.sh --cli
# Run a single test file
cd tests && poetry run python path/to/test_file.py
# Regenerate gRPC stubs from .proto files
make build_protoFor validations that must run inside the real Tensorlake builder image, use a throwaway Python virtualenv with the published tensorlake package. Do this for live environment checks, not normal repo tests.
Key points:
- Install from PyPI in a fresh venv:
python3 -m venv /tmp/tl-validate-venv && /tmp/tl-validate-venv/bin/python -m pip install -q --upgrade pip tensorlake. - Read the token from
~/.config/tensorlake/credentials.toml, but never print it. The published SDK readsTENSORLAKE_API_KEY;TENSORLAKE_PATis not enough for sandbox creation. - Read
organizationandprojectfrom.tensorlake/config.tomland pass them explicitly toSandboxClient.for_cloud(...). Relying only on environment variables can produce missing scope headers. - Create the throwaway sandbox from
tensorlake/rootfs-builder, run validation commands, and always delete it withclient.delete(sandbox_id)in afinallyblock. - Commands run as
tl-userby default. Builder-image checks that startdockerdmust run as root, e.g.sudo -n <script>.
Minimal pattern:
import os
from pathlib import Path
from tensorlake.sandbox import SandboxClient
def token_for(endpoint: str) -> str:
current = None
for raw in (Path.home() / ".config/tensorlake/credentials.toml").read_text().splitlines():
line = raw.strip()
if line.startswith("["):
current = line.strip("[]").strip().strip('"')
elif current == endpoint and line.startswith("token"):
return line.split("=", 1)[1].strip().strip('"')
raise RuntimeError(f"no token for {endpoint}")
def local_config() -> dict[str, str]:
out = {}
for raw in Path(".tensorlake/config.toml").read_text().splitlines():
line = raw.strip()
if "=" in line:
key, value = line.split("=", 1)
out[key.strip()] = value.strip().strip('"')
return out
endpoint = "https://api.tensorlake.ai"
token = token_for(endpoint)
cfg = local_config()
os.environ["TENSORLAKE_API_KEY"] = token
client = SandboxClient.for_cloud(
api_key=token,
api_url=endpoint,
organization_id=cfg["organization"],
project_id=cfg["project"],
)
sandbox = None
try:
sandbox = client.create_and_connect(image="tensorlake/rootfs-builder")
sandbox.write_file("/tmp/validate.sh", b"#!/usr/bin/env bash\nset -euo pipefail\nsudo -n id\n")
result = sandbox.run(
"sh",
["-lc", "chmod +x /tmp/validate.sh && sudo -n /tmp/validate.sh"],
timeout=900,
)
print(result.stdout)
if getattr(result, "exit_code", 0) != 0:
raise RuntimeError(result.stderr)
finally:
if sandbox is not None:
client.delete(sandbox.sandbox_id)-
Applications SDK (
src/tensorlake/applications/) — Decorator-based API for defining serverless functions and applications. Public interface is inapplications/interface/; everything re-exported throughapplications/__init__.pyviafrom .interface import *. -
Sandbox SDK (
src/tensorlake/sandbox) - Client for creating Sandboxes where users can run arbitrary code, copy files, install packages and etc. -
DocumentAI SDK (
src/tensorlake/documentai/) — Client for document parsing, extraction, and classification.
Users decorate functions with @application and @function (defined in interface/decorators.py). Decorators create Function objects registered in a global registry (registry.py). Functions support .map() and .reduce() operations and return Future/Awaitable objects for async execution.
Two execution modes:
- Local (
applications/local/) — Direct in-process execution for development/testing viarun_local_application(), implemented by LocalRunner class. - Remote (
applications/remote/) — Cloud deployment viarun_remote_application()and gRPC communication, implemented by AllocationRunner class.
src/tensorlake/function_executor/ — gRPC server that executes user functions in sandboxed environments. Proto definitions in function_executor/proto/. Proto files and generated Python stubs must coexist in the same directory (gRPC limitation).
src/tensorlake/cli/ — Click-based CLI (tensorlake command). Entry points: tensorlake deploy, tensorlake parse, tensorlake login, tensorlake secrets, etc.
src/tensorlake/vendor/ contains vendored faker and nanoid libraries. Black and isort are configured to skip this directory.
- Python 3.10+, managed with Poetry 2.0.0
- Formatting: Black + isort (profile "black"). Pre-commit hooks enforce this.
- Tests: Standard
unittestframework withparameterizedfor parameterized tests. Parameterized tests are main used to run the same test code in local and remote modes and ensure the same results. Claude must not create new Python environments to run test. Instead it should use currrent Poetry environment by i.e. usingpoetry run python tests/path_to/test_file.py. - Pydantic v2 for data models throughout.
- gRPC stubs are generated with grpcio-tools 1.60.0 (pinned old version for forward compatibility) and reformatted with Black/isort after generation.
IMPORTANT: After finishing code changes on a branch, before handing back to the user, remind them to bump the version. All packages (Python, Rust, CLI, TypeScript) are released in lockstep at a single shared version, so a release bumps everything together.
How to bump:
- Run
python .github/scripts/bump_version.py <new-version>. A single command updates every version-bearing file used by the PyPI / crates.io / CLI / npm release workflows:pyproject.toml(root,tensorlakePyPI package)Cargo.toml(root, workspace version — all crates inherit viaversion.workspace = true, includingcrates/cli)crates/rust-cloud-sdk-py/pyproject.tomltypescript/package.json(npm package;publish_npm.yamlreads the version from here)
Cargo.lockandtypescript/package-lock.jsonregenerate on build/install — commit them after they refresh, don't hand-edit.
CRITICAL: Always run tests in BOTH local and remote modes. Do NOT skip remote mode or run only local mode unless the user explicitly says to run local or remote only.
Most test files use @parameterized to run each test case in both modes.
Never reduce test scope to work around infrastructure failures. If tests fail due to missing setup (e.g. deploy_applications fails in setUpClass), this means remote mode is not set up yet — follow the remote mode setup procedure below instead of falling back to running only local tests.
Before running a test in remote mode you MUST first ensure all remote mode dependencies are available:
- Check if indexify-server is running (HTTP ping
http://localhost:8900) - If not then stop immediately and ask the user to run it. Do not try to run local mode tests to proceed faster.
- Ask user for the command that runs indexify-dataplane. Do not assume that indexify-dataplane is running or not running. You have to start it yourself to get access to its stdout/stderr so you can investigate test failures yourself.
- Run indexify-dataplane using the command given by user.
The dataplane command stdout/stderr contain logs from indexify-dataplane service and from Function Executors started by indexify-dataplane. Use these Function Executor logs to investigate failures in remote mode.
When running remote mode tests using poetry run tests/path_to/test_file.py you need to also define env var TENSORLAKE_API_URL=http://localhost:8900 by prepending it to the poetry run python command.
Local mode tests don't have any dependency on indexify-dataplane and indexify-server. The logs and backtraces for LocalRunner and related classes are available in stdout/stderr of the test file when you run it. Use these backtraces and logs to investigate local mode test failures.