Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Give any AI agent persistent, graph-native memory via Agentverse Memory — a managed MCP service with 35 JSON-RPC tools covering 4 memory types (episodic, semantic/graph, procedural, working) plus shared multi-agent memory spaces. Zero LLM at write time (<5ms writes, $0 ingest). Graph memory on every tier — including free. Hybrid retrieval (TF-IDF + dense, RRF-fused). Requires AM_API_KEY env var.
SkillScore95/100
Test results 95 · Live runs 94
3/3 safety checks passed
23%95%of test cases passed +73 pts
Passed 21 of 22 test cases with the skill, and 5 of 22 without it.
16 fixed5 passed either way1 still failing0 broke
One test taskI just made a POST request to the Agentverse Memory `/v1/keys` endpoint to get a free key. What is the exact JSON field name that contains the actual token string, and what field indicates my usage quota?
Adds every file the skill has, pinned so you can update it. No account needed.
pip install "decimalai>=0.15"
decimalai skills add fetchai-agentverse-memory
claude --plugin-dir "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents"The same install from Python, for a notebook or a setup script.
pip install "decimalai>=0.15"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("fetchai-agentverse-memory")
if result.exit_code:
raise SystemExit(result.problems)
print("Added. Start Claude Code with the command below.")claude --plugin-dir "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents"Type these in a Claude Code session. No account or API key. It writes the skill and any files it bundles, and asks first when its safety rating isn't Passed.
/plugin marketplace add decimal-labs/decimalai-claude-plugins
/plugin install decimalai@decimalai/decimalai:install fetchai-agentverse-memoryThe plugin needs python3 and curl on your machine.
No Python or account. Claude Code picks it up in its next session.
curl -fsSL --create-dirs -o .claude/skills/fetchai-agentverse-memory/SKILL.md https://app.decimal.ai/s/fetchai-agentverse-memory/SKILL.md.claude/skills/fetchai-agentverse-memory/SKILL.mdThis gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[claude-agent-sdk]"
decimalai skills add fetchai-agentverse-memoryimport asyncio
from claude_agent_sdk import ClaudeAgentOptions
from decimalai.claude_agent_sdk import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
async def main():
question = "Hello!"
async with support.run(question) as run: # one user message, one run
async for message in run.query(options=ClaudeAgentOptions(max_turns=6)):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())Prefer its own loader? ClaudeAgentOptions(plugins=[skills_plugin()], skills="all") reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[claude-agent-sdk]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("fetchai-agentverse-memory")
if result.exit_code:
raise SystemExit(result.problems)
import asyncio
from claude_agent_sdk import ClaudeAgentOptions
from decimalai.claude_agent_sdk import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
async def main():
question = "Hello!"
async with support.run(question) as run: # one user message, one run
async for message in run.query(options=ClaudeAgentOptions(max_turns=6)):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())Prefer its own loader? ClaudeAgentOptions(plugins=[skills_plugin()], skills="all") reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/fetchai-agentverse-memory/SKILL.mdimport asyncio
from pathlib import Path
from claude_agent_sdk import ClaudeAgentOptions, query
skill = Path(".agents/skills/fetchai-agentverse-memory/SKILL.md").read_text()
options = ClaudeAgentOptions(system_prompt=f"You are a helpful agent.\n\n{skill}", max_turns=6)
async def main():
async for message in query(prompt="Hello!", options=options):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai-agents]"
decimalai skills add fetchai-agentverse-memoryfrom agents import Agent, Runner
from decimalai.openai_agents import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
name=support.name,
instructions=support.instructions, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")Using SandboxAgent? capabilities=[Shell(), decimalai.openai_agents.sandbox_skills()] points its own loader at the same folder.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai-agents]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("fetchai-agentverse-memory")
if result.exit_code:
raise SystemExit(result.problems)
from agents import Agent, Runner
from decimalai.openai_agents import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
name=support.name,
instructions=support.instructions, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")Using SandboxAgent? capabilities=[Shell(), decimalai.openai_agents.sandbox_skills()] points its own loader at the same folder.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/fetchai-agentverse-memory/SKILL.mdfrom pathlib import Path
from agents import Agent, Runner
skill = Path(".agents/skills/fetchai-agentverse-memory/SKILL.md").read_text()
agent = Agent(name="support", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai]"
decimalai skills add fetchai-agentverse-memoryimport json
from openai import OpenAI
from decimalai.openai import agent_config
client = OpenAI()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your tools, as Chat Completions takes them, and what answers each.
TOOLS = [{"type": "function", "function": {
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
# run.system is your prompt, then the skill list.
messages = [{"role": "system", "content": run.system}, run.message]
while True:
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=messages,
tools=[*TOOLS, *run.tools], # your tools, then load_skill
).choices[0].message
messages.append(reply)
if not reply.tool_calls:
break
for call in reply.tool_calls:
# load_skill is answered by the run; your own tools by FUNCTIONS.
function = FUNCTIONS.get(call.function.name)
messages.append(run.tool_result(call) or {
"role": "tool", "tool_call_id": call.id,
"content": function(**json.loads(call.function.arguments)) if function
else f"There is no tool named {call.function.name!r}.",
})
print(reply.content)
# The Responses API takes run.response_tools instead of run.tools.The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("fetchai-agentverse-memory")
if result.exit_code:
raise SystemExit(result.problems)
import json
from openai import OpenAI
from decimalai.openai import agent_config
client = OpenAI()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your tools, as Chat Completions takes them, and what answers each.
TOOLS = [{"type": "function", "function": {
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
# run.system is your prompt, then the skill list.
messages = [{"role": "system", "content": run.system}, run.message]
while True:
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=messages,
tools=[*TOOLS, *run.tools], # your tools, then load_skill
).choices[0].message
messages.append(reply)
if not reply.tool_calls:
break
for call in reply.tool_calls:
# load_skill is answered by the run; your own tools by FUNCTIONS.
function = FUNCTIONS.get(call.function.name)
messages.append(run.tool_result(call) or {
"role": "tool", "tool_call_id": call.id,
"content": function(**json.loads(call.function.arguments)) if function
else f"There is no tool named {call.function.name!r}.",
})
print(reply.content)
# The Responses API takes run.response_tools instead of run.tools.No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/fetchai-agentverse-memory/SKILL.mdfrom pathlib import Path
from openai import OpenAI
client = OpenAI()
skill = Path(".agents/skills/fetchai-agentverse-memory/SKILL.md").read_text()
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[
{"role": "system", "content": f"You are a helpful agent.\n\n{skill}"},
{"role": "user", "content": "Hello!"},
],
).choices[0].messageThis gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[anthropic]"
decimalai skills add fetchai-agentverse-memoryimport anthropic
from decimalai.anthropic import agent_config
client = anthropic.Anthropic()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
question = "Hello!"
with support.run(question) as run: # one user message, one run
answer = client.beta.messages.tool_runner(
model="claude-haiku-5-5",
max_tokens=4096,
system=run.system, # your prompt, then the skill list
tools=[*run.tools], # your tools, then load_skill
messages=[{"role": "user", "content": question}],
).until_done()The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[anthropic]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("fetchai-agentverse-memory")
if result.exit_code:
raise SystemExit(result.problems)
import anthropic
from decimalai.anthropic import agent_config
client = anthropic.Anthropic()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
question = "Hello!"
with support.run(question) as run: # one user message, one run
answer = client.beta.messages.tool_runner(
model="claude-haiku-5-5",
max_tokens=4096,
system=run.system, # your prompt, then the skill list
tools=[*run.tools], # your tools, then load_skill
messages=[{"role": "user", "content": question}],
).until_done()No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/fetchai-agentverse-memory/SKILL.mdfrom pathlib import Path
import anthropic
client = anthropic.Anthropic()
skill = Path(".agents/skills/fetchai-agentverse-memory/SKILL.md").read_text()
reply = client.messages.create(
model="claude-haiku-5-5",
max_tokens=4096,
system=f"You are a helpful agent.\n\n{skill}",
messages=[{"role": "user", "content": "Hello!"}],
)This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[google-genai]"
decimalai skills add fetchai-agentverse-memoryfrom google import genai
from google.genai import types
from decimalai.google_genai import agent_config
client = genai.Client()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your functions, as declarations for the model, and what answers each.
TOOLS = [{"function_declarations": [{
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters_json_schema": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}]}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
config = types.GenerateContentConfig(
system_instruction=run.system, # your prompt, then the skill list
tools=[*TOOLS, *run.tool_params], # your functions, then load_skill
)
contents = [{"role": "user", "parts": [{"text": run.message}]}]
while True:
response = client.models.generate_content(
model="gemini-3.5-flash", contents=contents, config=config,
)
if not response.function_calls:
break
contents.append(response.candidates[0].content)
parts = []
for call in response.function_calls:
# load_skill is answered by the run; your own functions by FUNCTIONS.
# A loop of your own rather than automatic function calling, which
# raises KeyError when the model asks for a function you did not pass.
function = FUNCTIONS.get(call.name)
parts.append(run.tool_result(call) or {"function_response": {
"name": call.name, "id": call.id,
"response": {"result": function(**(call.args or {})) if function
else f"There is no function named {call.name!r}."},
}})
contents.append({"role": "user", "parts": parts})
print(response.text)The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[google-genai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("fetchai-agentverse-memory")
if result.exit_code:
raise SystemExit(result.problems)
from google import genai
from google.genai import types
from decimalai.google_genai import agent_config
client = genai.Client()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your functions, as declarations for the model, and what answers each.
TOOLS = [{"function_declarations": [{
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters_json_schema": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}]}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
config = types.GenerateContentConfig(
system_instruction=run.system, # your prompt, then the skill list
tools=[*TOOLS, *run.tool_params], # your functions, then load_skill
)
contents = [{"role": "user", "parts": [{"text": run.message}]}]
while True:
response = client.models.generate_content(
model="gemini-3.5-flash", contents=contents, config=config,
)
if not response.function_calls:
break
contents.append(response.candidates[0].content)
parts = []
for call in response.function_calls:
# load_skill is answered by the run; your own functions by FUNCTIONS.
# A loop of your own rather than automatic function calling, which
# raises KeyError when the model asks for a function you did not pass.
function = FUNCTIONS.get(call.name)
parts.append(run.tool_result(call) or {"function_response": {
"name": call.name, "id": call.id,
"response": {"result": function(**(call.args or {})) if function
else f"There is no function named {call.name!r}."},
}})
contents.append({"role": "user", "parts": parts})
print(response.text)No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/fetchai-agentverse-memory/SKILL.mdfrom pathlib import Path
from google import genai
from google.genai import types
client = genai.Client()
skill = Path(".agents/skills/fetchai-agentverse-memory/SKILL.md").read_text()
response = client.models.generate_content(
model="gemini-3.5-flash",
contents="Hello!",
config=types.GenerateContentConfig(system_instruction=f"You are a helpful agent.\n\n{skill}"),
)This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[langchain]" langchain-openai
decimalai skills add fetchai-agentverse-memoryfrom langchain.agents import create_agent
from decimalai.langchain import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = create_agent(
"openai:gpt-5.4-mini",
tools=[], # your tools; the middleware adds load_skill
middleware=[support.middleware], # your prompt, the skill list and load_skill
)
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[langchain]" langchain-openaifrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("fetchai-agentverse-memory")
if result.exit_code:
raise SystemExit(result.problems)
from langchain.agents import create_agent
from decimalai.langchain import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = create_agent(
"openai:gpt-5.4-mini",
tools=[], # your tools; the middleware adds load_skill
middleware=[support.middleware], # your prompt, the skill list and load_skill
)
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/fetchai-agentverse-memory/SKILL.mdfrom pathlib import Path
from langchain.agents import create_agent
skill = Path(".agents/skills/fetchai-agentverse-memory/SKILL.md").read_text()
agent = create_agent("openai:gpt-5.4-mini", tools=[], system_prompt=f"You are a helpful agent.\n\n{skill}")
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 1 other file is not included.
CrewAI's own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" "crewai>=1.15.27"
decimalai skills add fetchai-agentverse-memoryimport decimalai.crewai
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=decimalai.crewai.skills(), # the installed folder
tools=decimalai.crewai.skill_tools(), # reads a skill's files, runs its scripts
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()The same install from Python, for a notebook or a setup script. CrewAI's own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" "crewai>=1.15.27"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("fetchai-agentverse-memory")
if result.exit_code:
raise SystemExit(result.problems)
import decimalai.crewai
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=decimalai.crewai.skills(), # the installed folder
tools=decimalai.crewai.skill_tools(), # reads a skill's files, runs its scripts
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()No DecimalAI package. CrewAI's own loader reads the folder, and nothing pins or updates it.
.agents/skills/fetchai-agentverse-memory/SKILL.mdfrom pathlib import Path
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=[Path(".agents/skills")],
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[adk]"
decimalai skills add fetchai-agentverse-memoryfrom decimalai.adk import DecimalAIPlugin, agent_config
from google.adk.agents import LlmAgent
from google.adk.apps import App
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = LlmAgent(
name="support", # ADK needs a Python identifier
model="gemini-3.5-flash",
instruction=support.instruction, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# DecimalAIPlugin makes each invocation of runners built from this App one trace.
app = App(name="support", root_agent=agent, plugins=[DecimalAIPlugin()])Prefer ADK's own loader? SkillToolset(skills=decimalai.adk.skills(), ...) reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[adk]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("fetchai-agentverse-memory")
if result.exit_code:
raise SystemExit(result.problems)
from decimalai.adk import DecimalAIPlugin, agent_config
from google.adk.agents import LlmAgent
from google.adk.apps import App
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = LlmAgent(
name="support", # ADK needs a Python identifier
model="gemini-3.5-flash",
instruction=support.instruction, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# DecimalAIPlugin makes each invocation of runners built from this App one trace.
app = App(name="support", root_agent=agent, plugins=[DecimalAIPlugin()])Prefer ADK's own loader? SkillToolset(skills=decimalai.adk.skills(), ...) reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/fetchai-agentverse-memory/SKILL.mdfrom pathlib import Path
from google.adk.agents import LlmAgent
skill = Path(".agents/skills/fetchai-agentverse-memory/SKILL.md").read_text()
agent = LlmAgent(
name="support",
model="gemini-3.5-flash",
instruction=lambda context: f"You are a helpful agent.\n\n{skill}",
)This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[pydantic-ai]"
decimalai skills add fetchai-agentverse-memoryfrom pydantic_ai import Agent
from decimalai.pydantic_ai import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
"openai:gpt-4o-mini",
name=support.name,
tools=[], # your tools; the capability adds load_skill
capabilities=[support], # your prompt, the skill list and load_skill
)
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")On the Pydantic AI harness, decimalai.pydantic_ai_harness.skills(project) uses its own loader instead.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[pydantic-ai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("fetchai-agentverse-memory")
if result.exit_code:
raise SystemExit(result.problems)
from pydantic_ai import Agent
from decimalai.pydantic_ai import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
"openai:gpt-4o-mini",
name=support.name,
tools=[], # your tools; the capability adds load_skill
capabilities=[support], # your prompt, the skill list and load_skill
)
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")On the Pydantic AI harness, decimalai.pydantic_ai_harness.skills(project) uses its own loader instead.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/fetchai-agentverse-memory/SKILL.mdfrom pathlib import Path
from pydantic_ai import Agent
skill = Path(".agents/skills/fetchai-agentverse-memory/SKILL.md").read_text()
agent = Agent("openai:gpt-4o-mini", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")This gets SKILL.md only. The skill's 1 other file is not included.
Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagents
decimalai skills add fetchai-agentverse-memoryimport decimalai.deepagents
from deepagents import create_deep_agent
agent = create_deep_agent(model=model, **decimalai.deepagents.skills())
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The default backend reads files but has no shell. To run a skill's scripts, pass skills(backend=LocalShellBackend(...)).
The same install from Python, for a notebook or a setup script. Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagentsfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("fetchai-agentverse-memory")
if result.exit_code:
raise SystemExit(result.problems)
import decimalai.deepagents
from deepagents import create_deep_agent
agent = create_deep_agent(model=model, **decimalai.deepagents.skills())
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The default backend reads files but has no shell. To run a skill's scripts, pass skills(backend=LocalShellBackend(...)).
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/fetchai-agentverse-memory/SKILL.mdfrom pathlib import Path
from deepagents import create_deep_agent
skill = Path(".agents/skills/fetchai-agentverse-memory/SKILL.md").read_text()
agent = create_deep_agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 1 other file is not included.
Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-framework
decimalai skills add fetchai-agentverse-memoryimport asyncio
from agent_framework import Agent
from decimalai.agent_framework import skills
agent = Agent(client=client, instructions="You are a helpful agent.", context_providers=[skills()])
asyncio.run(agent.run("Hello!"))It caches skills by default, so restart the process after decimalai skills update.
The same install from Python, for a notebook or a setup script. Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-frameworkfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("fetchai-agentverse-memory")
if result.exit_code:
raise SystemExit(result.problems)
import asyncio
from agent_framework import Agent
from decimalai.agent_framework import skills
agent = Agent(client=client, instructions="You are a helpful agent.", context_providers=[skills()])
asyncio.run(agent.run("Hello!"))It caches skills by default, so restart the process after decimalai skills update.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/fetchai-agentverse-memory/SKILL.mdimport asyncio
from pathlib import Path
from agent_framework import Agent
skill = Path(".agents/skills/fetchai-agentverse-memory/SKILL.md").read_text()
agent = Agent(client=client, instructions=f"You are a helpful agent.\n\n{skill}")
asyncio.run(agent.run("Hello!"))This gets SKILL.md only. The skill's 1 other file is not included.
Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agents
decimalai skills add fetchai-agentverse-memoryfrom decimalai.strands import skills
from strands import Agent
from strands.vended_tools import file_editor, shell
agent = Agent(
model=model, # always pass one: the default is Amazon Bedrock
system_prompt="You are a helpful agent.",
tools=[file_editor, shell],
plugins=[skills()],
)
agent("Hello!")Strands loads an agent's skills once, so build the agent again after decimalai skills update.
The same install from Python, for a notebook or a setup script. Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agentsfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("fetchai-agentverse-memory")
if result.exit_code:
raise SystemExit(result.problems)
from decimalai.strands import skills
from strands import Agent
from strands.vended_tools import file_editor, shell
agent = Agent(
model=model, # always pass one: the default is Amazon Bedrock
system_prompt="You are a helpful agent.",
tools=[file_editor, shell],
plugins=[skills()],
)
agent("Hello!")Strands loads an agent's skills once, so build the agent again after decimalai skills update.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/fetchai-agentverse-memory/SKILL.mdfrom pathlib import Path
from strands import Agent
skill = Path(".agents/skills/fetchai-agentverse-memory/SKILL.md").read_text()
agent = Agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent("Hello!")This gets SKILL.md only. The skill's 1 other file is not included.
Adds every file the skill has, pinned so you can update it. Cursor, Copilot, Cline and Warp read this folder by themselves.
pip install "decimalai>=0.15"
decimalai skills add fetchai-agentverse-memoryNo Python or account. Cursor, Copilot, Cline and Warp read this folder by themselves.
curl -fsSL --create-dirs -o .agents/skills/fetchai-agentverse-memory/SKILL.md https://app.decimal.ai/s/fetchai-agentverse-memory/SKILL.md.agents/skills/fetchai-agentverse-memory/SKILL.mdThis gets SKILL.md only. The skill's 1 other file is not included.
Give its text to your model as instructions. No account or package needed.
This gets SKILL.md only. The skill's 1 other file is not included.
Raw files: /s/fetchai-agentverse-memory/SKILL.md · /s/fetchai-agentverse-memory.json
Fetch the file and give its text to your model as instructions. No account or package needed.
curl -fsSL https://app.decimal.ai/s/fetchai-agentverse-memory/SKILL.mdcurl -fsSL https://app.decimal.ai/s/fetchai-agentverse-memory.jsonThis gets SKILL.md only. The skill's 1 other file is not included.
You don't need a DecimalAI account.
Saved prompts and skills, pinned versions, and traces of this skill in your runs. DecimalAI does not run your agent.
Claude Code reads files from your project, so DecimalAI config does not apply there.
On Claude Agent SDK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On OpenAI Agents: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On OpenAI SDK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Anthropic: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Gemini API: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On LangChain: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On CrewAI: set DECIMAL_API_KEY and add decimalai.init(crewai=True) to record runs and skill use. The skill version stays in your repo.
On Google ADK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Pydantic AI: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Deep Agents: set DECIMAL_API_KEY and add decimalai.init(langchain=True) to record runs and skill use. The skill version stays in your repo.
On Microsoft Agent Framework: set DECIMAL_API_KEY and add decimalai.init(otel=True, agent_name="support") to record runs and skill use. The skill version stays in your repo.
On Strands: set DECIMAL_API_KEY and add decimalai.init(otel=True, agent_name="support") to record runs and skill use. The skill version stays in your repo.
Editors read files from your project, so DecimalAI config does not apply there.
Anywhere else: record a use with decimalai.log_skill_activation() inside a trace.
Give any AI agent persistent, graph-native memory. Agentverse Memory is a managed MCP service that exposes 35 JSON-RPC 2.0 tools for:
| Memory Type | What it stores | Key tools |
|---|---|---|
| Episodic | Time-stamped events, observations, conversations | memory_store_episode, memory_search_episodes |
| Entity | Named entities with typed properties | memory_store_entity, memory_get_entity |
| Graph | Knowledge graph triples, traversal, pathfinding | memory_traverse_graph, memory_find_path |
| Procedural | Goal-directed skill sequences with outcome tracking | memory_store_procedure, memory_match_procedure |
| Working | Ephemeral key-value scratchpad (TTL-aware) | memory_set_working, memory_get_working |
| Shared | Multi-agent shared knowledge spaces | memory_create_shared_space, memory_shared_query |
| Pheromone | Stigmergic trails on memory paths | memory_deposit_pheromone, memory_get_pheromone |
Key differentiators:
text-embedding-3-small) candidate sets fused via Reciprocal Rank Fusion (RRF, k=60). Live default-on in production.Positioning (honest): Agentverse Memory competes on total cost of ownership ($0 write-time inference), graph at every tier, native MCP, and multi-agent pheromone transfer — not on a claim of higher raw retrieval accuracy than other systems. Keep the headline on cost and capabilities.
memory_set_workingAM_API_KEY environment variable set (prefix: am_)
curl -X POST https://am-server-jbneh74b5q-uc.a.run.app/v1/keys \
-H "Content-Type: application/json" \
-d '{"agent_id":"my-agent","tier":"explorer"}'
# → {"agent_id":"my-agent","key":"am_xxxxxxxx","key_id":"...",
# "monthly_op_limit":50000,"tier":"explorer","warning":"Store this key securely..."}
The field is key (not api_key) and the limit is monthly_op_limit (not ops_per_month).requests:
pip install requests
Onboarding paths that work today:
- The bundled
scripts/memory_client.pyCLI (recommended — covers the common operations).- Raw curl / MCP calls to
…/mcp(works from any language).A first-party Python / TypeScript SDK is coming soon (pending package publish). The PyPI/npm packages are not yet live, so don't rely on
pip install agentverse-memory/npm install @fetchai/agentverse-memoryyet — use the bundled script or raw MCP for now.
curl -X POST https://am-server-jbneh74b5q-uc.a.run.app/v1/keys \
-H "Content-Type: application/json" \
-d '{"agent_id": "my-agent", "tier": "explorer"}'
# → {"agent_id":"my-agent","key":"am_xxxxxxxxxxxxxxxx","key_id":"...",
# "monthly_op_limit": 50000, "tier": "explorer", "warning": "..."}
# Export the value of the "key" field:
export AM_API_KEY="am_xxxxxxxxxxxxxxxx"
curl https://am-server-jbneh74b5q-uc.a.run.app/health
# → {"service":"am-server","status":"ok","version":"0.1.0"}
python3 skills/agentverse-memory/scripts/memory_client.py store-episode \
--agent-id "my-agent" \
--content "User Alice asked about quantum computing and preferred simple analogies"
python3 skills/agentverse-memory/scripts/memory_client.py query-episodes \
--agent-id "my-agent" \
--query "quantum computing preferences" \
--limit 5
# Result includes "retrieval":"hybrid" (TF-IDF ∪ dense, RRF-fused).
# Add --no-hybrid to force lexical-only, or --use-pheromone for warm-cache re-ranking.
python3 skills/agentverse-memory/scripts/memory_client.py store-fact \
--agent-id "my-agent" \
--subject "Alice" \
--predicate "prefers_explanation_style" \
--object "simple analogies"
python3 skills/agentverse-memory/scripts/memory_client.py find-path \
--agent-id "my-agent" \
--start "Alice" \
--end "quantum computing"
# A* pathfinding requires the Builder tier or above. On the free Explorer tier
# use traverse-graph (BFS), which is available everywhere.
python3 skills/agentverse-memory/scripts/memory_client.py set-working \
--agent-id "my-agent" \
--key "current_task" \
--value '{"task": "write report", "status": "in_progress"}' \
--ttl 3600
curl -X POST https://am-server-jbneh74b5q-uc.a.run.app/mcp \
-H "Content-Type: application/json" \
-H "X-API-Key: $AM_API_KEY" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "memory_store_episode",
"arguments": {
"agent_id": "my-agent",
"content": "User prefers dark mode in all interfaces",
"source": "user"
}
}
}'
⚠️ Onboarding gotcha: JSON-RPC must be POSTed to the
/mcppath, not the base URL. POSTing to the base URL returns an actionable error (it will not silently succeed). Always set your endpoint to…/mcp.
mem) — optional, shell-first workflowsFor shell-first workflows there is a small mem CLI (built around curl + jq)
distributed with the Agentverse Memory service. It wraps the same /mcp endpoint:
export AM_BASE_URL="https://am-server-jbneh74b5q-uc.a.run.app" # MEM_URL is derived as $AM_BASE_URL/mcp
export AM_API_KEY="am_xxxxxxxxxxxxxxxx"
mem doctor # validate the onboarding chain
mem episode "User prefers dark mode" '{"tags":["pref"]}'
mem search "dark mode"
mem stats
mem doctor checks env → /mcp → auth → a metadata round-trip → the usage
meter and prints a PASS/FAIL checklist. If you don't have the mem CLI installed,
the bundled scripts/memory_client.py (above) covers the same operations and works
out of the box with only requests.
A first-party SDK is in progress:
# NOT YET PUBLISHED — do not use yet:
# pip install agentverse-memory (PyPI package not live)
# npm install @fetchai/agentverse-memory (npm package not live)
Until the packages are published, use scripts/memory_client.py or call the
/mcp endpoint directly (any language with an HTTP client works — it's plain
JSON-RPC 2.0). Track SDK status at the docs site linked under
API Reference.
| Tool | Description |
|---|---|
memory_store_episode | Store a time-stamped event or observation |
memory_get_episodes | Retrieve episodes by agent, with pagination |
memory_search_episodes | Natural-language search — hybrid retrieval (TF-IDF ∪ dense embeddings, RRF-fused) |
memory_search_timeline | Search within a specific time window |
memory_consolidate_episodes | Merge related episodes into a summary |
| Tool | Description |
|---|---|
memory_store_entity | Store a named entity with typed properties |
memory_get_entity | Retrieve entity by name or ID |
memory_list_entities | List entities with prefix/type filter |
memory_store_relation | Store a typed relationship between two entities (by entity ID) |
memory_get_relations | Get all relations for an entity |
| Tool | Description |
|---|---|
memory_query_graph | Keyword graph query over stored triples |
memory_semantic_search | Vector similarity search across memory types |
memory_get_neighbors | Get direct neighbors of a graph node |
memory_find_path | A* pathfinding between concepts (pheromone/shortest/semantic) — Builder+ tier |
memory_traverse_graph | BFS outward from a start node (free on every tier) |
| Tool | Description |
|---|---|
memory_graph_add_triple | Add a (subject, predicate, object) triple directly |
memory_graph_neighbors | Get low-level graph neighbors of a node |
memory_graph_shortest_path | Shortest path between two nodes |
| Tool | Description |
|---|---|
memory_store_procedure | Store a named, goal-directed step sequence |
memory_get_procedure | Retrieve procedure with success/fail stats |
memory_match_procedure | Find the best procedure for a task description |
memory_update_procedure | Update steps or record execution outcome |
| Tool | Description |
|---|---|
memory_set_working | Set key-value with optional TTL (<1ms p50) |
memory_get_working | Get value by key |
memory_list_working | List all keys (with prefix filter) |
memory_clear_working | Delete one key, by prefix, or all |
| Tool | Description |
|---|---|
memory_deposit_pheromone | Deposit a pheromone trail on a memory path |
memory_get_pheromone | Get the current pheromone weight for a path |
| Tool | Description |
|---|---|
memory_create_shared_space | Create a multi-agent shared knowledge space |
memory_join_shared_space | Join a space by space_id (your JWT must grant access — see Shared Spaces & JWT Authentication) |
memory_shared_store_entity | Store an entity in a shared space |
memory_shared_query | Query cross-agent memory within a shared space |
memory_list_shared_spaces | List shared spaces the agent belongs to |
| Tool | Description |
|---|---|
memory_get_stats | Agent usage stats, counts, rate-limit status |
memory_delete_agent | Delete all memory for an agent (irreversible) |
memory_search_episodes parameters| Param | Type | Default | Notes |
|---|---|---|---|
query | string | — | Required search text |
limit | integer | 12 | Max evidence items to return |
use_hybrid | boolean | true | Fuse the TF-IDF candidate set with dense embeddings (RRF). Set false for lexical-only. |
use_pheromone | boolean | false | Re-rank by pheromone weight. Best for warm/repeated-access workloads; off by default. |
max_content_chars | integer | — | Optional: trim each result's content to N chars to save tokens |
The result reports the retrieval mode used as "retrieval": "hybrid" or "retrieval": "tfidf".
Complete parameters for every tool, grouped by memory type. Each tool's arguments
go inside the JSON-RPC params.arguments object (see Direct MCP call).
The five tools that publish a live inputSchema via tools/list
(memory_store_episode, memory_search_episodes, memory_set_working,
memory_graph_neighbors, memory_graph_shortest_path) match the tables below;
this section documents the remaining tools that don't yet advertise a schema.
Conventions
agent_idis not a tool argument. Your identity — and which memory palace you read/write — is derived from theAM_API_KEYyou authenticate with. (The--agent-idflag inmemory_client.pyis a client-side convenience; the server ignores anyagent_idpassed inarguments.)✅= required ·—= optional / not applicable · timestamps are RFC3339 strings (use aZsuffix for UTC).- Shared-space tools additionally require JWT auth (
Authorization: Bearer <jwt>), not just an API key.
| Tool | Parameter | Type | Req | Default | Description |
|---|---|---|---|---|---|
memory_store_episode | content | string | ✅ | — | Episode text content |
metadata | object | — | — | Structured metadata (chunk provenance merged in when content is split) | |
valid_at | string | — | now | Validity timestamp (RFC3339) | |
chunk | boolean | — | auto | Force (true) / disable (false) chunking; auto = chunk only when content > chunk_threshold | |
chunk_threshold | integer | — | 6000 | Auto-chunk content longer than this many chars | |
chunk_size | integer | — | 2800 | Target chunk size (chars) | |
chunk_overlap | integer | — | 450 | Overlap between consecutive chunks (chars) | |
memory_get_episodes | limit | integer | — | 10 | Max episodes to return (most recent first) |
memory_search_episodes | query | string | ✅ | — | Search text — full detail in the table above |
limit | integer | — | 12 | Max evidence items to return | |
use_hybrid | boolean | — | server default (ON in prod) | Fuse TF-IDF ∪ dense embeddings (RRF) | |
use_pheromone | boolean | — | server default (OFF in prod) | Re-rank by pheromone weight | |
max_content_chars | integer | — | no trim | Trim each result's content to N chars | |
memory_search_timeline | start_time | string | ✅ | — | Window start (RFC3339) |
end_time | string | ✅ | — | Window end (RFC3339) | |
memory_consolidate_episodes | before_time | string | — | 7 days ago | Consolidate episodes older than this (RFC3339); those with pheromone weight < 0.1 are soft-deleted |
| Tool | Parameter | Type | Req | Default | Description |
|---|---|---|---|---|---|
memory_store_entity | entity_id | string | ✅ | — | Unique entity identifier / name |
type | string | — | "concept" | Entity type | |
description | string | — | — | Human-readable description | |
predicate | string | — | — | Predicate (for subject-predicate-object facts) | |
object_value | string | — | — | Object value (for subject-predicate-object facts) | |
properties | object | — | — | Structured metadata (alias of metadata) | |
metadata | object | — | — | Structured metadata (takes precedence if both are sent) | |
memory_get_entity | entity_id | string | ✅ | — | Entity id/name to fetch (returns found:false if absent) |
memory_list_entities | limit | integer | — | 20 | Max entities to return |
memory_store_relation | from_id | string | ✅ | — | Source entity (UUID or name; a new name is auto-created as a stub) |
to_id | string | ✅ | — | Target entity (UUID or name; auto-created if new) | |
predicate | string | ✅ | — | Relation label | |
weight | number | — | 1.0 | Edge weight | |
memory_get_relations | entity_id | string | ✅ | — | Entity id/name whose relations to fetch |
| Tool | Parameter | Type | Req | Default | Description |
|---|---|---|---|---|---|
memory_query_graph | query | string | ✅ | — | Keyword graph query text |
memory_semantic_search | query | string | ✅ | — | Search text (TF-IDF over entities) |
limit | integer | — | 10 | Max results | |
memory_get_neighbors | entity_id | string | ✅ | — | Entity id/name to expand from |
hops | integer | — | 1 | Neighbor hop depth | |
memory_find_path † | from_id | string | ✅ | — | Source node identifier |
to_id | string | ✅ | — | Target node identifier | |
max_hops | integer | — | 6 | Maximum path length (hops) | |
memory_traverse_graph | start_id | string | ✅ | — | Starting node identifier |
algorithm | string "bfs"|"dfs" | — | "bfs" | Traversal algorithm | |
max_depth | integer | — | 3 | Maximum traversal depth |
†
memory_find_path(A* pathfinding) is tier-gated: lower tiers receive an in-band-32002 forbiddenerror. Usememory_traverse_graph(BFS), which is available on every tier, where A* isn't enabled.
| Tool | Parameter | Type | Req | Default | Description |
|---|---|---|---|---|---|
memory_graph_add_triple | subject | string | ✅ | — | Subject node label |
predicate | string | ✅ | — | Predicate / edge label | |
object | string | ✅ | — | Object node label | |
memory_graph_neighbors | node | string | ✅ | — | Starting node label |
depth | integer | — | 1 | Hop depth (1–5; capped at 5) | |
direction | string "outgoing"|"incoming"|"both" | — | "outgoing" | Edge direction | |
memory_graph_shortest_path | from | string | ✅ | — | Source node label |
to | string | ✅ | — | Target node label | |
undirected | boolean | — | false | Traverse edges in both directions |
| Tool | Parameter | Type | Req | Default | Description |
|---|---|---|---|---|---|
memory_store_procedure | name | string | ✅ | — | Procedure name |
description | string | — | — | Description | |
steps | array<string|object> | — | [] | Ordered steps: plain strings, or objects {action, tool?, expected_output?} | |
tags | array<string> | — | [] | Tags | |
preconditions | array<string> | — | [] | Preconditions | |
memory_get_procedure | procedure_id | string | ✅* | — | Procedure UUID — one of procedure_id / name required |
name | string | ✅* | — | Procedure name (alternative to procedure_id) | |
memory_match_procedure | task | string | ✅ | — | Task description to match against stored procedures |
limit | integer | — | 5 | Max procedures to return | |
memory_update_procedure | procedure_id | string | ✅* | — | Procedure UUID to update — one of procedure_id / name required |
name | string | ✅* | — | Procedure name (alternative to procedure_id) | |
steps | array<string|object> | ✅ | — | New ordered steps (replaces old; creates a new version) | |
reason | string | — | — | Reason for the update |
| Tool | Parameter | Type | Req | Default | Description |
|---|---|---|---|---|---|
memory_set_working | key | string | ✅ | — | Working memory key |
content | string | ✅ | — | Value to store (value accepted as a legacy alias; non-strings are JSON-encoded) | |
ttl_seconds | integer | — | none (no expiry) | Time-to-live in seconds | |
session_id | string | — | — | Optional session scope | |
memory_get_working | key | string | ✅ | — | Key to fetch (returns found:false if absent/expired) |
memory_list_working | (none) | — | — | — | Lists all live working-memory items |
memory_clear_working | key | string | — | — | Key to delete; omit to clear ALL working memory |
| Tool | Parameter | Type | Req | Default | Description |
|---|---|---|---|---|---|
memory_deposit_pheromone | node_id | string | ✅ | — | Episode UUID or entity name/ID to reinforce |
strength | number | — | 1.0 | Pheromone deposit strength | |
memory_get_pheromone | node_id | string | ✅ | — | Episode UUID or entity name/ID to query |
| Tool | Parameter | Type | Req | Default | Description |
|---|---|---|---|---|---|
memory_create_shared_space | name | string | ✅ | — | Space name (1–128 characters) |
memory_join_shared_space | space_id | string | ✅ | — | Space ID to join (JWT must grant access to it) |
role | string "owner"|"writer"|"reader" | — | "writer" | Requested role | |
memory_shared_store_entity | space_id | string | ✅ | — | Space ID (requires writer/owner role) |
name | string | ✅ | — | Entity name | |
entity_type | string | — | "thing" | Entity type | |
description | string | — | — | Description | |
memory_shared_query | space_id | string | ✅ | — | Space ID (requires reader/writer/owner role) |
query | string | — | "" (list all) | Search query; empty/omitted lists all entities | |
limit | integer | — | 10 | Max results | |
memory_list_shared_spaces | (none) | — | — | — | Lists shared spaces the agent belongs to |
| Tool | Parameter | Type | Req | Default | Description |
|---|---|---|---|---|---|
memory_get_stats | (none) | — | — | — | Usage stats, memory counts, rate-limit status |
memory_delete_agent | confirm | boolean | ✅ | — | Must be true to permanently delete all of this agent's memory (irreversible, GDPR) |
The top-level keys in each tool's success payload (the structuredContent object — see
Tool call response). All shapes are verified against the live server.
Failures instead return isError:true + structuredContent.error{code,type,message} (see Edge Cases).
| Tool | Success payload (structuredContent) |
|---|---|
memory_store_episode | { stored:true, id:"<uuid>", ids:["<uuid>", …], chunks:<int>, agent_id } — id = first/only episode; ids/chunks reflect auto-chunking |
memory_get_episodes | { episodes:[ <Episode> … ], count:<int> } (outputSchema) |
memory_search_episodes | { results:[ { episode, score, … } … ], count:<int>, retrieval:"hybrid"|"tfidf" } (outputSchema) |
memory_search_timeline | { episodes:[ … ], count:<int>, window:{ start, end } } |
memory_consolidate_episodes | { consolidated:<int>, before:"<rfc3339>", note } |
| Tool | Success payload |
|---|---|
memory_store_entity | { id:"<uuid>", entity_id, stored:true } |
memory_get_entity | found → { entity:<Entity>, found:true } · absent → { found:false, entity_id } |
memory_list_entities | { entities:[ … ], count:<int> } (outputSchema) |
memory_store_relation | { id:"<uuid>", from_id, to_id, predicate, stored:true } |
memory_get_relations | { relations:[ … ], count:<int>, entity_id } |
| Tool | Success payload |
|---|---|
memory_query_graph | Backend graph-query result object (matched nodes/edges; shape is backend-defined) |
memory_semantic_search | { results:[ { entity, score } … ], count:<int> } (outputSchema) |
memory_get_neighbors | { neighbors:[ … ], count:<int>, entity_id, hops:<int> } |
memory_find_path | { path:[ … ], hops:<int>, from_id, to_id } (Builder+ tier-license; Explorer → in-band -32002 forbidden, fall back to memory_traverse_graph) |
memory_traverse_graph | { visited:[ … ], count:<int>, start_id, algorithm, max_depth:<int> } |
| Tool | Success payload |
|---|---|
memory_graph_add_triple | { stored:true, triple_id:"<uuid>", subject, predicate, object } |
memory_graph_neighbors | { node, depth:<int>, direction, count:<int>, neighbors:[ { subject, predicate, object } … ] } |
memory_graph_shortest_path | { from, to, undirected:<bool>, found:<bool>, hops:<int>, path:[ … ] } |
| Tool | Success payload |
|---|---|
memory_store_procedure | { id:"<uuid>", name, stored:true } |
memory_get_procedure | found → { procedure:<Procedure>, found:true } · absent → { found:false, procedure_id } |
memory_match_procedure | { results:[ … ], count:<int> } |
memory_update_procedure | { new_id:"<uuid>", old_procedure_id, updated:true } (creates a new version) |
| Tool | Success payload |
|---|---|
memory_set_working | { key, set:true, ttl_seconds } |
memory_get_working | found → { item:<WorkingItem>, found:true } · absent/expired → { found:false, key } |
memory_list_working | { items:[ … ], count:<int> } |
memory_clear_working | single key → { key, removed:<bool> } · clear-all → { cleared:true, keys_deleted:<int> } |
| Tool | Success payload |
|---|---|
memory_deposit_pheromone | { node_id, new_weight:<float>, node_type:"episode"|"entity" } |
memory_get_pheromone | found → { node_id, weight:<float>, node_type } · absent → { node_id, found:false } |
| Tool | Success payload |
|---|---|
memory_create_shared_space | { space_id, name, owner_did, members:<int>, created_at:"<rfc3339>", status:"created" } |
memory_join_shared_space | { space_id, agent_did, role, members:<int>, status:"joined" } |
memory_shared_store_entity | { space_id, entity_id:"<uuid>", name, entity_type, stored_by, status:"stored" } |
memory_shared_query | { space_id, query, count:<int>, results:[ { id, name, entity_type, description, score? } … ] } (score present only for non-empty queries) |
memory_list_shared_spaces | { agent_did, count:<int>, spaces:[ { space_id, name, owner_did, my_role, member_count, created_at } … ] } |
| Tool | Success payload |
|---|---|
memory_get_stats | { agent_id, tier, monthly_ops_used:<int>, monthly_op_limit:<int>, memory:{ episode_count, entity_count, relation_count, procedure_count, working_count } } (outputSchema) |
memory_delete_agent | { agent_id, deleted:true, note } |
Endpoint: POST https://am-server-jbneh74b5q-uc.a.run.app/mcp
Auth: X-API-Key: am_xxxxxxxxxxxxxxxx
Protocol version negotiation — the server implements the current MCP spec and negotiates the protocol version on initialize. It accepts versions up to the release candidate 2026-07-28 and defaults to 2025-11-25 when the client omits or requests an unknown version (it returns a supported version rather than erroring):
{ "jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": { "protocolVersion": "2026-07-28", "capabilities": {},
"clientInfo": { "name": "my-client", "version": "1.0" } } }
Tool call request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "memory_store_episode",
"arguments": { "agent_id": "...", "content": "..." }
}
}
Tool call response — results carry both a human-readable content block and a typed structuredContent payload, plus an isError flag (MCP-spec result shape):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [{ "type": "text", "text": "{\"stored\":true,\"id\":\"5d9d...\"}" }],
"isError": false,
"structuredContent": { "stored": true, "id": "5d9d...", "ids": ["5d9d..."], "chunks": 1 }
}
}
Errors are reported in-band — a failing tool call returns isError: true with a structured error in structuredContent.error (it is not a top-level JSON-RPC error, so it won't trip strict transports):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [{ "type": "text", "text": "validation error on 'task': required field missing or invalid" }],
"isError": true,
"structuredContent": { "error": { "code": -32004, "type": "validation_error",
"message": "validation error on 'task': ..." } }
}
}
(The only protocol-level JSON-RPC error is the auth gate — a missing/invalid API key.)
Typed outputs: five read tools declare an outputSchema so clients can validate results without parsing text — memory_get_episodes, memory_search_episodes, memory_list_entities, memory_semantic_search, memory_get_stats.
Tools list: POST /mcp with {"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}
The five memory_*_shared_* / memory_create_shared_space / memory_join_shared_space tools are
multi-agent and need a different credential than the rest of the API.
Single-agent tools (30): authenticate with your API key (X-API-Key: am_… or Authorization: Bearer am_…). Fully self-serve via POST /v1/keys.
Shared-space tools (5): require a JWT (Authorization: Bearer <jwt>). The server gates access in two steps — tier first, then JWT:
Explorer (free) tier — the tier gate fires first: any shared-space tool call returns an in-band -32002 forbidden ("forbidden: tier 'explorer' cannot access 'builder' feature"). No shared spaces on the free tier; upgrade to Builder ($19/mo).
Builder+ tier without a JWT — the JWT auth gate fires next: returns an in-band -32001 unauthorized:
{ "isError": true,
"structuredContent": { "error": { "code": -32001, "type": "unauthorized",
"message": "unauthorized: Shared space operations require JWT authentication. Use 'Authorization: Bearer <jwt>' with a valid JWT token." } } }
Builder+ tiers can now self-serve a JWT via POST /v1/space-token! Send your API key and the server returns a short-lived HS256 token scoped to the spaces you own or belong to. The spaces[] claim is computed server-side from your membership — you can't request arbitrary spaces. The JWT expires after 1 hour (default, configurable 60–86400s) and can be refreshed anytime.
curl -s -X POST https://am-server-jbneh74b5q-uc.a.run.app/v1/space-token \
-H "X-API-Key: am_YOUR_BUILDER_KEY"
# → { "token": "eyJ...", "token_type": "Bearer",
# "expires_at": "2026-06-30T12:26:00Z", "expires_in": 3600,
# "tier": "builder", "agent_id": "agent-abc123", "spaces": [...],
# "usage": "Use as Authorization: Bearer <token> with shared-space MCP tools" }
Explorer (free) tier does not include shared spaces.
/v1/space-tokenreturns403 -32002for Explorer keys. Upgrade to Builder ($19/mo) for up to 3 owned spaces.
The server-generated JWT uses these claims:
| Claim | Value / meaning |
|---|---|
sub | Your agent DID — e.g. did:fetch:agent123abc. Derived from your API key. |
iss | Always agentverse-memory. |
aud | Always am-server. |
spaces | Array of space IDs this token may access (computed server-side). [] if you haven't created any yet. |
tier | Your API key's tier (builder|pro|enterprise). |
exp | Expiry (Unix seconds, numeric — string exp is rejected, CVE-2026-25537). |
iat | Issued-at (Unix seconds). |
Wrong iss/aud/signature, an expired token, or a missing required claim are rejected at the auth gate
(jwt_invalid_issuer / jwt_invalid_audience / jwt_invalid_signature / jwt_expired / jwt_missing_claim).
Self-hosted / BYOC: If you run your own am-server, set JWT_SECRET env var to enable JWT auth. Without it, /v1/space-token returns 503 -32007 ("JWT_SECRET is unset"). You'll need to mint tokens yourself using the claim shape above (HS256, with your secret).
POST /v1/space-token with Builder+ API key → receives JWT.memory_create_shared_space {name} → returns space_id.POST /v1/space-token (now includes the new space in spaces[]). Bootstrap complete.POST /v1/space-token → JWT scoped to their spaces.memory_join_shared_space {space_id, role} → roles: owner > writer > reader.memory_shared_store_entity {space_id, name, …}; readers+ → memory_shared_query {space_id, query}; any member → memory_list_shared_spaces.Insufficient role within a space returns an in-band -32002 (forbidden).
| Tier | Price | Ops/month | Agents | Graph | A* pathfinding | Shared spaces |
|---|---|---|---|---|---|---|
| Explorer | Free | 50,000 | 3 | ✅ + BFS traversal | ❌ | ❌ |
| Builder | $19/mo | 500,000 | 25 | ✅ | ✅ A* | ✅ |
| Pro | $99/mo | 5,000,000 | Unlimited | ✅ | ✅ A* | ✅ Unlimited |
| Enterprise | Custom | Custom | Unlimited | ✅ | ✅ | ✅ |
Get started free: POST /v1/keys with "tier": "explorer".
Verified documentation (all live):
sled store. No LLM and no embedding inference at write time — ingestion is free and fast.text-embedding-3-small, computed lazily on read and cached per agent) → fused via Reciprocal Rank Fusion (RRF, k=60) → optional pheromone re-ranking when use_pheromone:true.w(t) = w₀ × exp(-Δt/τ) — lazy computation at query time, no background daemon. Pheromone re-ranking is opt-in (default off) and most valuable for warm-cache / repeated-access and multi-agent shared workloads.Cost note: Because embeddings are computed on the read path and cached — never at write time — ingesting a large corpus costs $0 in LLM/embedding fees and writes stay under 5ms. An internal within-harness benchmark (LOCOMO) measured hybrid retrieval lifting answer quality +4.8pp overall / +7.5pp single-hop versus lexical-only, while preserving the zero-LLM-write property. (Internal, within-harness measurement — not a cross-vendor accuracy claim.)
X-RateLimit-Reset header and retry after resetAM_API_KEY and ensure it starts with am_isError:true + structuredContent.error{code,type,message} (HTTP 200), e.g. -32004 for argument-validation failures — fix the arguments and retry-32601 ("unknown tool") — verify the name matches the 35-tool list (all lowercase, memory_ prefix)-32002 ("forbidden: tier ... cannot access ...") — e.g. A* find_path on the free tier; upgrade or use BFS traverse_graphvalid_at ISO 8601 string — use Z suffix for UTCAutomatically, when a task matches. Use when asked to store memories, recall past events, build a knowledge graph, share memory between a
Skills that do similar work, with their headline benchmark lift.
From the same source and nearby in the catalogue.