Skip to main content
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:
extensions/warehouse/

Declare the extension

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 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:
extensions/warehouse/extension.py
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

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:
extensions/warehouse/extension.yaml
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.

Add lifecycle behavior

Declare exactly which Harnest surfaces the extension contributes.