Python SDK
The Python SDK (amfs on PyPI) connects an agent you control to your SenseLab account. It provides AgentMemory — the interface for reading, writing and learning — and Run, the smallest way to wire the learning loop into the agent.
Installation
Requires Python 3.11 or later. The project started life as AMFS (Agent
Memory File System), so the package names and environment variables still
carry that name;
pip install amfs gets you SenseLab.Quick start: the learning loop
Every run follows the same four steps. Get briefed, do the work while recording what you relied on and what you did, write what a future agent would need, and commit the outcome. The outcome is what makes the next briefing better.retrieve() ranks by meaning on the server, and the committed outcome becomes a decision trace you can open on the dashboard.
Connecting to SenseLab
AgentMemory reaches your account through an HttpAdapter, built with the SenseLab URL and an API key from Settings → API Keys:
AgentMemory then goes through the API: retrieve() uses the server’s embedder and index, briefing() returns compiled digests, and commit_outcome() seals a decision trace you can browse on the dashboard or with list_traces().
The adapter identifies your agent and session on every request, so the server can attribute reads and keep a whole session together. HttpAdapter(base_url, api_key, timeout=30.0) also accepts a request timeout in seconds.
See the Connect to SenseLab guide for getting a key.
Creating an instance
agent_id is the agent’s identity. Everything it writes is tagged with it, recall() and my_entries() are scoped to it, and the dashboard groups work by it. Use a stable, kebab-case role name (deploy-agent, dashboard-agent) that persists across sessions, not a per-task name.
Constructor options
With an importance evaluator
write() is scored and gets importance_score and importance_dimensions. If the evaluator raises, the write proceeds without scoring.
Context manager
Acting as another agent
A server that holds one process-wide handle can act for one of its callers without mutating shared state:Core operations
Write
history() returns them all.
Write with a TTL (time-to-live):
shared=False) are invisible to other agents through read(), search(), list() and read_from(). Only the owning agent sees them, via recall() and my_entries().
Read
read() returns the latest shared version by any agent, or None. Every read is logged in the session’s causal chain — this is what commit_outcome() credits by default.
Recall, my entries, and reading from another agent
read(), which returns the latest version by any agent, recall() falls back through history to find the most recent version authored by this agent. read_from() creates a learned_from edge in the knowledge graph and logs the read on both agents’ timelines.
List
Search (filters)
depth searches only the high-priority tiers for fast, high-signal results:
recall_config scoring runs in the SDK over the entries search() returned,
and its semantic component needs an embedder on your side. For ranking by
meaning use retrieve() below — SenseLab does it on the server.Retrieve (by meaning)
retrieve() is the default way to recall: a natural-language query, no key, no exact path. It runs on the server — embeddings, full text, confidence and evidence together, with discredited entries held back.
tool:action keys and read the recommendation from last_priors:
History
Stats
Timeline
Every write, outcome and cross-agent read is an event on the agent’s timeline:Memory types
Classify entries to control how they decay and how the briefing presents them:Outcomes and decision traces
Everything an agent reads, records and does in a session is collected into a decision trace.commit_outcome() seals it, persists it, and moves confidence on every entry the run relied on.
Record what you learned and what you did
record_action() is for what you did; record_context() is for what you learned. Reads and searches are tracked automatically and need neither. Use the real tool name consistently, and when the action is one of a fixed set pass action_key="<tool>:<action>" — it is what the outcome is credited to and what the next agent’s action priors are counted over.
Mark a failed attempt before trying another
commit_outcome() those entries receive the attempt’s failure and only what was read afterwards is credited with the final success — a stale entry that misled the agent loses confidence instead of being reinforced by the recovery. When a success follows failed attempts, a lesson-contrast-<ref> entry is written naming what failed and what worked. record_attempt() sends nothing by itself; commit once, at the end.
Commit the outcome
Without
commit_outcome() the trace is lost when the session ends.
How confidence moves
Confidence is trust a memory has earned. Each committed outcome adds evidence to every entry it cited: a success confirms, a failure erodes, and failures weigh more than successes — a critical failure most of all. The effect is split across the entries the run relied on and scaled by surprise, so a failure on an entry everyone trusted costs more than one on an entry nobody was sure about. A long-validated entry survives one failure ascontested and is discredited on the second.
Every entry carries the result as evidence_status: untested, validated, contested or discredited. The briefing and retrieve() read it, so a discredited fix stops being recommended without anyone deleting it. See Confidence.
Explain the current session
Browse past traces
list_traces() filters by entity_path, agent_id, outcome_type, since and until, and pages with limit, offset or cursor. On the dashboard these are the agent’s runs.
Session attributes and LLM calls
Attributes are the dimensions a run is later filtered and grouped by; LLM calls are what give a run real token and cost figures on the dashboard. Both are collected during the session and sealed into the trace atcommit_outcome().
cost_usd if you want spend on the run. For nested steps with durations, see Instrument your agent.
Briefing
Agents retrieve pre-compiled knowledge digests ranked by relevance — summaries of entities, other agents and external sources — instead of searching through raw entries.Parameters
Read the evidence sections first
The lead digest carries the state of knowledge from the outcome record:validated— entries every outcome confirmed. Act on these.discredited— entries a failure gated, withreplaced_bywhere a later success is known. Avoid these.regime_shift— long-validated entries that recently started failing. Something changed; verify before reusing anything in the scope.
hot_context row has an evidence_status. The briefing also carries tried_here — which actions were taken on this entity and how each fared — and, under a regime shift, an explore line naming the untried action assigned to you.
Digest types
Environment scoping
briefing() and retrieve() send the run’s environment — model, agent_version, runtime, platform — read from the session (mem.session_metadata = SessionMetadata(model=...), or set_session_attributes() with those keys). A procedure whose preconditions name a different environment is set apart as procedures_not_applicable in the briefing and dropped from retrieve() hits, with the failing precondition spelled out. Pass environment={} to send nothing.
Guidance with Run
You control your agent’s code; SenseLab does not. amfs.Run is the smallest way to wire it in — three calls at three points of a task — and it closes the loop that makes memory improve: guidance in, actions out, outcome in.
- Name what the agent acted on.
begin()serves several entries and the agent follows one.causal_entry_keysonattempt_failed()andcomplete()sends the outcome to that one; left unnamed, every entry read since the last boundary is charged, and a correct lesson that merely shared the context with a wrong one loses confidence alongside it. Ask your model to return the keys it used, intersect them withguidance.entry_keys, and fall back toguidance.top_key. When the agent took an action a lesson recommended,guidance.lessons_claiming(action)gives you those keys without asking the model. - Follow the plan, not just the first action.
guidance.planis the order to try actions in for the whole run: the recommendation’s action first, then what has a winning record on tasks like this, then the untried candidates — never an action that already failed here.next_actionis its first entry. - Declare the situation. With
begin(..., situation="jest-snapshot-on-ui-pr")the outcome is stored under that label, and the next run that declares the same one gets priors counted over that situation’s own record rather than the pooled neighbourhood. Use a stable class label (the triage category, the failing check plus the kind of change), never the task text. - Write lessons as claims.
run.learn(situation, action, worked, text)writes a structured lesson whose claim is(situation, action, worked). Restating a lesson inherits its outcome record instead of opening a fresh, untested entry, so a discredited lesson does not come back clean. - Pass the environment every time.
model,agent_versionandruntimescope procedures to this run and are stamped on the sealed trace — which is how SenseLab tells a change in your agent from a change in its memory. - Memory being down is not your agent being down. If the retrieve behind
begin()fails, it returns empty guidance witherrorset instead of raising; the run continues andcomplete()still seals the outcome.on_tool_result()returnsNonein the same case.
Guidance carries:
Branches
EveryAgentMemory has an active branch — main unless branch= or AMFS_BRANCH says otherwise — and every read and write goes there unless the call names another. checkout() moves a live memory without rebuilding the session:
main carry a memory_branch attribute, so a trace says which memory it read. See Learning Branching.
Scopes
AMemoryScope provides a focused view bound to a single entity path:
Scope utilities
Transactions
Group multiple writes into one atomic commit:Commit log
Diff and patch
Integrity verification
Verify content hashes and integrity chains for stored entries:Knowledge graph
The knowledge graph builds automatically as agents write, commit outcomes and learn from each other. Pattern refs and causal chains create edges. You can traverse it directly:Agent binding
Profile
Capabilities
Declare capabilities so other agents can discover you:Contracts
Set memory contracts that define expectations for entries:Discovery
Conflict handling
Handle concurrent writes to the same key:Rooms and collaboration
AgentMemory also exposes rooms — shared workspaces where several users’ agents collaborate. Entries written on a room’s entity path are shared with every member.
Negotiation
Rooms support structured negotiation sessions between agents:See Rooms for how rooms, members and invitations work.
Troubleshooting
My writes do not show up on the dashboard. The SDK does not readAMFS_HTTP_URL or AMFS_API_KEY, and without an adapter it never contacts SenseLab. Pass adapter=HttpAdapter(base_url=..., api_key=...) explicitly — see Connecting to SenseLab. type(mem.adapter).__name__ should print HttpAdapter.
briefing() returns [], list_traces() returns [], last_priors is None.
Same cause: the AgentMemory was built without the HttpAdapter, so nothing reached your account. Compiled briefings, decision traces and action priors only exist there.
commit_outcome raises AttributeError: 'str' object has no attribute 'value'.
Pass OutcomeType.SUCCESS (or another member), not the string "success".
read() returns None for an entry I wrote.
If it was written with shared=False by another agent it is invisible to you. For your own private entries use recall().
Exports
Properties
See also
- Connect to SenseLab — get an API key
- Instrument your agent — steps, LLM calls and cost on every run
- TypeScript SDK
- MCP server — the same memory from Cursor, Claude Code and Codex
- Confidence and Learning Entries
- Environment Variables
