Manage persistent projects and run cloud agents with keyword arguments and typed responses. Requires Python 3.11 or later.
Works with Macrofold Cloud and self-hosted deployments. Use the same resource methods with the origin and API key for your deployment. For help integrating an existing application, use the coding-agent setup prompt.
Install from source
From the repository root, install into your application virtual environment:
python -m pip install ./sdk/python
Start a run
Set MACROFOLD_API_KEY to a scoped dashboard key and copy a project ID. Select a harness and model directly; no saved agent or session is required. This example uses Codex and OpenAI’s GPT-5.4 mini. The model catalog determines the provider. Managed execution uses your credits; use fixture-model with the local simulator for free development.
from macrofold import Macrofold
macrofold = Macrofold()
run = macrofold.runs.create(
project_id="YOUR_PROJECT_ID",
harness="codex",
model="gpt-5.4-mini",
billing_mode="managed",
prompt="Create hello.txt containing Hello world.",
)
for text in macrofold.runs.stream_text(run.run_id):
print(text, end="", flush=True)
macrofold.close()
The default origin is https://app.macrofold.ai. Override it for self-hosting, staging, or local development; for example:
macrofold = Macrofold(base_url="http://localhost:3210", api_key="YOUR_LOCAL_API_KEY")
An explicit key takes precedence over MACROFOLD_API_KEY. Empty or missing keys fail before a request. Client remains an alias for the same client. Close the client when finished; long-lived applications can share it across requests.
Resource methods and types
projects = macrofold.projects.list(limit=20, archived=False)
state = macrofold.runs.get(run.run_id)
macrofold.runs.cancel(run.run_id)
All public operations have resource methods. Keyword arguments and nested types in macrofold.params provide completion. Returned Pydantic models expose attributes, typed UUIDs/datetimes, and model_dump(mode="json"). Money and sequence numbers stay strings. Use from_ for date-range query parameters because from is a Python keyword.
Required keyword arguments are enforced by Python; editors/type checkers also validate fields, enums, and nested options. Exactly-one project/workspace/session selection and ownership-dependent model/BYOK rules are validated by the API. Omit optional fields to use server defaults; None sends JSON null only where the contract allows it.
Pages have data and next_cursor; pass the latter as cursor on the next request. File reads return bytes. File writes use macrofold.workspaces.write_file(id, path="notes.md", if_match=revision, content=content) with the observed revision.
Text, structured events, or a complete result
runs.stream_text(id, after="SEQUENCE") yields only new assistant text as strings. It uses the existing SSE parser, reconnects after interruptions, and suppresses replay duplicates. Tool payloads, reasoning summaries, lifecycle events, and repeated full-response messages are excluded. Chunks are fragments, not necessarily complete words or lines.
For a complete response without streaming:
result = macrofold.runs.wait(run.run_id, timeout=300)
print(result.output_text)
print(result.checkpoint_id)
wait() polls status until execution and persistence finish, then returns the typed result and metadata. It has no overall timeout unless one is supplied in seconds. A timeout raises WaitTimeoutError with run_id and stops waiting without cancelling the agent. HTTPX connection/read timeouts and retry delays are capped by the remaining wait; synchronous transport phases can slightly exceed the deadline before returning control. Waiting does not wait for optional Git synchronization.
Both helpers raise RunFailedError for failed, cancelled, timed-out, or unsuccessfully persisted runs. Inspect run_id, status, failure_code, and the typed result; API/authentication errors remain ApiError. Partial text may have been yielded before failure.
Use macrofold.runs.events(id, after="SEQUENCE") for typed structured events and durable sequence cursors. The existing runs.stream() remains available. Save a sequence when you need replay after a process restart; automatic reconnects handle it internally during one iterator's lifetime.
Call close() on a text/event generator to detach. Only macrofold.runs.cancel(id) cancels execution. The synchronous client uses HTTPX; async applications should run blocking work in a worker thread. wait_operation(id) remains available for workspace maintenance.
Errors and recovery
Mutations keep one identity across bounded retries (two retries by default). To persist your own recovery identity:
from macrofold import RequestOptions
project = macrofold.projects.create(
name="Research",
request_options=RequestOptions(idempotency_key="YOUR_SAVED_REQUEST_KEY"),
)
TransportError.idempotency_key preserves an uncertain mutation's key, including incomplete or invalid typed responses. Inspect remote state and retry the same body and key. ApiError exposes status, code, and request_id. Redirects are refused; HTTPS is required except on loopback hosts.
Read persisted files
Before closing the client, read the exact file bytes using the run's workspace ID:
macrofold.runs.wait(run.run_id)
content = macrofold.workspaces.read_file(run.workspace_id, path="hello.txt")
print(content.decode("utf-8"))
Keep binary content as bytes. Close the client in your application's cleanup, as in the example above.
Direct reads return the complete file up to 4 MiB. During execution they use the last published revision. See reading files for HTTP usage, larger downloads, permissions, and errors.
Advanced access
request(operation, path=..., query=..., body=...) remains a low-level escape hatch returning dictionaries or bytes. Supply a callable token instead of api_key for renewed OAuth access tokens. organization selects a membership for a user token; API keys stay bound to their organization.
See API conventions for budgets, permissions, pagination, and errors.
Choose a harness
The same run methods support codex, claude-code, opencode, hermes, deepseek, and pi. Select a compatible model from the catalog. See harness capabilities and examples.