Python SDK for the ExternalSoul platform — programmatic workspace mutation, event-sourced, audit-logged.
Project description
esoul — Python SDK for ExternalSoul
esoul is the official Python SDK for the ExternalSoul platform. It lets
scripts mutate workspace state from anywhere Python runs — inside the
platform's E2B sandboxes, on a data scientist's laptop, in a Colab notebook,
in CI, in a scheduled cron job.
pip install esoul
import esoul
client = esoul.Esoul() # auto-detects credentials
state = client.describe() # what workspaces + apps + events are available
print(state.session.workspace_ids)
# Low-level dispatch
result = client.dispatch_event(
app_id="app_abc123",
event_name="spreadsheet_add_row",
event_data={"cells": {"name": "Alice", "email": "a@example.com"}},
)
print(result.event_id, result.sequence_num)
Why an SDK?
ExternalSoul workspaces are event-sourced — every state mutation is a typed event on a per-workspace timeline, scrubbable and forkable. The UI, agents, and now scripts all dispatch through the same reducers; events are the source of truth, audit logging is automatic.
The SDK is the platform's universal binding for scripted workspace operations. Common use cases:
- Bulk-import 1000 rows into a spreadsheet (one event, not 1000 LLM tool calls)
- Run an OpenCV pipeline over Drive images and write masks back
- Programmatic kanban / contacts load from a CSV
- Notebook-as-workspace-builder
- Any agent or human writing Python to mutate app state
Authentication
esoul.Esoul() auto-detects credentials in this order:
- Explicit
token=kwarg ESOUL_TOKENenvironment variable/var/run/esoul/token(the file mode 0600 token written by every E2B sandbox at boot —Esoul()inside a sandbox Just Works)~/.config/esoul/credentials(TOML file with a[default]section containingtoken = "esoul_pat_...")
For off-platform use (laptop, CI), create a Personal Access Token in workspace settings → "Access Tokens", pick the workspaces it can mutate, copy the token (shown once), and either:
# Export inline:
export ESOUL_TOKEN="esoul_pat_..."
# Or write to ~/.config/esoul/credentials:
mkdir -p ~/.config/esoul
cat > ~/.config/esoul/credentials <<EOF
[default]
token = "esoul_pat_..."
EOF
chmod 600 ~/.config/esoul/credentials
Workspace isolation
A given credential is scoped to one or more specific workspaces. Cross- workspace dispatch is structurally impossible — not a permission check in your script, an architectural invariant of the server.
Idempotency
Every write is automatically idempotent. The SDK generates a UUID per call
and reuses it across retries; the server caches the response under
(session, key) for 24h. Same key + same body → identical cached response,
not a duplicate event. You can override the key for application-level retry
control:
client.dispatch_event(
app_id=...,
event_name=...,
event_data=...,
idempotency_key="my-task-2026-05-15", # caller-controlled
)
Async client
The async client mirrors the sync API exactly:
import asyncio
import esoul
async def main():
async with esoul.AsyncEsoul() as client:
result = await client.dispatch_event(
app_id=..., event_name=..., event_data=...,
)
asyncio.run(main())
Typed errors
Failures surface as Python exception classes mapped from the server's
error.code. You can catch the kind you care about, and EsoulError
catches everything:
import esoul
try:
client.dispatch_event(...)
except esoul.WorkspaceAccessDenied as e:
print(f"This token cannot reach workspace {e.details['workspaceId']}")
except esoul.IdempotencyConflict as e:
print("Same key was used with a different request body")
except esoul.RateLimitError as e:
time.sleep(e.retry_after_seconds or 1)
except esoul.AuthError:
print("Token expired or revoked — get a new one")
except esoul.EsoulError as e:
print(f"{e.code}: {e.message}")
Status
v0.1 — alpha. Wire surface is stable; per-app typed resources are
codegen'd and shipping incrementally. The low-level dispatch_event /
dispatch_batch / read_state paths are production-ready.
See CHANGELOG.md for release notes.
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file esoul-0.2.0.tar.gz.
File metadata
- Download URL: esoul-0.2.0.tar.gz
- Upload date:
- Size: 37.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2b19dfc215a6bc92f28dfe2951ad50df5b1aa7527c4248d8285626ad8d6249fd
|
|
| MD5 |
bc1251d08830a8b7cff33e51cb44b455
|
|
| BLAKE2b-256 |
298a35aea8359db1118c1aa41897e7f7c8b9286fdfcabb09c46caa3d55c8143d
|
Provenance
The following attestation bundles were made for esoul-0.2.0.tar.gz:
Publisher:
publish.yml on vyomkeshj/esoul-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
esoul-0.2.0.tar.gz -
Subject digest:
2b19dfc215a6bc92f28dfe2951ad50df5b1aa7527c4248d8285626ad8d6249fd - Sigstore transparency entry: 1554913183
- Sigstore integration time:
-
Permalink:
vyomkeshj/esoul-python@f326ed883dab1ce8f673e222d5e6ebe08103d518 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/vyomkeshj
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f326ed883dab1ce8f673e222d5e6ebe08103d518 -
Trigger Event:
push
-
Statement type:
File details
Details for the file esoul-0.2.0-py3-none-any.whl.
File metadata
- Download URL: esoul-0.2.0-py3-none-any.whl
- Upload date:
- Size: 43.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d8b2afb0bbac5a21cdf18c86f765d55fa3468a123bf606e3789783d449a5385
|
|
| MD5 |
36b86d1d044126363a9d13fdb7edbc9d
|
|
| BLAKE2b-256 |
00ea16b3fe322feddef86782a2bb7be0cff68f32bd6cdbed791b85b7bdcd0b23
|
Provenance
The following attestation bundles were made for esoul-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on vyomkeshj/esoul-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
esoul-0.2.0-py3-none-any.whl -
Subject digest:
7d8b2afb0bbac5a21cdf18c86f765d55fa3468a123bf606e3789783d449a5385 - Sigstore transparency entry: 1554913185
- Sigstore integration time:
-
Permalink:
vyomkeshj/esoul-python@f326ed883dab1ce8f673e222d5e6ebe08103d518 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/vyomkeshj
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f326ed883dab1ce8f673e222d5e6ebe08103d518 -
Trigger Event:
push
-
Statement type: