Tools#
Define a single, runnable capability that agents (or your app) can call.
What is a “tool”?#
A tool is a self-contained skill that an agent (or your app) can call to get real work done (summarize text, create a ticket, query a DB, call an internal API). In AgentPM, a tool:
- Exposes a typed interface via
inputsandoutputs(JSON Schema), so agents know exactly what to pass and what to expect. - Becomes a callable function through the SDKs; the agent (or your app) invokes it just like any other tool/function in its runtime.
- Runs in a managed subprocess, isolating dependencies from the agent host so Node ↔ Python mixes are safe and deterministic.
- Advertises capabilities (name, description, schema) that agent planners can use for tool selection and argument construction.
- Publishes portable artifacts (manifest + files) that agents can install, verify, and reuse across stacks and languages.
Scaffold a tool#
agentpm init --kind tool --name summarize --description "Summarize input text"Generated skeleton (agent.json):
{
"kind": "tool",
"name": "summarize",
"version": "0.1.0",
"description": "Summarize input text",
"files": [],
"entrypoint": {
"command": "",
"args": []
},
"inputs": {},
"outputs": {}
}You’ll need to complete this manifest before publish. Run agentpm lint for guidance.
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 |
entrypoint | string | yes | Execution ref {command, args, cwd, timeout_ms, env} |
inputs | object | yes | JSON Schema (or shape) for inputs |
outputs | object | yes | JSON Schema (or shape) for outputs |
files | string[] | yes | Non-empty list of paths/globs to package |
runtime | object | no | { type: "python or node", version: "MAJOR[.MINOR[.PATCH]]" } |
environment | object | no | Dictionary of required or optional env variables {required, description, default} |
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" } |
Defining the entrypoint#
"entrypoint": {
"command": "node", // interpreter: node|nodejs|python|python3 (or absolute path)
"args": ["dist/summarize.js"], // script/module path (repo-relative)
"cwd": ".", // optional working dir
"timeout_ms": 60000, // optional execution timeout
"env": { } // optional env vars passed to subprocess
},
"runtime": {
"type": "node",
"version": "20" // major or full semver your tool requires
}Lint enforces that runtime.type matches the interpreter implied by entrypoint.command.
Defining the environment#
Use agent.json → environment.vars to declare the env vars your tool expects. These are tool-facing variables (API keys, endpoints, knobs) that the SDK merges into the subprocess from what you pass to load(...env=…).
- Keys must be UPPER_SNAKE_CASE (
^[A-Z][A-Z0-9_]*$). - Each var has:
required: booleandescription: string- optional
default: string(used if the caller doesn’t supply a value)
{
"environment": {
"vars": {
"OPENAI_API_KEY": {
"required": true,
"description": "API key for OpenAI"
},
"OPENAI_BASE_URL": {
"required": false,
"description": "Custom API endpoint; defaults to https://api.openai.com/v1",
"default": "https://api.openai.com/v1"
}
}
}
}If a tool declares required environment variables without a default, the SDK load() function will fail immediately when that variable is missing. Provide the value by passing it per-call via load().
Notes
- These declarations power docs in the registry UI and validation in the SDKs.
Defining inputs and outputs (JSON Schema)#
Both inputs and outputs are any valid Draft 2020-12 JSON Schema. Below are common patterns—mix and match as needed.
1) Minimal object with a required field#
"inputs": {
"type": "object",
"properties": {
"text": { "type": "string", "description": "Text to process" }
},
"required": ["text"],
"additionalProperties": false
},
"outputs": {
"type": "object",
"properties": {
"summary": { "type": "string" }
},
"required": ["summary"],
"additionalProperties": false
}2) Optional params with defaults (document in description)#
"inputs": {
"type": "object",
"properties": {
"text": { "type": "string" },
"max_sentences": { "type": "integer", "minimum": 1, "maximum": 10, "description": "Default: 3" }
},
"required": ["text"],
"additionalProperties": false
}3) Enums, unions, and nullable#
"inputs": {
"type": "object",
"properties": {
"text": { "type": "string" },
"style": { "type": "string", "enum": ["bullet", "abstract", "headline"] },
"language": {
"oneOf": [
{ "type": "string", "enum": ["en","es","fr","de"] },
{ "type": "null" }
],
"description": "If null, auto-detect."
}
},
"required": ["text"],
"additionalProperties": false
}4) Arrays and item schemas#
"inputs": {
"type": "object",
"properties": {
"documents": {
"type": "array",
"items": { "type": "string", "minLength": 1 },
"minItems": 1
}
},
"required": ["documents"],
"additionalProperties": false
}5) Numbers with constraints (good for budgets/limits)#
"inputs": {
"type": "object",
"properties": {
"budget_ms": { "type": "number", "minimum": 0, "maximum": 10000 }
},
"required": ["budget_ms"],
"additionalProperties": false
}6) Nested objects and patternProperties#
"inputs": {
"type": "object",
"properties": {
"text": { "type": "string" },
"metadata": {
"type": "object",
"patternProperties": {
"^[a-zA-Z_][a-zA-Z0-9_]*$": { "type": ["string","number","boolean"] }
},
"additionalProperties": false
}
},
"required": ["text"],
"additionalProperties": false
}7) Discriminated unions (advanced)#
"inputs": {
"oneOf": [
{
"type": "object",
"properties": { "mode": { "const": "single" }, "text": { "type": "string" } },
"required": ["mode","text"],
"additionalProperties": false
},
{
"type": "object",
"properties": { "mode": { "const": "batch" }, "documents": { "type": "array", "items": { "type": "string" }, "minItems": 1 } },
"required": ["mode","documents"],
"additionalProperties": false
}
]
}Guidance:
- Prefer
type:"object" + properties + requiredfor clarity. - Use
additionalProperties:falseto catch typos early. - Document sensible defaults in
descriptionor add an output field likeused_defaultsif the tool applies them.
Packaging files#
Include everything your tool needs at runtime:
"files": [
"dist/**",
"prompts/*.md",
"models/*.bin"
]- Paths are repo-relative; globs/directories are supported.
- The published archive preserves relative paths.
- Make sure your
entrypoint.argspoints at a packaged file.
Best practices#
- Strong schemas: Validate early with
agentpm lint --strict. - Env & timeouts: Declare any required env vars in docs; set
timeout_msto bound execution. - Runtime clarity: Keep
runtime.type/versionin sync with your actual interpreter. - Determinism: Pin
version, publish with CI, and let consumers lock viaagent.lock. - Docs from manifest: Good
description+ field descriptions render as rich docs in the registry.
Next steps#
- Fill in
entrypoint,inputs,outputs, andfiles. - Run:
agentpm lint --strict
agentpm publish --dry-run- When ready:
agentpm publish- See the
Agentspage next for composing multiple tools.