Agents#
Compose multiple tools behind a single agent manifest.
What is an “agent”?#
An agent is a composition layer: it declares which tools it can call. The agent manifest doesn’t execute code itself. It is a package artifact that enumerates tools (with versions/ranges), prompt examples, and future reserved references so the CLI/SDKs can resolve, install, and expose the tool graph to your agent runtime.
- Defines capability surface by listing tools the agent may invoke.
- Drives deterministic installs via
agent.lock(package identity + integrity + relationships). - Keeps host/runtime lightweight: each tool runs in a managed subprocess with its own dependencies.
- Preserves future composition metadata for
skills,knowledge,memory, andprofileswithout resolving them yet.
Scaffold an agent#
agentpm init --kind agent --name research-assistant --description "Assistant composed of multiple tools"Generated skeleton (agent.json):
{
"kind": "agent",
"name": "research-assistant",
"version": "0.1.0",
"description": "Assistant composed of multiple tools",
"tools": [],
"skills": [],
"knowledge": [],
"memory": [],
"profiles": [],
"examples": [
{
"title": "Example prompt",
"prompt": "Describe the user request this agent should handle."
}
]
}Add tools to tools[], then run agentpm install to resolve/download artifacts.
Field reference (overview)#
| Field | Type | Required | Notes |
|---|---|---|---|
$schema | string | no | URI to this schema (optional but recommended) |
kind | enum | yes | "agent" or "tool" (discriminator) |
name | string | yes | ^[a-z][a-z0-9-]{0,63}$ |
version | semver | yes | SemVer string (supports pre/metadata) |
description | string | yes | Free text |
tools | array | yes | Array of tool refs: string or {name, version} |
skills | array | no | Reserved future refs. Validated and preserved, but not resolved today. |
knowledge | array | no | Reserved future refs. Validated and preserved, but not resolved today. |
memory | array | no | Reserved future refs. Validated and preserved, but not resolved today. |
profiles | array | no | Reserved future refs. Validated and preserved, but not resolved today. |
examples | array | no | Inline prompt examples { title, prompt }. |
readme | string | no | Path to README file. Will automatically look for README.md if not specified. |
license | object | no | { spdx: "license spdx", file: "Path to LICENSE file" } |
Declaring tools#
You can reference tools using either a string spec or an object. Both carry the same information; choose one style per team preference.
String spec (concise)#
{
"tools": [
"@zack/summarize@0.1.2"
]
}Object form (explicit)#
{
"tools": [
{ "name": "@zack/summarize", "version": "0.1.2" }
]
}Installing tools for an agent#
Once tools[] is declared, run:
agentpm install- Resolves versions.
- Downloads tool artifacts and prepares them under:
.agentpm/tools/<namespace>/<name>/<version> - Populates/updates the lockfile
agent.lockwith package identity, integrity, and dependency relationships. - Uses the download cache at
.agentpm/cache(use--refreshto bypass).
For a local kind: "agent" manifest, AgentPM does not copy that manifest into .agentpm/agents. The local agent.json remains the source of truth.
You can also add & install in one step:
agentpm install @zack/summarize@0.1.2
# writes/updates tools[] and installsDirect package install vs manifest-driven install#
AgentPM supports two different install workflows for agents:
Manifest-driven install#
agentpm install- reads the local
agent.json - resolves the local manifest's
tools - writes a
local:agentroot intoagent.lock - installs tools into
.agentpm/tools/... - does not write the local manifest under
.agentpm/agents
Direct package install#
agentpm install @zack/support-agent@0.1.0- resolves the requested package by identity
- if the package is an agent, installs the agent artifact into
.agentpm/agents/... - reads the installed agent manifest and resolves its tool dependencies
- installs those tools into
.agentpm/tools/... - writes an
agent:@namespace/name@versionroot intoagent.lock
Lockfile v2 (high level)#
agent.lock v2 records package identity and relationships instead of only a flat tool map.
At a high level it contains:
packages- keys like
tool:@zack/summarize@0.1.2 - keys like
agent:@zack/support-agent@0.1.0
- keys like
rootslocal:agentfor local manifest installsagent:@namespace/name@versionfor registry-installed agents
That is what lets AgentPM:
- distinguish manifest-driven local installs from installed registry agents
- keep multiple versions of the same tool when different agents need different versions
- expose resolved tool refs from installed agents through the SDKs
Example: two agents, two versions of the same tool#
If:
@zack/support-agent@0.1.0resolves@zack/slack-post-message@0.1.1@zack/escalation-agent@0.1.0resolves@zack/slack-post-message@0.2.0
then both tool versions can coexist in agent.lock and on disk:
.agentpm/tools/zack/slack-post-message/0.1.1/.agentpm/tools/zack/slack-post-message/0.2.0/
Lockfile v2 keeps those package identities separate instead of collapsing them into one flat tool entry.
How agents and tools work together#
- Your app (Node or Python) uses the SDK to load callable tool functions based on the agent’s
tools[]. - Each tool executes in its own subprocess (correct interpreter/runtime), keeping the host app clean and language-agnostic.
- The agent manifest + lockfile make the toolset portable and reproducible across dev/CI/prod.
Best practices#
- Pin for prod: Exact versions in
tools[], commitagent.lock. - Gate in CI:
agentpm lint --strict
agentpm install --frozen --quiet- Name & describe well: Clear
name/descriptionhelps discovery and registry docs. - Evolve safely: Bump the agent’s
versionwhen you change its tool set or operational contract.
Tools are the only resolved dependency type today. skills, knowledge, memory, and profiles are validated and preserved in the manifest and lock metadata, but AgentPM does not resolve or install them yet.