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

# Create a Harnest Extension

> Author the Harnest Extension manifest, singleton, typed invocation context, and dependency contract.

From the agent folder, create a root-owned folder under `extensions/`. The folder name is the extension identity and must be a valid Python identifier. The CLI creates the canonical manifest, module, and dependency metadata together:

```bash theme={null}
harnest extensions init warehouse
```

```text extensions/warehouse/ theme={null}
extensions/warehouse/
├── extension.yaml
├── extension.py
├── README.md            optional package documentation
├── pyproject.toml       optional SDK dependencies
├── lib/                 private extension helpers
├── lifecycle/           lifecycle contributions
├── mcp/                 managed MCP contributions
├── skills/              managed Agent Skill contributions
├── subagents/           managed SubAgent contributions
└── tools/               managed Agent Tool contributions
```

## Declare the extension

<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
  contributes:
    lifecycle: [lifecycle/]
    mcp: [mcp/]
    skills: [skills/]
    subagents: [subagents/]
    tools: [tools/]
  capabilities:
    - content.mcp
    - content.skills
    - content.subagents
    - content.tools
  ```

  ```toml extensions/warehouse/pyproject.toml theme={null}
  [project]
  name = "harnest-extension-warehouse"
  version = "1.0.0"
  requires-python = ">=3.11,<3.14"
  dependencies = ["warehouse-sdk>=2,<3"]
  ```
</CodeGroup>

`metadata.name` must match the folder. The optional PEP 621 distribution name must be `harnest-extension-<name>` and its version must match `extension.yaml`. The prefix prevents an extension from colliding with an SDK distribution that uses the provider name. Static dependencies join the root environment solve.

For a local extension, declare only extension-owned dependencies, such as `warehouse-sdk` above. Do not pin `harnest` or compiler-owned framework packages; upgrade Harnest to change its runtime versions. Published wheels can carry those requirements for standalone installation, but [Harnest's installer](/docs/harnest/build/extensions/use) leaves their versions to the pinned runtime.

A distributable extension may include one regular root `README.md` and reference it from `project.readme`. Package that file with `extension.yaml` and `extension.py` so PyPI renders the same reviewed documentation that Harnest preserves during installation. Harnest rejects links, special files, and unexpected root resources.

`contributes` is the only content projection contract. Harnest does not infer content from folder names. Each value is a package-relative directory; paths must exist, remain inside the package, and cannot overlap. You may use conventional paths as above or a custom source such as `resources/tools/`. Harnest installs the complete package under `extensions/<name>/` and composes declared content from there—it does not copy files into the agent's root `tools/`, `mcp/`, or other authored folders. Omitting `contributes` creates a runtime-only extension.

## Export the application-owned singleton

`extension.py` exports one public `Extension` subclass and the singleton named `extension`. Keep SDK clients on that singleton, and expose a bounded invocation view through `ExtensionContext`:

```python extensions/warehouse/extension.py theme={null}
import os

from harnest.extensions import Extension, ExtensionContext
from warehouse_sdk import WarehouseClient


class WarehouseContext(ExtensionContext):
    """Expose bounded warehouse operations during one invocation."""

    __slots__ = ("_owner",)

    def __init__(self, extension_name: str, owner: "Warehouse") -> None:
        """Bind the revocable context to its application-owned extension."""

        super().__init__(extension_name)
        self._owner = owner

    async def query(self, statement: str) -> list[dict]:
        """Run one query while the Harnest invocation remains active."""

        self._require_active()
        return await self._owner._query(statement)


class Warehouse(Extension[WarehouseContext]):
    """Own one warehouse SDK client for the application lifetime."""

    def __init__(self) -> None:
        """Defer all external connection work until runtime startup."""

        self._client = None

    async def start(self, _context) -> None:
        """Connect after dependency-ordered application startup begins."""

        self._client = await WarehouseClient.connect(
            endpoint=os.environ["WAREHOUSE_ENDPOINT"],
        )

    async def stop(self) -> None:
        """Release the application-owned SDK client."""

        # Shutdown must also be safe after a partial startup failure.
        if self._client is not None:
            await self._client.close()
            self._client = None

    def create_context(self, base: ExtensionContext) -> WarehouseContext:
        """Create one typed, revocable view for the active invocation."""

        return WarehouseContext(base.extension_name, self)

    async def query(self, statement: str) -> list[dict]:
        """Route public calls through the current invocation context."""

        return await self.context.query(statement)

    async def _query(self, statement: str) -> list[dict]:
        """Cross the private SDK boundary after startup validation."""

        # Calls fail closed if they escape the managed application lifetime.
        if self._client is None:
            raise RuntimeError("Warehouse extension is not started")
        return await self._client.query(statement)


extension = Warehouse()
```

Harnest imports extension modules during compilation but does not call `start()` or connect to services. Runtime startup activates extensions in dependency order and calls `stop()` in reverse order.

## Add optional extension content

| Contribution key | Purpose                       | Required manifest capability           |
| ---------------- | ----------------------------- | -------------------------------------- |
| `lifecycle`      | Lifecycle hooks and factories | The capability matching each decorator |
| `tools`          | Managed Agent Tools           | `content.tools`                        |
| `mcp`            | Managed MCP clients           | `content.mcp`                          |
| `skills`         | Managed Agent Skills          | `content.skills`                       |
| `subagents`      | Managed SubAgents             | `content.subagents`                    |

`lib/` remains private implementation and is never a contribution. Managed mode composes declared content into the owning agent. Advanced mode accepts declared lifecycle hooks and factories but rejects declared managed content because the native target owns its own composition.

## Add extension dependencies

Use `requires.extensions` when this extension depends on another local Harnest Extension:

```yaml extensions/warehouse/extension.yaml theme={null}
requires:
  extensions: [credentials]
```

Harnest rejects missing dependencies and cycles. Extension Python dependencies share one solve with the root project; incompatible constraints fail `harnest env sync` instead of creating isolated environments.

```bash theme={null}
harnest env sync .
harnest test .
```

<Card title="Add lifecycle behavior" icon="arrows-rotate" href="/docs/harnest/build/extensions/lifecycle">
  Declare exactly which Harnest surfaces the extension contributes.
</Card>
