# Capability-to-Provider Execution Path vs Kernel Writeback Control Path in LoopX

> Understand the difference between LoopX capability-to-provider execution path and Kernel writeback control path. Learn how LoopX handles external work and state changes.

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

---

**The capability-to-provider execution path handles external work delegation without state mutation privileges, while the Kernel writeback control path exclusively validates transition proposals and persists state changes according to quota and authority contracts.**

LoopX (`huangruiteng/loopx`) separates the "doing" of work from the "governing" of state changes through two orthogonal flows. Understanding the distinction between the capability-to-provider execution path and the Kernel writeback control path is essential for safely extending the system and implementing custom capabilities.

## The Capability-to-Provider Execution Path

This forward-moving path performs the concrete work requested by agents, such as calling external APIs, running tools, or issuing Git commands.

### Flow and Ownership

The execution follows a strict chain documented in [`README.md`](https://github.com/huangruiteng/loopx/blob/main/README.md) (line 438):

1. The **Agent** asks a **Capability** for an operation.
2. The **Capability** builds a **Provider** request (read-only or effectful).
3. The **Provider** executes the external action and returns a **read-back** payload.

The Capability defines *what* should be done, while the Provider implements *how* to do it. As described in [`docs/reference/extensions.md`](https://github.com/huangruiteng/loopx/blob/main/docs/reference/extensions.md) (lines 34-40), the "Provider readback → Capability transition proposal → LoopX Kernel" chain ensures that no external actor bypasses the Kernel's authority.

### Authority and Constraints

Providers operate in a sandboxed context without Kernel authority. They cannot directly mutate LoopX state; they only produce read-back payloads that must be packaged into transition proposals. This constraint ensures that all state mutations flow through the Kernel's validation layer.

## The Kernel Writeback Control Path

This backward-moving path validates, authorizes, and persists the results of the provider’s work, deciding whether further turns are allowed.

### Flow and Validation

According to [`docs/reference/protocols/computer-use-runtime-v0.md`](https://github.com/huangruiteng/loopx/blob/main/docs/reference/protocols/computer-use-runtime-v0.md) (lines 68-71), the Kernel must never author a write-back itself. Instead, it acts on proposals:

1. The **Provider** returns its read-back payload to the Capability.
2. The **Capability** packages the payload into a **transition proposal**.
3. The **Kernel** inspects the proposal, checks authority and quota, then either **accepts** it (writing back state, creating todos/gates, updating quota) or **rejects** it (producing a controlled error).

Runtime enforcement occurs in [`loopx/extensions/governed_capability_execution.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/extensions/governed_capability_execution.py) (lines 224-340), where governed transition proposals require proper Kernel context before persistence.

### State Mutation Authority

Only the Kernel holds the sole authority to mutate durable state, including todos, gates, quota, and evidence. This centralized control guarantees that all state changes obey the system's contracts and quota limits.

## Key Differences Between the Paths

**Direction**: The capability-to-provider path moves forward (agent → capability → external side), while the Kernel writeback path moves backward (provider → capability → kernel).

**Responsibility**: The execution path determines *what* happens and *how* to invoke external systems. The control path determines *whether* results may persist and *how* core state changes.

**Error Handling**: Provider errors return to the capability for potential fallback suggestions. Kernel rejections occur when authority or quota checks fail, turning errors into controlled turn-settlements rather than system failures.

**State Mutation**: The execution path only produces read-back payloads. Only the Kernel performs actual state write-backs, such as creating new todos or updating quotas.

## Implementation in Code

The following examples illustrate how these paths interact in practice, from the capability module to the core control-plane.

First, the capability builds a provider request and wraps the response into a transition proposal:

```python
def run(self, ctx: CapabilityContext, args: dict) -> ProviderResponse:
    provider = ctx.provider_factory.get('git')
    # Provider executes external work (e.g., create a PR)

    response = provider.create_pull_request(
        repo=args["repo"], branch=args["branch"], title=args["title"]
    )
    # Wrap provider's read-back into transition proposal

    proposal = {
        "type": "github_pr_created",
        "payload": response,
        "author": ctx.agent_id,
    }
    return proposal

```

Then, the Kernel receives the proposal and decides whether to persist the changes:

```python
def handle_transition(self, proposal: dict) -> None:
    if not self.quota.can_spend(proposal["type"]):
        raise KernelError("Quota exceeded")
    # Kernel writes back durable state (e.g., a new Todo)

    self.state.todo.create(
        todo_id=proposal["payload"]["pr_number"],
        description=proposal["payload"]["title"],
        owner=proposal["author"],
    )

```

The first snippet typically resides in a capability module (e.g., `loopx/capabilities/issue_fix/`), while the second reflects the Kernel's implementation in [`loopx/kernel.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/kernel.py).

## Summary

- The **capability-to-provider execution path** delegates external work to providers without granting state mutation privileges.
- The **Kernel writeback control path** exclusively validates transition proposals and owns all durable state changes.
- **Transition proposals** bridge the two paths, carrying read-back payloads from capabilities to the Kernel for approval.
- Only the **Kernel** may mutate todos, gates, quota, or evidence after checking authority constraints.
- **Providers** operate in sandboxed contexts according to the protocol definitions in `docs/reference/protocols/`.

## Frequently Asked Questions

### Can a Provider directly modify LoopX state?

No. Providers operate in a sandboxed context and can only return read-back payloads. Direct state mutation is restricted to the Kernel writeback control path as enforced in [`docs/reference/protocols/computer-use-runtime-v0.md`](https://github.com/huangruiteng/loopx/blob/main/docs/reference/protocols/computer-use-runtime-v0.md) (lines 68-71).

### What happens if a transition proposal violates quota limits?

The Kernel rejects the proposal. In [`loopx/kernel.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/kernel.py), the `handle_transition` method raises a `KernelError` when `quota.can_spend()` returns false, preventing the state write-back and producing a controlled error response rather than allowing the mutation.

### How does the Capability know which Provider to invoke?

The Capability builds Provider requests using a provider factory available in the `CapabilityContext`. As shown in the execution diagram at [`README.md`](https://github.com/huangruiteng/loopx/blob/main/README.md) (line 438), the Capability defines *what* operation is needed, then retrieves the appropriate Provider implementation to handle the external execution.

### Why must the Kernel never author its own write-backs?

This constraint ensures that all state mutations flow through validated transition proposals, maintaining the separation of concerns. The Kernel only *accepts* or *rejects* proposals authored by capabilities, preventing arbitrary state changes and ensuring quota and authority checks apply consistently.