To prevent agents and humans from clobbering each other's edits, use the claim method. A claim acts as a non-locking lease that serializes writers.
When you call claim, the SDK provides an AsyncDisposable handle. Using await using ensures the claim is released automatically when the scope exits. While a claim is held, any subsequent update calls are automatically protected by a stale-check: the SDK attaches the claim's snapshot version as readAt and sets onStale: 'reject'. If the row was modified by another party while the claim was held, the update will fail with an AbloStaleContextError instead of overwriting the new data.
Use the queue option to control behavior when a row is already held:
queue: false: The claim call resolves to null immediately if another participant holds the row. This allows an agent to 'yield' and avoid fighting for the row.queue: true (or omitted): The claim call waits for the current holder to release the row, then re-reads the fresh data and hands it to you.
// Example of claiming a row and performing a protected update
try {
const acquired = await ablo.tasks.claim({
id: taskId,
queue: false, // Yield immediately if someone else has it
description: 'marking_done',
});
if (!acquired) return { status: 'yielded' };
// Use 'await using' to ensure the claim is released on scope exit
await using claim = acquired;
// This update is automatically stale-checked against the claim's version
const updated = await ablo.tasks.update({
id: claim.data.id,
data: { status: 'done' },
});
return { status: 'done', task: updated };
} catch (err) {
if (err instanceof AbloClaimedError) return { status: 'yielded' };
if (err instanceof AbloStaleContextError) return { status: 'stale' };
throw err;
}