Python and TypeScript SDK
Reviewed 26 September 2026. The supported 0.x SDK reads and publishes bounded scientific curve revisions through the public API. Contracts remain preview contracts. Source installation is qualified on Python 3.10/3.12; stable 1.0, PyPI/npm publication, a complete open-source release and production support are separate release gates.
Install and use
Section titled “Install and use”Follow Read data in your own Python for browser login and a complete read (login uses the deployment’s identity provider; see Install › Sign-in). Use a private virtual environment:
python -m pip install 'ophiolite[pandas,numpy,validation] @ git+https://github.com/tuna-soup/ophiolite-sdk@ac62ad00e2fe399756474cd655ee6b750966dd88'ophiolite skills pathThis installs the Ophiolite SDK of release 2026.11.18.
Exact version
ac62ad00e2fe399756474cd655ee6b750966dd88The installed guides cover authentication, exact reads, local validation,
publication, sharing and recovery. They use public APIs and confer no new rights.
Source and API examples
include sync Client, async AsyncClient, typed descriptors and bounded local
validation. Validation and contract imports need no server or credential cache.
Scientific data contract
Section titled “Scientific data contract”client.assets() discovers permitted assets. client.read(asset, revision, ["GR", "RHOB"]) selects exact curves explicitly. These names are an example;
choose curves returned for your asset. Reads require no binding or run.
data.to_frame() returns a DataFrame and a separate descriptor;
data.to_numpy() returns an array and its descriptor. Preserve both together.
Metadata is not silently attached: descriptor.attach(frame) is explicit.
Missing samples become NaN in numerical views; normalized JSON uses null and
zero stays zero. Original LAS bytes preserve their declared NULL marker.
The descriptor preserves source identity, units, axis/depth reference, interpretation and checksums. Multi-curve views require matching axes and scientific context. No unit conversion, interpolation, CRS/datum inference or well identity matching happens automatically. Unknown units remain unknown. Source revisions are opaque; do not generalize a managed-derived checksum rule to all sources. Changed mappings refuse; reader-version differences stay explicit.
data.workspace_url() opens the selected scientific revision and curve in
Workspace. Access and retention still apply to old revisions. Synthetic templates
show this URL contract but do not serve Workspace themselves.
Local work, publication and recovery
Section titled “Local work, publication and recovery”Use client.work_folder(private_folder) for configure/start, local calculation,
validation, publication and download. A run-start records/resolves input; it does
not execute Python. Inspect your result before explicit publication. Current
publication creates a separate derived asset; it does not append to its parent.
Sharing is a separate authorized operation.
Preserve the entire private folder. client.recover(private_folder) replays the
saved exact request and validates its response; a completed folder returns None.
Direct calls without a work folder do not provide recovery after process exit.
A command ID alone is insufficient. Changed inputs/code need a new folder.
Recovery binds the gateway, project and identity. A fresh approved grant for the
same confirmed user is supported; an opaque delegate requires the original
fingerprint. Credentials are not stored in the folder. This is process-restart
qualification, not a power-loss guarantee.
| Operation | Retry and recovery |
|---|---|
| Reads and inspection | Up to three attempts for transient transport/busy responses |
| Configure, start, upload and publish | Same command/body on bounded retries; work folders persist the exact request |
| Sharing | Never automatic; after ShareOutcomeUnknown, read client.grants(receipt) first and decide from current state |
| Login, refresh and revoke | Never replay an ambiguous request automatically |
| Error | Meaning and next step |
|---|---|
| AuthenticationRequired / PermissionRefused | Renew authorized access or ask the owner for the required grant; no credential fallback |
| VerificationFailed / InterpretationChanged | Bytes or interpretation cannot be trusted; inspect exact artifacts and reader version |
| AxisMismatch / Incompatible | Read separately or choose and document an explicit supported transformation |
| ValidationFailed | Correct reported output violations before publication |
| IntegrityConflict | Saved command and request disagree; preserve evidence, do not invent a new command to bypass uncertainty |
| CapacityExceeded / Busy | Reduce the bounded request or follow the reported retry guidance |
| RecoveryUnavailable | Preserve the original folder and evidence; arbitrary disk-loss recovery is not promised |
| ShareOutcomeUnknown | Read current grants before deciding whether another sharing action is needed |
Agents
Section titled “Agents”ophiolite.agents.AgentClient(base_url, project, credential) uses an agent credential
from Settings → Agents: read() for reads, propose(), wait() and execute() (or
run() for all three) for changes, recover(command_id=… | plan=…) after a lost answer.
A job is 1 to 8 steps under one approval (ophiolite.agent-job/1):
| Method | What it does |
|---|---|
propose_job(steps, *, evidence=None, files=None) | Posts jobs/propose with steps {operation, body}. Each body is copied and names the client’s project (project_id is added when absent). A body value {"$step": k, "pointer": "/…"} is part of step k’s answer. A malformed list or a step naming another project raises Refused (a ValueError) before any request. Which operations a job may run is the gateway’s decision, in its words. files is {step: bytes} for each file step (table-imports/read): its body gains the file’s bytes and sha256, and a file step without its bytes, or naming other bytes, raises Refused before any request |
job_status(plan) | Posts jobs/status; the answer is checked against ophiolite.agent-job/1 without the validation extra (VerificationFailed otherwise) |
step(plan, step, *, evidence_id=None, command_id=None) | Posts jobs/step. The command id defaults to uuid5(NAMESPACE, f'{plan}:{step}'), with ophiolite.agents.NAMESPACE a fixed published UUID, so every process sends the same id; a completed step answers its recorded answer and writes nothing |
run_job(steps, *, evidence=None, files=None, **wait) | propose_job, wait for the approval (the evidence id as for run), then every step in order; returns the answers. A file step’s bytes go to its own route (send_file_step) |
resume(plan, *, files=None, **wait) | Waits while the plan is pending, replays completed steps by their ids and runs the rest; returns every answer in order. A file step that has not run needs its bytes in files and its body from this process’s propose_job; after a restart, call run_job with the same steps and files (the same plan) |
send_file_step(plan, step, operation, body, raw, *, evidence_id=None, command_id=None) | Posts the file to the step’s own route with the approved body in X-Ophiolite-Upload, X-Ophiolite-Plan and X-Ophiolite-Job-Step: <step> <command_id> (the id step uses); a completed file step answers its recorded answer |
A step that needs the person’s decision raises ChoiceRequired with its question, choices,
choice_token, plan and step. A declined or expired job raises PlanDeclined or
PlanExpired; a failed job raises the gateway’s word (BudgetExhausted, CommandOwned, or
Refused with that code). CommandOwned from a completed step whose answer was never stored is
not recoverable through the SDK. job(job_id) stays the runner-job reader (E13).
The person’s own Client has proposals() (agents/proposals, the envelope checked against
ophiolite.agent-proposals/1): every pending plan and every job waiting for their choice. It
also has answer(choice_token, choice) (jobs/answer), which returns
{plan, step, state: 'running', choice}. An agent credential is refused on both by the gateway
(agent-refused, 403). A used, foreign or stale token, or another person’s job, raises
ChoiceRefused (choice-refused) with details['reason'] one of token-used,
token-foreign, token-stale or not-the-delegator.
See Let an agent work for you.
Tested starter templates
Section titled “Tested starter templates”Four starter sources provide an agent workflow, executed notebook, Python application and React app. Each records its template/SDK version, locked dependencies, synthetic fixtures, README and explicit test command. Synthetic mode needs no credentials; live mode uses your authorized configuration. The notebook preserves descriptors alongside numerical data; the React starter keeps credentials in its local Python backend. Its loopback server requires explicit browser origin and per-start request proof. Fixture tests establish bounded examples, not production deployment or connectors.
Sharing
Section titled “Sharing”client.grants(asset) returns the recipients and their generation (None when
the server predates conditional sharing). Share with
client.share(asset, read=[...], reuse=[...], expected_generation=grants.generation):
after a lost response the SDK repeats the identical request once, and that repeat
raises IntegrityConflict instead of undoing a change made meanwhile. Without
expected_generation the call is unconditional, never repeated, and warns as
deprecated. ophiolite share reads the current generation first. See
Share data with colleagues.
Versions of a result
Section titled “Versions of a result”client.publish(run, changes=..., new_version_of=previous_receipt) (also on work
folders) adds the next version of your own result (or of a colleague’s, when the project
names you both as members who add versions to each other’s results), with the revision you reviewed
as expected parent; if someone added a newer version first the SDK raises
IntegrityConflict and nothing changes. client.history(result) lists every
version you can read of a result or a derived publication, including those someone
else published and shared with you — pass the asset as {"asset_id": ..., "revision": ..., "authority": ...} from client.assets(). The versions of an uploaded original are not
listed: history refuses one in plain words; read the exact revision you were given,
or ask its uploader (2026.10.22).
Well tops, trajectories and horizon grids
Section titled “Well tops, trajectories and horizon grids”client.read_data(asset, revision) returns WellTops, Trajectory or GridSurface with the
exact original, verified descriptor and data (to_frame(), to_numpy(), cell_center(),
explicit minimum_curvature()); also on AsyncClient. Export them with None as the curve
list. See Well tops, trajectories and horizon grids.
Fault sticks and seismic volumes
Section titled “Fault sticks and seismic volumes”read_data also returns PolylineSet (fault sticks in file order, to_frame()) and
SeismicVolume — the volume’s description (grid, sample meaning, every header decision,
per-inline chunk digests); the volume itself is not downloaded. client.read_slice(asset, revision, axis, label) returns a SeismicSlice (values, rows, columns, to_numpy(),
value_at(), scope) checked against that description; axis is 'inline', 'crossline'
or 'sample' and label the line number or the 0-based sample number.
client.export_slices(asset, revision, [(axis, label), ...], folder) writes a bundle 2.3 with
the chosen slices and names the original by its digest. Both are also on AsyncClient. See
Fault sticks and seismic volumes.
Portable bundles
Section titled “Portable bundles”client.export([(asset, revision, curves), ...], folder) writes a new portable
bundle of exact revisions (all or nothing, never overwriting); ophiolite.bundle.open_bundle(folder)
checks and loads it offline, and plot_svg(curve, path) draws a track. The CLI
offers ophiolite export and ophiolite bundle check|show. See
Take exact curves with you.
TypeScript
Section titled “TypeScript”@ophiolite/client provides generated operations and verified readCurve.
Build from the reviewed source; npm publication is pending. Host applications own
credentials and refresh. Session mode uses Workspace CSRF/cookies; bearer mode
uses an explicit supplier and omits browser cookies. Redirects refuse. Calls make
one HTTP attempt; sharing never retries. There is no browser work-folder journal.
Incomplete server response schemas remain unknown or documented adapters; a
generated request alone does not prove scientific integrity.
Versioning, migration and licence
Section titled “Versioning, migration and licence”Python and TypeScript share 0.MINOR.PATCH and one release tag. PATCH fixes defects or adds APIs. MINOR may break APIs with a CHANGELOG Breaking entry and a one-minor shim where feasible. A new schema suffix requires a new model/MINOR. A stable 1.0 promise requires supported registry entries for every SDK read and stable OpenAPI.
The old pilot 0.2 modules remain in the 0.3.0 compatibility kit for one announced transition release. Fresh SDK login is required; never copy old credential caches. They are removed in the first versioned distribution release afterward. The SDK, TypeScript client, templates, guides and extracted contracts are Apache-2.0; server licensing and full release qualification are separate.
