backends.ObjectBackend
The operations tether needs from one class of system.
Usage
backends.ObjectBackend()listing, diff, and history have default implementations (no listing; capability errors) so backends without DIFF / HISTORY need not define them.
Locators may carry an at field naming a specific native state (a snapshot id, version, commit, or tag). A backend that supports it treats the object as detached there: fingerprint(locator, None) returns that state instead of the base branch’s head, so commit pins it and new forks from it. Once a working ref exists it takes precedence.
Attributes
| Name | Description |
|---|---|
| KEY_SUFFIXES | For a kind whose positional locator (uri) is a path or URI: the store |
| LOCAL_PATH_KEYS | Locator keys whose value may be a local filesystem path. The engine |
| LOCAL_PATH_PREFIXES | Prefixes a LOCAL_PATH_KEYS value may carry before its path |
| MATURITY |
How much the backend has been exercised: "stable" runs its full
|
| PROMOTE_HINT | What to tell a user when tether cannot move the base branch (no |
| SAFE_CONFIG_KEYS |
[backends.<kind>] keys the committed tether.toml may set. A clone
|
| SAFE_OPTION_KEYS |
For each committed option table (storage_options, catalog), the
|
| URI_KEYS | Locator keys that name the object’s store, in order of preference; the |
| VOLATILE_KEYS | State keys that address the data without identifying it – a Neon LSN |
KEY_SUFFIXES
For a kind whose positional locator (uri) is a path or URI: the store
KEY_SUFFIXES: tuple[str, …] | None = None
suffixes default_key() drops from its last segment (.icechunk in greetings.icechunk); () drops none. None: the locator is not a path, and an object of this kind is always registered with a key.
LOCAL_PATH_KEYS
Locator keys whose value may be a local filesystem path. The engine
LOCAL_PATH_KEYS: tuple[str, …] = ()
turns a relative one into an absolute path when the object is registered (add, import), against the caller’s working directory, so a committed locator means the same path from every directory and every clone.
LOCAL_PATH_PREFIXES
Prefixes a LOCAL_PATH_KEYS value may carry before its path
LOCAL_PATH_PREFIXES: tuple[str, …] = ()
(DuckLake’s ducklake: or ducklake:sqlite:), which would otherwise read as a URL scheme. The path after the longest matching prefix is resolved like a bare one.
MATURITY
How much the backend has been exercised: "stable" runs its full
MATURITY: str = "stable"
lifecycle against the real system in CI (embedded stores and libraries); "experimental" is tested against a fake of a network service and has not been run against the service itself by the maintainers. tether backends prints it; add mentions it for experimental kinds.
PROMOTE_HINT
What to tell a user when tether cannot move the base branch (no
PROMOTE_HINT: str = ""
SAFE_CONFIG_KEYS
[backends.<kind>] keys the committed tether.toml may set. A clone
SAFE_CONFIG_KEYS: frozenset[str] = frozenset()
arrives with that file, so anything that chooses an executable, an endpoint credentials are sent to, SQL to run, or which environment variable holds a secret must come from the untracked .tether/secrets.toml or the environment instead. A key whose value is a table (such as storage_options) must also appear in SAFE_OPTION_KEYS; see check_committed_config().
SAFE_OPTION_KEYS
For each committed option table (storage_options, catalog), the
SAFE_OPTION_KEYS: Mapping[str, frozenset[str]] = {}
keys a clone may set inside it. An allowlist, not a pattern: a key the backend has not named is refused, so a new endpoint- or credential-shaped option cannot slip through by spelling. Everything else in that table comes from secrets.toml, where the same table may hold any key.
URI_KEYS
Locator keys that name the object’s store, in order of preference; the
URI_KEYS: tuple[str, …] = ("uri", "path")
per-URI entries of secrets.toml are matched against the first present.
VOLATILE_KEYS
State keys that address the data without identifying it – a Neon LSN
VOLATILE_KEYS: frozenset[str] = frozenset()
that advances on checkpoints, a change id derived from a sha. They stay in the state (pin and open need them) but are excluded from equality and from pin ids; see content_state().
Methods
| Name | Description |
|---|---|
| ancestor_of() |
Whether ancestor is in descendant’s history (None: unknown).
|
| base_branch() | The upstream branch a locator names: what the trunk bookmark stands |
| branch_scope() | The native resource that owns branches, as a stable string. |
| configure_cache() | Tell the backend where it may keep per-workspace scratch state. |
| configure_checkout() | Tell the backend where the dataset’s VCS checkout is. |
| configure_secrets() | Receive the untracked per-checkout settings for this kind. |
| create() |
Make an empty store at locator and write the owner marker for
|
| default_key() | The key add gives an object registered without one: the last |
| delete_store() | Remove the store. Called only after is_ref_empty() returned |
| delete_working_ref() | Delete a working ref created by fork(). Requires FORK. |
| diff() |
Describe what changed from state a to state b. Requires DIFF.
|
| fingerprint() |
Read the current state at working_ref (or the locator’s base).
|
| fork() |
Create a writable branch name off source. Requires FORK.
|
| history() | List native history, newest first, starting at ref (default: base). |
| identity() | Locator subset that participates in the content-addressed pin id. |
| is_ref_empty() | Whether nothing remains in the store but its base branch at the |
| list_pins() | Return pin ids that currently exist natively. Requires PIN. |
| list_working_refs() |
Native branches created by fork() (tether.ws.*). Requires FORK.
|
| listing() |
Optional detailed description of state to store alongside it.
|
| merge() |
Three-way merge source into the base branch.
|
| open() | Return a native handle for a target. |
| owner() |
The dataset id in the store’s owner marker, or None when tether
|
| pin() |
Create a durable native ref for state. Requires PIN.
|
| promote() |
Fast-forward the locator’s base branch to source. Requires PROMOTE.
|
| ref_namespace() | The native resource whose pins list_pins returns, as a string. |
| rename_pin() |
Give the pin old (which names state) the id new_id.
|
| rename_working_ref() |
Rename working branch old to new; return the resulting ref.
|
| secret_rule_for() |
The one object’s own secrets.toml entry – the longest matching
|
| secrets_for() | Credential options for one object: the longest matching URI prefix |
| state_addressable() | Whether this recorded state can be opened again later. |
| unpin() | Release a pin. Requires PIN. |
| validate_locator() | Refuse a locator this backend must never be handed. |
| verify() |
Check that state/pin still hold.
|
| working_ref_blockers() |
Why ref cannot be deleted right now, or None if it can.
|
ancestor_of()
Whether ancestor is in descendant’s history (None: unknown).
Usage
ancestor_of(locator, ancestor, descendant)Used by promote when no fork point was recorded. Default: unknown.
base_branch()
The upstream branch a locator names: what the trunk bookmark stands
Usage
base_branch(locator)branch_scope()
The native resource that owns branches, as a stable string.
Usage
branch_scope(locator)Two objects with the same scope share one branch namespace: a fork under a bookmark creates one branch for both, and the engine forks it once and lets every member write through it. Defaults to the canonical identity (one object per system). Override where several objects legitimately live in one branch space – a Neon project, an Iceberg table with several object keys – and where the identity carries fields the branch does not (a database, a source branch).
configure_cache()
Tell the backend where it may keep per-workspace scratch state.
Usage
configure_cache(cache_dir)Called by the engine after construction with .tether/cache/ (untracked). Backends that remember expensive results between runs – the file backend keeps a stat -> content-hash cache there – store them under this directory; everything else ignores the call.
configure_checkout()
Tell the backend where the dataset’s VCS checkout is.
Usage
configure_checkout(root)Called by the engine after construction. Every file under root arrived with the clone, so a backend that would run something a directory there configures – the git backend reads a repository’s config – refuses paths inside it; everything else ignores the call.
configure_secrets()
Receive the untracked per-checkout settings for this kind.
Usage
configure_secrets(defaults, rules)defaults is the merged [backends.<kind>] (committed allowlisted keys under the secrets file’s); rules maps a URI prefix to the credential options for objects under it (the engine folds [objects."<key>"] entries in as exact-URI rules). Backends read them through secrets_for().
create()
Make an empty store at locator and write the owner marker for
Usage
create(locator, *, owner)Raises
BackendError- Anything already exists there – create never adopts a store someone else made.
default_key()
The key add gives an object registered without one: the last
Usage
default_key(locator)segment of the locator’s uri (or path), less one of KEY_SUFFIXES. None when this kind names no path or no valid key comes out.
delete_store()
Remove the store. Called only after is_ref_empty() returned
Usage
delete_store(locator)delete_working_ref()
Usage
delete_working_ref(locator, ref)diff()
Describe what changed from state a to state b. Requires DIFF.
Usage
diff(locator, a, b, *, listings=(None, None))fingerprint()
Read the current state at working_ref (or the locator’s base).
Usage
fingerprint(locator, working_ref)fork()
Create a writable branch name off source. Requires FORK.
Usage
fork(locator, source, name, *, expected=None)source is a ~tether.manifest.Pin (fork from the native ref) or a recorded State (fork directly from an addressable state, used by policy.pin == "record" objects that carry no native ref).
Reset contract: if name already exists it is moved back onto source (whatever was written on it is discarded); a branch already at source is left alone. The conformance suite checks this.
Conditional move: expected is the head name must hold for the move to happen – the state the caller reviewed, or ABSENT when the branch must not exist yet. When it holds something else, raise ~tether.errors.RefMovedError and move nothing (compare content states: VOLATILE_KEYS may differ). None moves unconditionally, as before 0.1.0b4; see accepts_expected() for how the engine treats a backend whose signature predates the keyword.
history()
List native history, newest first, starting at ref (default: base).
Usage
history(locator, ref=None, limit=20)Requires HISTORY. Metadata only; limit bounds the walk.
identity()
Locator subset that participates in the content-addressed pin id.
Usage
identity(locator)Defaults to the full locator; override to exclude non-identity fields (region, credential references, source branch, …).
is_ref_empty()
Whether nothing remains in the store but its base branch at the
Usage
is_ref_empty(locator, *, ignoring=())initial state, the owner marker, and the refs in ignoring (the ones a gc plan is about to delete). A store with a working area (a git checkout, a directory) must also hold no uncommitted content: files are data whether or not a ref names them. Requires CREATE.
None means the backend cannot tell – and None means keep: a store is only ever removed on a definite True.
list_pins()
Return pin ids that currently exist natively. Requires PIN.
Usage
list_pins(locator)list_working_refs()
Usage
list_working_refs(locator)Default: none. Used by gc --prune-bookmarks.
listing()
Optional detailed description of state to store alongside it.
Usage
listing(locator, state)The engine writes the text content-addressed under .tether/listings/ at commit time and hands both sides back to diff() later. Used by backends whose state is a digest (the file backend’s directory and prefix listings) so Observed states can still be diffed.
merge()
Three-way merge source into the base branch.
Usage
merge(locator, source, message, *, expected=None)source is a working ref, a Pin, or a State. The engine passes the state the plan reviewed, so what is merged is what was shown – a ref is a name someone can move between plan and apply. Requires MERGE. Raises ~tether.errors.MergeConflict (and leaves the base untouched) when the system reports conflicts, and ~tether.errors.RefMovedError when expected is given and the base head is not that state. Returns the base branch’s new state.
open()
Return a native handle for a target.
Usage
open(locator, target, read_only)target is one of: None (the base/working ref), a str working ref, a ~tether.manifest.Pin (read a pinned state), or a recorded State mapping (read an addressable state without a pin).
owner()
The dataset id in the store’s owner marker, or None when tether
Usage
owner(locator)never wrote one (or the store is gone). Requires CREATE.
pin()
Create a durable native ref for state. Requires PIN.
Usage
pin(locator, state, pin_id)promote()
Fast-forward the locator’s base branch to source. Requires PROMOTE.
Usage
promote(locator, source, *, expected=None)source is a working ref name, a ~tether.manifest.Pin, or a recorded State. Implementations must refuse (BackendError) when the base head is not an ancestor of source – a fast-forward never discards anything – and be a no-op when the base is already there. expected is the base head the caller reviewed: when the base holds another state, raise ~tether.errors.RefMovedError and move nothing (a compare-and-swap where the system has one – git’s update-ref with an old value, Icechunk’s from_snapshot_id on an object store; see Capability.CONDITIONAL_REF). Returns the base branch’s new state.
ref_namespace()
The native resource whose pins list_pins returns, as a string.
Usage
ref_namespace(locator)gc compares the pins it lists against the pins every object in that namespace references; listing a project-wide namespace against one object’s references would release the others’ pins. Defaults to the canonical identity.
rename_pin()
Give the pin old (which names state) the id new_id.
Usage
rename_pin(locator, old, state, new_id)rename_working_ref()
Rename working branch old to new; return the resulting ref.
Usage
rename_working_ref(locator, old, new)secret_rule_for()
The one object’s own secrets.toml entry – the longest matching
Usage
secret_rule_for(locator)URI-prefix rule, without the kind defaults secrets_for layers it on; empty when none matches.
secrets_for()
Credential options for one object: the longest matching URI prefix
Usage
secrets_for(locator)rule over the kind defaults; empty when nothing applies (the backend then falls back to the environment, as it always did).
state_addressable()
Whether this recorded state can be opened again later.
Usage
state_addressable(locator, state)The capability says the backend can address states in general; a particular fingerprint may still lack the coordinate (an object in a bucket without versioning has no version_id). commit records such a state as not recoverable instead of promising a read it cannot do.
unpin()
Release a pin. Requires PIN.
Usage
unpin(locator, pin)validate_locator()
Refuse a locator this backend must never be handed.
Usage
validate_locator(locator)Called when an object is registered (add, import) so the refusal comes with the manifest’s author present, not at the first read of a clone. Default: accept. Raise BackendError to refuse.
verify()
Check that state/pin still hold.
Usage
verify(locator, state, pin, deep)working_ref_blockers()
Why ref cannot be deleted right now, or None if it can.
Usage
working_ref_blockers(locator, ref)Consulted by gc --prune-bookmarks and forget-workspace before planning a delete-branch, so an undeletable branch is planned as kept with the reason instead of failing at apply time. Neon: a branch with children (pins taken on it) cannot be deleted until they are. Default: no blockers.