Extend Harn
Five things in Harn are meant to be extended by you. They are documented separately because they are genuinely different mechanisms; this page is the map.
| You want to | Reach for | Ships as |
|---|---|---|
| Give an agent a new action | a custom tool | a package that exports one tool |
| Share Harn code across projects | a package | a versioned harn.toml package |
| Reach an outside service | a connector | a package with connector metadata |
| Teach an agent a procedure | a skill | a signed SKILL.md |
Add a harn subcommand | a CLI extension | a .harn script the CLI dispatches |
Everything you ship can be signed
Before the five, the thing that makes shipping any of them safe.
harn pack walks an entrypoint's transitive imports, links one closed program,
snapshots the provider catalog and stdlib pin, generates an SBOM, and writes a
deterministic .harnpack container. With --sign it embeds an Ed25519
signature over the bundle hash:
harn skill key generate --out signing-key.pem
harn pack agent.harn --sign --key signing-key.pem --exclude-secrets
harn pack verify agent.harnpack
wrote agent.harnpack (3879 bytes, bundle_hash blake3:e045e81a…)
ok agent.harnpack (bundle_hash blake3:e045e81a…, signature_verified=true)
verify recomputes the canonical bundle hash, checks the signature, and
cross-checks every archive entry's BLAKE3 against the manifest. Change one byte
anywhere in the bundle and it exits non-zero with a hash mismatch rather than
quietly accepting it.
--exclude-secrets refuses to bundle paths that look like credentials
(.env, *.pem, *.key, credentials*, anything under secrets/) and
reports each skipped asset in the manifest. It is off by default, so pass it
from any pipeline that shares bundles outside your own machine.
Skills carry their own signatures rather than relying on the bundle's:
harn skill sign writes a detached SKILL.md.sig, and a skill declaring
require_signature = true is omitted from the startup registry unless its
signature chain verifies. See Skill provenance.
Custom tools
A tool is one action an agent can call. harn tool new scaffolds a package
that exports exactly one:
harn tool new summarize-diff --description "Summarize a git diff"
Use this when the capability is a single verb with typed parameters. For a tool
defined inline in the program that uses it, the tool declaration in
Builtin functions is simpler and needs no package.
- Tool surface validation — the checks Harn runs over a tool registry before a loop spends tokens on it.
- Preset tool hooks and Hooks — intercepting calls rather than adding one.
- Long-running tools — starting slow work and collecting the result on a later turn.
Packages
A package is versioned Harn code with a harn.toml manifest: exported
functions, custom tools, [llm] adapters, and dependencies. It is the unit
that harn add, harn install, and the package index move around.
- Package authoring — manifest shape, exports, and the publishing path.
Connectors
A connector is a package that also declares how to reach an outside service: its auth type, required scopes, required secrets, and the operations it exposes. That declaration is what lets a host show a "Connect" button and report a connector as installed but not yet usable, instead of failing at call time.
- Connector authoring — package layout and setup metadata.
- Connector testkit — exercising one without live credentials.
- Connector OAuth — provider-specific flows.
- Connector parity matrix — what is wired today.
Skills
A skill is procedural knowledge: a SKILL.md with frontmatter describing when
it applies, which tools it may use, and what paths it concerns. Harn discovers
skills across layers (project, user, package, system) and selects them per
task.
- Skills — discovery, layers,
harn.tomlconfiguration, and selection. - Skill provenance — Ed25519 signing, endorsement, and the trust map.
- Skill activation evidence — proving a skill earned its place.
CLI subcommands
Harn subcommands can themselves be written in Harn. The CLI dispatches to a
.harn script, and std/cli/argparse, std/cli/envelope, and
std/cli/render give it the same argument parsing, --json envelope, and
output rendering the built-in commands use.
- Extending the CLI in
.harn— the dispatch shim and how to add or port a subcommand without writing Rust. std/cli/argparse,std/cli/envelope,std/cli/render,std/cli/paths— the supporting modules.
Which one do I want?
If you are adding a verb, write a tool. If you are adding a service, write a connector — it is a package with the extra metadata a host needs to get you credentials. If you are adding know-how rather than a capability, write a skill. If you are adding a command you run yourself, extend the CLI. A package is the container the first three ship in.