Skip to content

Take exact curves with you

A portable bundle is a folder that holds the exact revisions you selected, the original LAS bytes, the served descriptions and the normalized curves, listed with checksums in one manifest.json. Anyone with the Python SDK installed can check it, load the curves and plot them later, with no account, no server and no network.

This is a bounded checkpoint: well-log curves (uploaded LAS, release captures and Python results, including their later versions) and, in bundle 2.0, well tops, deviation surveys and horizon grids, on self-hosted storage. Zip archives, cloud storage, groups and other data types are not included yet.

You can export only what you can already read. Every file is fetched through the same exact-read path the Workspace uses, so current sharing, withdrawal and restricted-parent rules apply to each item.

Terminal window
ophiolite export --asset <asset> --revision <revision> --curve GR --curve RHOB --output well-a-bundle
from ophiolite import Client
client = Client.from_configuration("configuration.json")
bundle = client.export([(asset_id, revision, ["GR", "RHOB"])], "well-a-bundle")
  • All or nothing. If any selected item is refused (not shared with you, withdrawn, revoked), the export fails and no bundle folder appears.
  • Exact and frozen. A bundle keeps the revision you chose. A newer version published later does not change it; export again to take the newer version.
  • Never overwrites. Choose a new folder. An interrupted export leaves at most a hidden staging folder, which a later export removes once it is no longer in use.
  • Bounds. Up to 128 revisions, 32 MiB per file and 512 MiB per bundle.

Add --title and --description (and optionally --version) to write a citation and the RO-Crate, Croissant and DataCite descriptors beside the manifest. You give only the words. The creators are the people the records say made each exported version, earliest first; when no version names a person, the project’s organisation is the creator. The publisher is the project’s organisation, and the licence is the files’ own open licence when they all share one; otherwise the citation carries a notice to ask the publisher. ophiolite bundle check verifies the descriptors with the files. Well tops, deviation surveys, time-depth tables and point sets are described in the Croissant file as record sets, so a Croissant reader reads them row by row. A starter pack carries the same three descriptors, written from its starter.json when the pack is finalised, and ophiolite bundle check on the pack folder verifies them with its files.

Terminal window
ophiolite bundle check well-a-bundle # verifies every checksum, path and version
ophiolite bundle show well-a-bundle # summarizes revisions and curves
from ophiolite.bundle import open_bundle, plot_svg
bundle = open_bundle("well-a-bundle") # refuses anything it cannot verify
curve = bundle.assets[0].curves["GR"]
curve.values # None is a missing sample; 0.0 stays 0.0
curve.unit, curve.context["depth_index"]
plot_svg(curve, "gr.svg") # dependency-free depth track
curve.to_frame() # with the pandas extra installed

The reader never imports networking or sign-in code. It refuses a bundle whose files do not match their checksums, whose paths leave the folder or are links, that lists files twice, exceeds the reader’s own size limits, carries non-finite numbers, or uses a newer major version. Files present in the folder but not in the manifest are reported and never used.

When exported results belong to result groups you can see, the bundle records them under observations: the group name, when it was observed, which of the exported items belong to it and, if the recommended version is among them, who recommended it and why. This is an observation at export time — a person’s organisation of the work, not a scientific property — and it is never updated afterwards. Members and recommendations you cannot see are left out and not counted. If groups could not be listed (for example with an application credential), the bundle says so. Use --no-groups (CLI) or export(..., groups=False) to leave them out; readers that predate observations still read these bundles.

Measured on the pilot host (27 September 2026), the same on the local and S3-compatible stores: exporting 5 curves of a 24 MiB, 40-curve LAS produced a 30 MiB bundle in about 65 s (the gateway re-reads the original for each curve; its peak memory was about 0.9 GiB); 20 small results took about 3 s. More than 128 exact revisions are refused before anything is written. These are measurements, not guarantees.

ophiolite bundle pack BUNDLE_FOLDER bundle.zip (or ophiolite.bundle.pack) writes the bundle as one zip: the manifest first, entries sorted, fixed times, so the same bundle always gives the same bytes. Packing refuses a folder with files the manifest does not list and never overwrites. ophiolite bundle check bundle.zip and open_bundle('bundle.zip') check the archive before extracting anything — entry names within the bundle layout, no links or folders, no names that differ only in letter case, sizes and compression within the reader’s limits, exactly the listed files — and then check the extracted copy as a folder. The extracted copy belongs to the opened bundle and is removed when you close it.

imported = client.import_bundle('bundle.zip', audience=['bob'], attribution='From the 2026 study bundle',
rights_confirmed=True, well_logs={exported_log: (new_log, new_revision)})

Each original the bundle carries (well logs, tops, surveys, grids, meshes, points, fault sticks, and a result’s own file) becomes your new upload in the destination: private to you (the audience is only who you may later share with), with the context the bundle declares (units, CRS, meanings — unknown stays unknown) and the bundle named as its origin (manifest checksum, the exported asset and revision, the exporter). That origin is provenance, not authority: the destination asset is new, and nothing about the source deployment’s history, groups, grants or approvals comes along. Tops that belonged to a well log need you to name the imported well log; seismic slices carry no original and are not imported. A wells table (bundle 2.17: the rows a wells import kept, exported with the wells they locate) is not uploaded either: ophiolite.restore restores it with its wells. You must confirm that you may keep and share the files — having a bundle grants nothing. Repeating an import is safe: assets already imported come back unchanged, so an interrupted import can simply be run again.

Moving a whole project between deployments with its people, history and authority is a different path: the project move (cli/migrate_project.py), which uses its own package and identity mapping.

  • A checksum proves the files are unchanged since export. It does not prove who made them or that the science is correct.
  • Exported copies cannot be recalled. Revoking access later stops new exports, not copies that already exist.
  • Holding a bundle grants no rights in Ophiolite.
  • History inside a bundle is the summary served at export time (version number, count and latest revision then), not a complete list of versions.

The earlier project exporter for native assets (tools/export_project.py) is unchanged, now covered by automated tests of its layout, checksums, bounds and refusals (it checks that the destination does not exist and then renames; it is not an exclusive claim), and remains the path for native project data; portable bundles cover the managed scientific curves described here. The bundle format is specified in the Contracts component (ophiolite.portable-bundle/1).