Observed since 20 Oct, 22:55 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
AgentPM™ Python SDK
A lean, typed Python SDK for AgentPM tools and installed agent, Knowledge, Memory, Profile, and Loop packages. It discovers tools installed by agentpm install, executes their entrypoints in a subprocess, and can also inspect installed agent manifests plus their resolved dependency refs.
.agentpm/tools (project) and ~/.agentpm/tools (user), with AGENTPM_TOOL_DIR override..agentpm/agents and exposes their resolved tool and skill refs from agent.lock..agentpm/skills and exposes their manual content plus resolved tool refs..agentpm/knowledge and exposes mode-specific metadata and canonical paths..agentpm/memory and exposes authored blueprint metadata, build metadata, contract indexes, and resolved contract paths..agentpm/profiles and exposes authored role, objective, and communication metadata..agentpm/loops and exposes authored phase, transition, and error-policy metadata.node or python (whitelisted) and exchanges JSON over stdin/stdout.with_meta=True returns func + meta (name, version, description, inputs, outputs).Requires Python 3.10+.
Using uv:
uv pip install agentpm
Or with standard pip:
python -m pip install agentpm
If you'll use the optional LangChain adapter:
uv pip install 'agentpm[langchain]'
# or
python -m pip install 'agentpm[langchain]'
uv)# create and activate a venv
uv venv
source .venv/bin/activate
# install SDK in editable dev mode (ruff/black/mypy/pytest, etc.)
uv pip install -e ".[dev]"
# sanity checks
uv run ruff check .
uv run black --check .
uv run mypy
uv run pytest -q
If you're not using
uv, standardpython -m venv+pip install -e ".[dev]"works too.
from agentpm import load
# Spec format: "@scope/name@version"
summarize = load("@zack/summarize@0.1.0")
result = summarize({"text": "Long document content..."})
print(result["summary"])
from agentpm import load
tool = load("@zack/summarize@0.1.0", with_meta=True)
summarize, meta = tool["func"], tool["meta"]
rich_description = (
f"{meta.get('description','')} "
f"Inputs: {meta.get('inputs')}. "
f"Outputs: {meta.get('outputs')}."
)
print(rich_description)
print(summarize({"text": "hello"})["summary"])
from agentpm import (
load,
load_agent,
load_knowledge,
load_loop,
load_memory,
load_profile,
load_skill,
)
agent = load_agent("@zack/support-agent@0.1.0")
docs = load_knowledge("@zack/python-docs@0.1.0")
loop = load_loop("@zack/incident-response-loop@0.3.0")
memory = load_memory("@zack/profile-memory@0.1.0")
profile = load_profile("@zack/support-style@0.1.0")
first_skill = agent["resolvedSkills"][0]
skill = load_skill(f'{first_skill["name"]}@{first_skill["version"]}')
first_tool = skill["resolvedTools"][0]
tool = load(f'{first_tool["name"]}@{first_tool["version"]}')
print(agent["resolvedKnowledge"])
print(agent["resolvedLoop"])
print(agent["resolvedMemory"])
print(agent["resolvedProfiles"])
print(loop["loop"]["transitions"])
print(docs["knowledge"]["mode"])
print(memory["contracts"])
print(profile["profile"]["communication"])
load_agent() returns:
resolvedKnowledge from agent.lockresolvedLoop from agent.lockresolvedMemory from agent.lockresolvedProfiles from agent.lockknowledge, memory, profiles) as metadataresolvedTools from agent.lockresolvedSkills from agent.lockIt does not execute the agent package or orchestrate the tools for you.
Compatibility note:
resolvedKnowledge is populated from the modern first-class root.knowledge entries in agent.lock.reserved.knowledge is legacy pass-through metadata from older lockfile shapes. For current installs, treat resolvedKnowledge as the authoritative Knowledge dependency list and expect reserved.knowledge to usually be empty.reserved.knowledge, rerun agentpm install to rewrite the lockfile before expecting resolvedKnowledge to be populated.resolvedLoop is populated from the modern first-class root.loop entry in agent.lock.resolvedProfiles is populated from the modern first-class root.profiles entries in agent.lock.reserved.profiles is legacy pass-through metadata from older lockfile shapes. For current installs, treat resolvedProfiles as the authoritative Profile dependency list and expect reserved.profiles to usually be empty.manifest["loop"] and manifest["bindings"] preserve the authored declarative metadata from the installed agent.json.This is the Python mirror of the Node SDK’s loadAgent() flow:
load()from agentpm import BeforeToolCallDecision, BeforeToolCallInput, HarnessClient
harness = HarnessClient(agent="@zack/support-agent@0.1.0")
def model_provider(request):
return {
"id": "turn-1",
"assistant_content": "Handled by the host model.",
"actions": [],
"usage": {},
"finish_reason": "stop",
"provider_metadata": {"model": request["selection"]["model"]},
}
def before_tool_call(input: BeforeToolCallInput) -> BeforeToolCallDecision:
return {"decision": "continue", "patch": {"arguments": input["arguments"]}}
harness.register_model_provider("company-model", model_provider)
harness.on_before_tool_call(before_tool_call)
harness.on_approval(lambda checkpoint: "approve")
result = harness.run("Use the configured agent.")
harness.shutdown()
print(result)
agent is optional. When set, it is passed to agentpm harness as either an installed Agent package ref such as @zack/support-agent@0.1.0 or a local manifest path such as ./agent.json; when omitted, Harness uses its normal workspace discovery/default Agent selection. Register host services before starting a run. The SDK launches agentpm harness --machine, correlates request/response frames, streams Harness events, and routes host-service callbacks for model providers, embedding providers, Knowledge runtimes, hooks, and approvals.
The convenience Hook helpers use contract-specific type hints. on_before_model_request may return context_sections and provider_options, on_before_tool_selection may return candidate_ids, on_before_tool_call may return replacement arguments, on_before_knowledge_request may shape the same package request options, and on_after_knowledge_retrieval may filter/reorder existing results or transform model-visible text while retaining result identity. Direct Memory hook helpers can shape authorized read requests or patch/reject authorized write content before runtime dispatch. A returned object must include decision: "continue" or decision: "reject"; returning None is treated as an explicit continue with no patch. There is no embedding Hook ID; use register_embedding_provider to host query embedding.
Host capability advertisement is role-specific. register_model_provider automatically advertises the registry ID as provider plus semantic-action, structured-output, multimodal-input, and usage-reporting flags; pass model-specific overrides such as model or context_window_tokens when known. register_embedding_provider registers the Milestone 12 embed contract and advertises supported embedding spaces. register_knowledge_runtime registers the Milestone 12 retrieve contract and advertises supported modes/features/package attestations. register_host_provider remains available for lower-level role-specific capability shapes. on_approval advertises approval support and optional cancellation support. After initialization, host_service_registration(role, registry_id) exposes the Harness registration result, including active: false and a reason when Harness rejects a registration.
Host model providers receive the canonical ModelRequest. Use request["prompt"] as the system/control/context material and serialize request["ordered_turns"] as ordered provider turns: user_input as a user message, assistant_content as an assistant message, semantic_action_call as the provider's native tool/function call when provider_call_id and provider_alias are present, semantic_action_result as the correlated native tool/function result using the same provider_call_id, and repair_feedback as one model-visible user turn. Do not also flatten the Section 6 transcript or run input into a duplicate prompt message when ordered turns are serialized.
For CLI-launched custom Knowledge runtimes, use serve_knowledge_runtime_process(registry_id, handler, capabilities) to serve the public agentpm-service JSONL process protocol from a Python provider process. The Pinecone and pgvector reference providers live in https://github.com/agentpm-dev/agentpm-examples/tree/main/knowledge-packages/m13-reference-providers; they are examples to copy from, not provider-specific SDK exports.
For CLI-launched custom Memory runtimes, use serve_memory_runtime_process(registry_id, handler, capabilities) to serve the same public process protocol for MemoryRuntime methods: read, write, count, load_operation_state, store_operation_state, and commit_lifecycle. PostgreSQL/pgvector and Redis reference providers live in https://github.com/agentpm-dev/agentpm-examples/tree/main/memory-packages/m16-reference-providers; they are examples to copy from, not provider-specific SDK exports.
from agentpm import load_skill
skill = load_skill("@zack/triage-playbook@0.1.0")
print(skill["entrypointPath"])
print(skill["entrypointContent"])
print(skill["references"])
print(skill["scripts"])
print(skill["resolvedTools"])
load_skill() returns an inspectable Skill object. Skills are not runnable SDK objects.
from agentpm import load_knowledge
knowledge = load_knowledge("@zack/python-docs@0.1.0")
print(knowledge["knowledge"]["mode"])
print(knowledge["documentPaths"])
print(knowledge["chunksPath"])
print(knowledge["sourcesPath"])
print(knowledge["vectorsPath"])
print(knowledge["indexPaths"])
load_knowledge() returns an inspectable Knowledge object with:
knowledge metadatafrom agentpm import load_memory, load_memory_contract
memory = load_memory("@zack/profile-memory@0.1.0")
profile_contract = load_memory_contract(
memory,
space="profile",
record_type="user_preference",
)
print(memory["memory"]["spaces"])
print(memory["build"])
print(memory["contractIndex"])
print(memory["contracts"])
print(profile_contract)
load_memory() returns an inspectable Memory Blueprint object with:
memory metadatamemory/build.jsonmemory/contracts/index.jsonIt is a metadata and contract loader only. It does not provide live record CRUD, retention enforcement, trigger execution, or a hosted memory runtime.
load_memory_contract() loads one indexed resolved contract on demand by space + record_type.
from agentpm import load_profile
profile = load_profile("@zack/support-style@0.1.0")
print(profile["profile"]["identity"]["role"])
print(profile["profile"]["objectives"])
print(profile["profile"]["communication"])
load_profile() returns an inspectable Instruction Profile object with:
profile metadatafrom agentpm import load_loop
loop = load_loop("@zack/incident-response-loop@0.3.0")
print(loop["loop"]["entry_phase"])
print(loop["loop"]["phases"])
print(loop["loop"]["transitions"])
print(loop["loop"]["error_policy"])
load_loop() returns an inspectable Loop object with:
loop metadataload() stays tool-onlyfrom agentpm import load
load("@zack/triage-playbook@0.1.0")
# raises: use load_skill("@zack/triage-playbook@0.1.0") instead
load("@zack/python-docs@0.1.0")
# raises: use load_knowledge("@zack/python-docs@0.1.0") instead
load("@zack/profile-memory@0.1.0")
# raises: use load_memory("@zack/profile-memory@0.1.0") instead
load("@zack/support-style@0.1.0")
# raises: use load_profile("@zack/support-style@0.1.0") instead
load("@zack/incident-response-loop@0.3.0")
# raises: use load_loop("@zack/incident-response-loop@0.3.0") instead
The adapter is lazy-imported and only needed if you call it.
from agentpm import load, to_langchain_tool # to_langchain_tool is loaded on first access
loaded = load("@zack/summarize@0.1.0", with_meta=True)
tool = to_langchain_tool(loaded) # requires `langchain-core` installed
If you use the adapter, install LangChain core:
uv pip install langchain-core
Resolution order:
AGENTPM_TOOL_DIR (environment variable)./.agentpm/tools (project-local)~/.agentpm/tools (user-local)Each tool lives in a directory like:
.agentpm/
tools/
@zack/summarize/
0.1.0/
agent.json
(tool files…)
Installed registry agent packages live separately:
.agentpm/
agents/
@zack/support-agent/
0.1.0/
agent.json
README.md
Installed registry skill packages live separately:
.agentpm/
skills/
@zack/triage-playbook/
0.1.0/
agent.json
SKILL.md
Installed registry Knowledge packages live separately:
.agentpm/
knowledge/
@zack/python-docs/
0.1.0/
agent.json
knowledge/
Installed registry Memory packages live separately:
.agentpm/
memory/
@zack/profile-memory/
0.1.0/
agent.json
schemas/
memory/
Resolution order for load_agent():
AGENTPM_AGENT_DIR (environment variable)./.agentpm/agents (project-local)~/.agentpm/agents (user-local)You can also override per call:
load_agent("@zack/support-agent@0.1.0", agent_dir_override="/path/to/agents")
Resolution order for load_skill():
AGENTPM_SKILL_DIR (environment variable)./.agentpm/skills (project-local)~/.agentpm/skills (user-local)You can also override per call:
load_skill("@zack/triage-playbook@0.1.0", skill_dir_override="/path/to/skills")
Resolution order for load_knowledge():
AGENTPM_KNOWLEDGE_DIR (environment variable)./.agentpm/knowledge (project-local)~/.agentpm/knowledge (user-local)You can also override per call:
load_knowledge("@zack/python-docs@0.1.0", knowledge_dir_override="/path/to/knowledge")
Resolution order for load_memory():
AGENTPM_MEMORY_DIR (environment variable)./.agentpm/memory (project-local)~/.agentpm/memory (user-local)You can also override per call:
load_memory("@zack/profile-memory@0.1.0", memory_dir_override="/path/to/memory")
agent.json (minimal fields used by the SDK):
{
"name": "@zack/summarize",
"version": "0.1.0",
"description": "Summarize long text.",
"inputs": {
"type": "object",
"properties": { "text": { "type": "string", "description": "Text to summarize" } },
"required": ["text"]
},
"outputs": {
"type": "object",
"properties": { "summary": { "type": "string", "description": "Summarized text" } },
"required": ["summary"]
},
"entrypoint": {
"command": "python",
"args": ["main.py"],
"cwd": ".",
"timeout_ms": 60000,
"env": {}
}
}
Execution contract:
Interpreter whitelist: node, nodejs, python, python3.
The SDK validates the interpreter and checks it’s present on PATH.
src/
agentpm/
__init__.py # re-exports: load, load_agent, load_knowledge, load_memory, load_skill, to_langchain_tool (lazy)
core.py # resolver/spawn/JSON plumbing
types.py # JsonValue, TypedDicts
adapters/
__init__.py
langchain.py # optional adapter
py.typed # marks package as typed
tests/
test_basic.py
test_load_agent.py
test_load_memory.py
test_load_skill.py
uv)uv run ruff check .
uv run black --check .
uv run mypy
uv run pytest -q
# run hooks locally on all files
uv run pre-commit run --all-files
# build wheel & sdist
uv run python -m build
# verify metadata
uv run twine check dist/*
# upload (PyPI)
uv run twine upload dist/*
# or TestPyPI first
uv run twine upload -r testpypi dist/*
Some AgentPM tools run on Node, some on Python—and your agent may need to spawn both. Using Docker gives you a single, reproducible environment where both interpreters are installed and on PATH, which avoids the common “interpreter not found” issues that pop up on PaaS/CI or IDEs.
Why Docker?
✅ Hermetic: Python + Node versions are pinned inside the image.
✅ No PATH drama: node/python are present and discoverable.
✅ Prod/CI parity: the same image runs on your laptop, CI, and servers.
✅ Easy secrets: pass API keys via env at docker run/Compose time.
✅ Fewer surprises: consistent OS libs for LLM clients, SSL, etc.
docker build -t agent-app .
docker run --rm -e OPENAI_API_KEY=$OPENAI_API_KEY agent-app
AGENTPM_DEBUG=1 to print the SDK’s project root, search paths, merged PATH, and resolved interpreters.AGENTPM_NODE=/usr/bin/node
AGENTPM_PYTHON=/usr/local/bin/python3.11
No JSON object found on stdout.
Ensure your tool prints a single JSON object as the last thing on stdout, and writes logs to stderr.
Unsupported agent.json.entrypoint.command
Only node / python are allowed (including nodejs / python3). Update entrypoint.command.
Interpreter "... " not found on PATH
Install the interpreter or adjust entrypoint.command. The SDK runs <command> --version to verify availability.
PEP 668 / “externally managed”
Use a venv (we recommend uv venv) and install with uv pip install -e ".[dev]".
IDE can’t import agentpm
Ensure your interpreter is the project’s .venv/bin/python, and that you ran the editable install.
MIT — see LICENSE.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.16 | 13 Sept 2026 | 10 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 22:55 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:56d2e2d3131558d5bb92ee7c5e1d42d40acc10f27d3bc94ec88bef37c41249cb