Abilities
This page covers what an ability actually is, day to day — its
structure, and how to publish/add/remove one. For the full design
reference — why copying beats importing, secrets management in the
Admin UI, and the open questions — see Ability
System instead; this page is the shorter, practical
version, and bin/ability-manager.ts is where the mechanics below live
in the source tree.
What it is
A loopengine ability is a bundle of tool files, a skill directory,
and actauth rules, installed by copying files into an agent's own
tree — never as a node_modules import. The three pieces normally get
hand-authored separately with nothing tying them together (a tool with
no rule is blocked outright by default_decision; a tool with no skill
may go unused if its purpose isn't obvious from its description alone);
an ability packages all three as one shareable, installable unit
instead.
Private vs. public
Nothing in the format below distinguishes the two — the difference is
only where you publish and what your tools' own fetch() calls
actually point at:
| Private | Public | |
|---|---|---|
| Example | get_order_onway/get_order_shipments_detail hardcoding one company's own API shape (its specific query params, its specific endpoints) |
A tool built against a genuinely multi-tenant API — Stripe, Shopify, Zendesk |
| Reusable by | The same company's own agents and environments (staging vs. production, different mailboxes) | Any company's agents — the API itself doesn't care whose tenant is calling |
| Published to | A private registry, a scoped @company/pkg, or just a git repo — never intended for a public catalog |
The public npm registry |
Most abilities most companies will ever write are the private kind — internal-reuse bundles like the example above, not something that could be usefully installed by a stranger's agent since nobody else's backend speaks that exact API. A public ability is the narrower case, and it's the only kind a future public catalog/marketplace (not built yet — see Ability System) would ever make sense for; a private ability has no reason to appear in one.
Scope and structure
An ability is a directory, published like any npm package:
my-order-tools/
package.json # name, version — an ordinary npm package
loopengine.ability.json # the manifest
tools/
get_order_onway.ts
get_order_shipments_detail.ts
skills/
order-lookup/
SKILL.md
actauth/
rules.yml
| Manifest field | Points at | Notes |
|---|---|---|
loopengineVersion |
— | A semver range, checked against the installing project's own loopengine dependency before anything is written. |
tools |
File paths | Each expected to export const <camelCase>: ToolDefinition — the same shape the Web UI's HTTP tool builder already generates. |
skills |
Directory paths | Each a complete SKILL.md (+ any assets alongside it), copied as-is. |
actauth |
One YAML file | Rule objects — same name/scope/tool/decision shape as a hand-written actauth.yml. |
env |
— | Optional. Every process.env.X the ability's tools actually read, declared once rather than buried per tool file. secret: true means the Admin UI's Environment tab never echoes the value back. |
No name/version in the manifest itself — those come from the
ability's own sibling package.json, which already has to exist and
carry real values for npm pack to treat the directory as fetchable at
all. A tool or skill name that collides with one already installed
doesn't refuse outright — it installs namespaced under the ability's own
name instead (tools/<ability-name>__<name>.ts,
skills/<ability-name>/<id>/); an actauth rule name collision does
refuse, since two rules can't share one name in the same file.
Publishing
No tooling beyond loopengine.ability.json itself — npm publish from
a directory shaped as above is a complete, valid ability. Public
registry, a private one (a scoped @company/pkg, GitHub Packages, a
self-hosted Verdaccio), or just a tagged commit in a plain git repo
with no registry at all — anything npm pack itself accepts. Auth for
a private target comes entirely from whatever .npmrc token or SSH
key/git-credential helper is already configured in the environment
running the command.
Adding
npx loopengine add-ability <spec> --agent <name>
<spec> is resolved exactly like npm pack would — a public/private
package name, @company/pkg, github:org/repo#v1.0.0,
git+ssh://..., or file:../local-path for testing. Refuses outright,
before writing anything, on the first failing check: the version range
above, then an actauth rule name collision. Once past those, tool
files and skill directories get copied in, tools/index.ts and
actauth.yml get patched, and provenance is recorded in
agents/<name>/.loopengine-abilities.json — the merge base a future
upgrade needs, and what tells the Admin UI which env vars to prompt for.
Upgrading and removing
npx loopengine upgrade-ability <abilityName> --agent <name> [--spec <spec>]
npx loopengine remove-ability <abilityName> --agent <name> [--force]
Upgrading three-way-merges each managed file against what changed
upstream since install — a hand-edit survives a clean merge; a real
conflict leaves <<<<<<< markers instead of silently overwriting
either side. Removing deletes exactly the files provenance recorded,
refusing any that look hand-modified beyond what a normal upgrade would
have produced, unless --force is passed.