Verentis

Python SDK

Python SDK reference

The `verentis` Python SDK gives engine code typed access to the run context, the VFS file API, platform HTTP, and output — with the same surface in Docker and the browser.

Python engines import the SDK with a single line:

from verentis import engine

The package is verentis-engine-sdk (pip install verentis-engine-sdk, Python 3.10+). On import it auto-loads the execution context the platform injects at /verentis/context.json, so engine is ready to use with no boilerplate.

One SDK, two runtimes

The exact same engine.context / engine.files / engine.http / engine.output / engine.token surface works whether your engine runs server-side (Docker) or client-side in the browser (Pyodide/WASM). A script you write once behaves identically in both. In the browser the file/HTTP clients need a scoped token, which the platform mints for directory programs — see Runtimes and the execution model.

engine.context

The read-only run context (a property, not a call). Mirrors the C# ExecutionContext.

executionobject

id, mode (request-response / long-running), trigger (user / schedule / event / …), timeout (seconds), tool.

workspaceobject

id, slug, name.

fileobject | None

The target file: path, name, mime_type, size, version, branch. None for runs with no single target file.

inputobject

arguments (list), environment (dict), parameters (dict or None).

platformobject

api_url and token (access_token, expires_at, scopes) — the scoped token your file/HTTP calls use. You rarely read this directly; use engine.files / engine.http.

print(engine.context.execution.id)        # exec-uuid
print(engine.context.file.path)           # /scripts/transform.py
print(engine.context.input.arguments)     # ["--verbose"]
params = engine.context.input.parameters or {}

engine.is_initialized is True when a context is present; reading engine.context without one raises RuntimeError.

engine.files

Read and write workspace files through the gateway file API, authenticated with the run's scoped token. Paths are VFS paths (leading / optional); the branch is taken from engine.context.file.branch (defaults to main).

read(path) → bytes

Raw bytes. read_text(path, encoding='utf-8') → str and read_json(path) → Any are convenience wrappers.

write(path, content, *, content_type='text/plain', encoding='utf-8') → dict

Create or overwrite a text file. Returns the created file's metadata.

write_bytes(path, content, *, content_type='application/octet-stream') → dict

Create or overwrite with raw bytes.

write_json(path, data) → dict

Serialise data to JSON and write it.

list(path='/', *, page_size=50, page_no=1) → dict

List entries under a directory path.

move(from_path, to_path)

Move/rename a file.

delete(path)

Delete a file.

data = engine.files.read_json("/data/input.json")
result = {"rows": len(data)}
engine.files.write_json("/data/output.json", result)
engine.files.move("/data/tmp.json", "/archive/tmp.json")

Writing needs authoring scopes

Reads need node.file.read; writing/deleting a file exercises the full VFS authoring cascade (node.node.create/update, node.content.create/update, node.journal.*, node.branch.update, node.file.delete). Declare what you need in your manifest's spec.permissions. The scoped token is confined to the run's launch-directory subtree and intersected with the caller's own grants, so a read-only caller can't write even if the engine asks to.

engine.http

An authenticated HTTP client scoped to the platform gateway — for platform calls beyond files (within your granted scopes). Every request carries the scoped token.

resp = engine.http.get("/v1/some/endpoint", params={"q": "x"})
if resp.is_success:
    payload = resp.json()

engine.http.post("/v1/things", json={"name": "example"})

get / post / put / delete / request return a response with .status_code, .content, .text, .json(), .is_success and .headers. A non-2xx status raises VerentisApiError (status_code, detail) with RFC 7807 ProblemDetails parsed when present.

engine.http is for platform APIs. To call third-party services, use requests/urllib directly — in the browser they're transparently backed by the browser's fetch (via pyodide-http), subject to CORS.

engine.output

Report progress, logs, artifacts and the structured result. Server-side these are written to /verentis/result.json and /verentis/progress.json; in the browser they're captured in-memory and read back by the host — same API either way.

log(message)

Emit a log line (captured as execution logs / streamed for long-running runs).

progress(percent, message=None, phase=None)

Report progress 0–100 (polled by the platform for long-running engines).

artifact(path)

Declare a VFS path your run produced; included in the final result.

result(data=None, *, status='success', error=None)

Write the final structured result.

fail(error, data=None)

Convenience for a failed result.

engine.output.log("Processing started…")
engine.output.progress(50, "Half done", phase="transform")
engine.output.artifact("/data/output.json")
engine.output.result({"rows": 42})

engine.token

The scoped token for the run. engine.token.get_token() → str returns the bearer value and engine.token.scopes → list[str] the granted scopes. You normally don't need this — engine.files and engine.http use it for you.

For server-side long-running executions, node-bounded user tokens and service-principal tokens renew automatically shortly before their five-minute expiry. Renewal preserves the original principal, scopes, workspace, and node boundary; a request that would widen any of them is rejected. Transient proactive renewal failures retry with bounded backoff while the bearer remains valid, and engine.http retries one request after a 401 by forcing renewal.

Local development

With no /verentis mount, build an engine manually to test against a real (or local) gateway:

from verentis import VerentisEngine

engine = VerentisEngine.initialize(
    api_url="https://api.localtest.me:6500",
    access_token="<dev-token>",
    workspace_id="<workspace-guid>",
    file_path="/scripts/transform.py",
    branch="main",
)

See Testing your engine for a mock-context harness that needs no running platform.

Next

Engine tools

Expose typed operations the platform and agents can invoke.