> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usefused.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Harnest Extension lifecycle

> Connect extension startup, invocation context, hooks, storage, telemetry, and auditing to Harnest lifecycle.

A Harnest Extension participates in three lifecycle layers:

| Layer                       | Authoring location                                           | Lifetime                                       |
| --------------------------- | ------------------------------------------------------------ | ---------------------------------------------- |
| SDK startup and shutdown    | `Extension.start()` and `Extension.stop()` in `extension.py` | Application process                            |
| Typed access                | `Extension.create_context()`                                 | One managed invocation                         |
| Harnest hooks and factories | `extensions/<name>/lifecycle/**/*.py`                        | The lifecycle phase declared by each decorator |

The extension manifest must declare every Harnest capability its lifecycle files contribute. Declaration makes ownership inspectable; it does not grant access to undeclared runtime internals.

Storage authorities start first. Harnest then calls `Extension.start()` in dependency order, followed by contributed `@lifecycle.resource` factories. Shutdown closes extension resources before calling `Extension.stop()` in reverse dependency order, then closes storage. `ExtensionStartContext` therefore exposes only already-live named custom storage and declared continuations, not arbitrary lifecycle resources or invocation credentials.

## Declare and implement a hook

<CodeGroup>
  ```yaml extensions/warehouse/extension.yaml theme={null}
  apiVersion: harnest.dev/v1alpha1
  kind: Extension
  metadata:
    name: warehouse
    version: 1.0.0
  runtime:
    entrypoint: extension:extension
  capabilities:
    - lifecycle.tool
  ```

  ```python extensions/warehouse/lifecycle/tool_policy.py theme={null}
  from harnest.lifecycle import lifecycle


  @lifecycle.tool.before(order=-50)
  async def restrict_warehouse_writes(context, request):
      """Require approved naming for model-selected warehouse writes."""

      # This extension owns policy only for the write tools it contributes.
      if context.tool_name.startswith("warehouse_write_"):
          return context.finish({"error": "use_an_approved_write_tool"})
      return context.next()
  ```
</CodeGroup>

Application-owned and extension-owned lifecycle files form one globally validated lifecycle. Lower `order` values run first. Extension dependency order and source location break ties. Duplicate singleton authorities or named resources fail compilation rather than shadowing one another.

## Choose a declared capability

| Manifest capability                                                                                         | Contribution from the extension                 |
| ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
| `lifecycle.agent`, `.model`, `.tool`, `.mcp`, `.http`, `.skills`                                            | Portable interception and dynamic skill sources |
| `context.resources`, `.credentials`, `.continuations`, `.storage`, `.assets`, `.session`, `.skills`, `.mcp` | Scoped runtime access used by the extension     |
| `content.tools`, `.mcp`, `.skills`, `.subagents`                                                            | Managed-mode content                            |
| `storage.sessions`, `.checkpoints`, `.assets`, `.custom`                                                    | Storage factories                               |
| `http.routes`                                                                                               | Application HTTP routes                         |
| `native.adk`, `native.langgraph`                                                                            | Framework-native integration                    |
| `policy.output`, `telemetry.exporter`                                                                       | Output policy or telemetry destinations         |

Declare only the rows the extension actually uses. Advanced mode still composes Harnest-owned boundaries, but it cannot intercept an opaque native path that bypasses Harnest.

## Audit committed mutations

Wrap committed user- or agent-triggered writes with `extension_mutation(...)`. It emits correlated, payload-free OTEL audit events without recording arguments, credentials, or results:

```python extensions/warehouse/extension.py theme={null}
from harnest.extensions import extension_mutation


async def _create_export(self, query_id: str):
    """Audit the committed SDK mutation without exposing its payload."""

    async with extension_mutation("warehouse", "export.create", trigger="agent"):
        return await self._client.create_export(query_id)
```

For external work that must survive a replica stopping, declare `context.continuations` and follow [Durable execution](/harnest/runtime/durable-execution). The extension persists bounded continuation metadata; it does not resume a suspended Python process.

<Card title="Use the extension" icon="plug" href="/harnest/build/extensions/use">
  Call the bounded public API from an Agent Tool or other trusted invocation code.
</Card>
