Skip to content

Procedural Memory

Procedural memory answers "how do I do this?" A procedure is a named skill: an ordered list of steps (action, parameters, expected outcome), the situations that should trigger it, and a running record of how often it succeeds.

Use it to store playbooks the agent can look up by situation ("the user wants to send an email") and to prefer the procedures that work best.


Models

ProceduralMemory

Field Type Default Description
name str "" Unique-ish procedure name (lookups use it)
content str "" Description (stored as description)
trigger_conditions list[str] [] Situations in which to use it
steps list[ProcedureStep] [] Ordered steps
success_rate float 0.0 Running success rate (0 – 1)
use_count int 0 Number of recorded executions
updated_at datetime \| None created_at on store

ProcedureStep

Field Type Default
step_order int 0
action str ""
parameters dict {}
expected_outcome str ""

Storage: PostgreSQL (procedures + procedure_steps, steps cascade-deleted with their procedure), Weaviate (<prefix>Procedural), ArangoDB (procedural_nodes with step_count, success_rate, use_count).


Usage

Learn a procedure

with AgentMemory(config) as mem:
    proc = mem.learn_procedure(
        "deploy_service",
        description="Deploy a service to the staging cluster",
        trigger_conditions=["user asks to deploy", "new release tagged"],
        steps=[
            {"action": "run_tests", "parameters": {"suite": "unit"}, "expected_outcome": "tests pass"},
            {"action": "build_image", "parameters": {"tag": "latest"}, "expected_outcome": "image pushed"},
            {"action": "kubectl_apply", "parameters": {"env": "staging"}, "expected_outcome": "pods ready"},
        ],
    )

learn_procedure numbers the steps 0, 1, 2… in list order.

Find a procedure

mem.procedural.get_by_name("deploy_service")

for p in mem.procedural.search_by_trigger("ship the new version to staging"):
    print(p.score, p.name, [s.action for s in p.steps])

mem.procedural.get_top_procedures(limit=10)   # by success rate, then use count

search_by_trigger is a vector search over the procedure's name, description and step text. Trigger conditions themselves are not part of the embedded text.

Track executions

mem.procedural.record_execution(proc.id, success=True)
mem.procedural.record_execution(proc.id, success=False)

p = mem.procedural.retrieve(proc.id)
print(p.use_count, p.success_rate)   # 2 0.5

record_execution increments use_count and updates the running average: new_rate = (old_rate × old_count + (1 if success else 0)) / (old_count + 1).

Update and delete

from agentic_memory.models import ProcedureStep

p.steps.append(ProcedureStep(step_order=3, action="smoke_test", expected_outcome="200 OK"))
mem.procedural.update(p)   # replaces all steps, re-embeds

mem.procedural.delete(p.id)

API Reference

Method Description
store(memory) -> str Store a procedure and its steps
retrieve(memory_id) Load a procedure with its steps
search(query, top_k=5) Vector similarity search
update(memory) Overwrite fields and replace all steps
delete(memory_id) Remove the procedure (steps cascade)
record_execution(memory_id, success) Update use_count and success_rate
get_by_name(name) First procedure with this name, or None
get_top_procedures(limit=10) Best procedures by success rate, then use count
search_by_trigger(condition) Vector search for procedures that fit a situation