Advanced guide¶
The Tutorial is enough to build a complete, governed app. This guide covers the rest: how specs merge in detail, the tool governor and approvals in depth, other languages, and extending HarnessWeaver with your own plugins.
Tip
Read the tutorial first. These pages build on it and assume you know its words: spec, overlay, task, runner, session, guard, hook point.
In depth¶
| Page | Covers |
|---|---|
| Layers, locks and bounds | Every merge rule, lock form and bound, profile references and version ranges, provenance |
| The tool governor | The nine steps, the lethal trifecta, schema validation, idempotency, dry runs, sandboxed code |
| Approvals in depth | Requests, grants, how each runner resumes, crash safety, background runs |
Other languages¶
| Page | Covers |
|---|---|
| TypeScript | @harnessweaver/core and @harnessweaver/ai-sdk: the same spec in TypeScript apps, with Vercel AI SDK models |
| harnessd sidecar | The spec served over HTTP, for any language |
Extending HarnessWeaver¶
A module becomes a plugin by how it is designed, not by what it is called.
HarnessWeaver ships the plugins most apps need: model providers, the Pydantic AI adapter, a sandbox, OpenTelemetry export and full CEL. Anyone can build more, in their own repository, under any package name, and use them with no change to HarnessWeaver. First-party and third-party plugins use exactly the same contract. The plugins in this repository get no private hooks into the core, and the core registers its own built-in providers through that contract too.
What you can add¶
| Contribution | Declared with | Selected in the spec by | Page |
|---|---|---|---|
A provider for any port (Guardrail, PolicyEngine, ModelProvider, ContextProvider, Sandbox, Evaluator, ...) |
@hw.provider |
use: acme.pii in the module's section |
Providers and ports |
| Middleware on any hook point | @hw.middleware |
middleware: [{ use: acme.no_weekend_refunds }] |
Middleware |
| A routing stage | @hw.decider |
cascade: [{ use: acme.vip_rules }] |
Runners, deciders and adapters |
| A runner | @hw.runner |
tasks.<t>.runner: { use: acme.flow } |
Runners, deciders and adapters |
| An adapter for a client or agent framework | @hw.adapter |
Picked by harness.instrument() or harness.wrap() from the target's type |
Runners, deciders and adapters |
| Profiles | hw.Plugin(profiles={...}) |
extends: ["profile://acme.baseline@^1"] |
Plugins |
| Project templates | hw.Plugin(templates={...}) |
harnessweaver init -t acme.rag |
Plugins |
The public extension surface¶
Build only against these. They are versioned with the contract (RULES V1, V2), so a plugin keeps working across core releases within harnessweaver/v1:
harnessweaver.Pluginand the decoratorsprovider,middleware,decider,runner,adapter;- the port Protocols in
harnessweaver.ports; - the contract models exported from
harnessweaver(events, outcomes,GuardResult,Decision,ModelRequest,ToolResult, ...); harnessweaver.adapters(Binding,CallProvider), for adapters;harnessweaver.testing, including the conformance suite.
Anything else, and every module whose name starts with _, is internal and may change (RULES C7). The Python API reference documents this surface.
The rules plugins live by¶
- Installing is not enabling. Installing a plugin activates nothing. Only names the effective spec refers to are imported, and plugin modules must do no I/O and register nothing at import time (RULES S8).
- The spec assigns bands, not the plugin. A plugin can't put its middleware in the
baselineband; only an org profile can (R1, R2). - Orgs decide what's allowed. A baseline can lock
plugins.allowto a list of namespaces. - Contracts are declared. Every plugin and contribution declares the contract range it was built against (
>=1.0,<2), and the loader refuses an incompatible one (V5). - Conformance is shared. Every plugin can run the same conformance suite the first-party plugins pass (T5).
- No framework types in contracts. Hook payloads, ports and results hold only HarnessWeaver types (R7).
- Probabilistic components never grant (R3): a judge or classifier can only tighten a decision.
Start here¶
uv run harnessweaver plugin new acmescaffolds a standalone package with a sample guard and tests that run the conformance suite.- Read Plugins for packaging, namespaces and loading.
- Pick the contribution you need from the table above.
- Run
pytest --harnessweaver-conformance=acme(Conformance). - Publish it under any name. Apps add the package and write
use: acme.<name>.
For TypeScript plugins, see TypeScript.