# Soft Claims vs Hard Leases in LoopX Todo Coordination: A Complete Technical Guide

> Understand LoopX's soft claims vs hard leases for todo coordination. Learn how LoopX uses these mechanisms for efficient multi-agent access and exclusive write-scope.

- Repository: [huangruiteng/loopx](https://github.com/huangruiteng/loopx)
- Tags: deep-dive
- Published: 2026-09-04

---

**Soft claims provide lightweight ownership hints for routing and visibility, while hard leases enforce exclusive write-scope with TTL protection—LoopX uses both mechanisms together to coordinate multi-agent access to todos.**

LoopX implements a dual-layer coordination system for its todo-sharing protocol. Understanding the difference between **soft claims** and **hard leases** is essential for building robust multi-agent workflows in the `huangruiteng/loopx` repository. Both mechanisms serve distinct purposes in the shared-goal authority model: soft claims handle visibility, while hard leases guarantee exclusive mutation rights when needed.

## What Are Soft Claims?

Soft claims represent the default coordination mechanism in LoopX. They function as **non-exclusive ownership hints** that allow agents to signal intent without blocking others.

### How Soft Claims Work

A soft claim is stored directly in the todo's markdown content via the `claimed_by` field. As implemented in [`loopx/visible_governance.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/visible_governance.py), the system extracts these claims from the status queue to route tasks and display current ownership in [`ACTIVE_GOAL_STATE.md`](https://github.com/huangruiteng/loopx/blob/main/ACTIVE_GOAL_STATE.md).

```bash

# Add a soft claim

loopx todo claim --todo-id 42 --agent-id alice

# Remove when finished

loopx todo unclaim --todo-id 42 --agent-id alice

```

The key characteristic: **multiple agents can soft-claim the same todo simultaneously**. This coexistence is possible because soft claims never interact with the lease store. The test in [`tests/control_plane/test_goal_handoff_mode.py`](https://github.com/huangruiteng/loopx/blob/main/tests/control_plane/test_goal_handoff_mode.py) (line 391) explicitly validates this behavior.

### Soft Claim Properties

- **No TTL**: Claims persist as long as the todo remains open and the agent reports activity
- **Crash recovery**: Cleared automatically through standard todo-status updates if an agent fails
- **Always visible**: Appears in the shared canonical state regardless of lease configuration

## What Are Hard Leases?

Hard leases provide **optional, exclusive write-scope protection** for scenarios requiring deterministic arbitration. Unlike soft claims, hard leases actively prevent concurrent mutation.

### How Hard Leases Work

In [`loopx/control_plane/goals/shared_goal_alignment.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/control_plane/goals/shared_goal_alignment.py), hard leases are persisted as JSON files under `goals/<goal>/task-leases/` and protected by file locks. Only one active lease exists per todo at any moment.

The protocol definition in [`docs/reference/protocols/host-integration-surface-v0.md`](https://github.com/huangruiteng/loopx/blob/main/docs/reference/protocols/host-integration-surface-v0.md) (line 223) specifies four explicit operations:

```bash

# Acquire exclusive lease with 10-minute TTL

loopx task-lease acquire --todo-id 42 --ttl 600

# Renew before expiration

loopx task-lease renew --todo-id 42

# Explicit release

loopx task-lease release --todo-id 42

# Check status

loopx task-lease inspect --todo-id 42

```

### Hard Lease Properties

- **Optional TTL**: Configurable expiration; see [`examples/control_plane/todo-claim-lease-roadmap-smoke.py`](https://github.com/huangruiteng/loopx/blob/main/examples/control_plane/todo-claim-lease-roadmap-smoke.py) (line 55) for TTL handling
- **Single holder**: Other agents see occupied status and must wait
- **Crash safety**: Stale lease detection via "inactive terminal records" prevents ABA issues during reacquisition ([`shared_goal_alignment.py`](https://github.com/huangruiteng/loopx/blob/main/shared_goal_alignment.py), line 284)

## Programmatic Usage in LoopX SDK

Both mechanisms are accessible through the Python SDK:

```python
from loopx import LoopXClient

client = LoopXClient()

# Soft claim — non-exclusive, always available

client.todo.claim(todo_id=42, agent_id="alice")

# Hard lease — exclusive, opt-in

lease = client.task_lease.acquire(todo_id=42, ttl=600)

# ... perform exclusive work ...

client.task_lease.release(lease_id=lease.id)

```

## Side-by-Side Comparison

| Aspect | Soft Claim | Hard Lease |
|--------|------------|------------|
| **Scope** | Visibility and routing | Exclusive mutation rights |
| **Storage** | Todo `claimed_by` markdown field | `goals/<goal>/task-leases/*.json` with file lock |
| **Concurrency** | Multiple agents allowed | Single holder only |
| **TTL** | None | Optional, configurable |
| **Management** | Implicit claim/unclaim | Explicit acquire/renew/release/inspect |
| **Visibility** | Always in [`ACTIVE_GOAL_STATE.md`](https://github.com/huangruiteng/loopx/blob/main/ACTIVE_GOAL_STATE.md) | Only when lease feature enabled |
| **Failure handling** | Cleared by status updates | Terminal record prevents ABA |

## When to Use Each Mechanism

**Use soft claims when:**
- Agents need visibility into who intends to work on a task
- Cooperative coordination is sufficient
- You want minimal overhead and maximum flexibility

**Use hard leases when:**
- Exactly one agent must mutate the todo at a time
- Deterministic arbitration prevents race conditions
- TTL-based timeout protection is required for crash safety

## Key Implementation Files

| File | Purpose |
|------|---------|
| [`loopx/visible_governance.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/visible_governance.py) | Soft claim extraction and routing logic |
| [`loopx/control_plane/goals/shared_goal_alignment.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/control_plane/goals/shared_goal_alignment.py) | Hard lease validation, acquisition, and corruption handling |
| [`docs/reference/protocols/host-integration-surface-v0.md`](https://github.com/huangruiteng/loopx/blob/main/docs/reference/protocols/host-integration-surface-v0.md) | CLI and API contract for hard leases |
| [`tests/control_plane/test_goal_handoff_mode.py`](https://github.com/huangruiteng/loopx/blob/main/tests/control_plane/test_goal_handoff_mode.py) | Validation that soft claims bypass the lease store |
| [`examples/control_plane/todo-claim-lease-roadmap-smoke.py`](https://github.com/huangruiteng/loopx/blob/main/examples/control_plane/todo-claim-lease-roadmap-smoke.py) | TTL handling demonstration |

## Summary

- **Soft claims** are LoopX's default coordination mechanism—lightweight, non-exclusive ownership hints stored in todo markdown for routing and visibility
- **Hard leases** provide opt-in exclusive write-scope with TTL protection, implemented via file-locked JSON in `goals/<goal>/task-leases/`
- Both mechanisms coexist: soft claims never read the lease store, allowing parallel claims while hard leases enforce single-writer semantics when explicitly requested
- Choose soft claims for cooperative workflows; add hard leases when deterministic arbitration and crash-safe timeouts are required

## Frequently Asked Questions

### Can an agent hold both a soft claim and hard lease on the same todo?

Yes. These mechanisms are independent. An agent typically maintains its soft claim for visibility in [`ACTIVE_GOAL_STATE.md`](https://github.com/huangruiteng/loopx/blob/main/ACTIVE_GOAL_STATE.md) while holding a hard lease for exclusive mutation rights. The soft claim signals intent; the hard lease enforces it.

### What happens if a hard lease expires while work is in progress?

The lease becomes invalid. Agents must proactively renew leases before TTL expiration using `loopx task-lease renew`. The recommendation in [`todo-claim-lease-roadmap-smoke.py`](https://github.com/huangruiteng/loopx/blob/main/todo-claim-lease-roadmap-smoke.py) is to set TTLs generously and implement heartbeat renewal patterns for long-running work.

### Why does LoopX retain "inactive terminal records" for expired leases?

To prevent **ABA problems**. As implemented in [`shared_goal_alignment.py`](https://github.com/huangruiteng/loopx/blob/main/shared_goal_alignment.py) (line 284), a crashed agent's stale lease could be silently replaced if the system reused lease identifiers. Terminal records preserve a tombstone history, ensuring that reacquisition attempts expose the intervening expiration clearly.

### Are hard leases required for basic LoopX operation?

No. Hard leases are entirely optional. The system functions fully with soft claims alone. Hard leases activate only when an agent explicitly calls `loopx task-lease acquire` or the equivalent SDK method, making them opt-in infrastructure for contention-heavy scenarios.