Best Practices

Patterns, pitfalls, and advanced usage

Agent best practices

These patterns help agents use archival memory effectively during conversations.

1. Avoid over-insertion

The most common pitfall is inserting too many memories, creating clutter. Trust the agent to decide what’s worth storing long-term.

2. Use tags consistently

Establish a tag taxonomy and stick to it. Good language models typically handle tagging well.

3. Add context to insertions

❌ Don’t: “Likes replicants” ✅ Do: “Deckard shows unusual empathy toward replicants, particularly Rachael, suggesting possible replicant identity”

4. Let agents experiment

Agents can test different query styles to understand what works:

1# What the agent does (agent tool call)
2archival_memory_search(query="How does the Voight-Kampff test work?")
3archival_memory_search(query="Voight-Kampff procedure")
4archival_memory_search(query="replicant detection method")

Important: Have the agent persist learnings from experimentation in a memory block (like archival_tracking or archival_policies), not in archival itself (avoid meta-clutter).

Developer best practices (SDK)

These patterns help developers configure and manage archival memory via the SDK.

Backfilling archives

Developers can pre-load archival memory with existing knowledge via the SDK:

1// Load company policies
2const policies = [
3 "All replicants must undergo Voight-Kampff testing upon arrival",
4 "Blade Runner units are authorized to retire rogue replicants",
5 "Tyrell Corporation employees must report suspected replicants immediately"
6];
7
8for (const policy of policies) {
9 await client.agents.passages.insert(agent.id, {
10 content: policy,
11 tags: ["policy", "company", "protocol"]
12 });
13}
14
15// Load technical documentation
16const docs = [
17 {
18 content: "Nexus-6 replicants: Superior strength, agility, and intelligence. Four-year lifespan prevents emotional development.",
19 tags: ["technical", "nexus-6", "specifications"]
20 },
21 {
22 content: "Voight-Kampff test: Measures capillary dilation, blush response, and pupil dilation to detect replicants.",
23 tags: ["technical", "testing", "voight-kampff"]
24 }
25];
26
27for (const doc of docs) {
28 await client.agents.passages.insert(agent.id, {
29 content: doc.content,
30 tags: doc.tags
31 });
32}

Use cases for backfilling:

  • Migrating knowledge bases to Letta
  • Seeding specialized agents with domain knowledge
  • Loading historical conversation logs
  • Importing research libraries

Create an archival policies block

Help your agent learn how to use archival memory effectively by creating a dedicated memory block for archival usage policies:

1await client.blocks.create({
2 label: "archival_policies",
3 value: `
4 When to insert into archival:
5 - User preferences and important facts about the user
6 - Technical specifications and reference information
7 - Significant decisions or outcomes from conversations
8
9 When NOT to insert:
10 - Temporary conversational context
11 - Information already stored
12 - Trivial details or pleasantries
13
14 Search strategies:
15 - Use natural language questions for best results
16 - Include tags when filtering by category
17 - Try semantic variations if first search doesn't find what you need
18 `
19});

You can improve this block through conversation with your agent:

You: “I noticed you didn’t store the fact that I prefer TypeScript for backend development. Update your archival policies block to ensure you capture language preferences in the future.”

Agent: Updates the archival_policies block to include “Programming language preferences” under “When to insert into archival”

This collaborative approach helps agents learn from mistakes and improve their archival memory usage over time.

Track query effectiveness

Build self-improving agents by having them track archival search effectiveness in a memory block:

1// Create a memory block for tracking
2await client.blocks.create({
3 label: "archival_tracking",
4 value: `
5 Query patterns: Natural language questions work best
6 Recent searches: "test procedures" (3 results), "replicant specs" (5 results)
7 Success rate: ~85% of searches return relevant results
8 Frequently searched topics: [technical specifications, protocols, case histories]
9 Common patterns: Queries about technical specs work better than vague questions
10 Improvements needed: Add more tags for better filtering
11 `
12});

The agent can update this block based on search results and continuously refine its archival strategy.

Enforcing archival usage with tool rules

If your agent forgets to use archival memory, you should first try prompting the agent to use it more consistently. If prompting alone doesn’t work, you can enforce archival usage with tool rules.

Force archival search at turn start:

1await client.agents.update(agent.id, {
2 toolRules: [
3 { type: "init", toolName: "archival_memory_search" }
4 ]
5});

Require archival insertion before exit:

1await client.agents.update(agent.id, {
2 toolRules: [
3 {
4 type: "child",
5 toolName: "send_message",
6 children: ["archival_memory_insert"]
7 }
8 ]
9});

Using the ADE: Tool rules can also be configured in the Agent Development Environment’s Tool Manager interface.

Note: Anthropic models don’t support strict structured output, so tool rules may not be enforced. Use OpenAI or Gemini models for guaranteed tool rule compliance.

When to use tool rules:

  • Knowledge management agents that should always search context
  • Agents that need to learn from every interaction
  • Librarian/archivist agents focused on information storage

Latency considerations: Forcing archival search adds a tool call at the start of every turn. For latency-sensitive applications (like customer support), consider making archival search optional.

Learn more about tool rules →

Modifying archival memories

While agents cannot modify archival memories, developers can update or delete them via the SDK:

1// Update a memory
2await client.agents.passages.update(agent.id, passage.id, {
3 content: "Updated content",
4 tags: ["new", "tags"]
5});
6
7// Delete a memory
8await client.agents.passages.delete(agent.id, passage.id);

This allows you to:

  • Fix incorrect information
  • Update outdated facts
  • Remove sensitive or irrelevant data
  • Reorganize tag structures

Troubleshooting

Why can’t my agent delete or modify archival memories?

Archival memory is designed to be agent-immutable by default. Agents can only insert and search, not modify or delete. This is intentional to prevent agents from “forgetting” important information.

Solution: If you need to modify or delete archival memories, use the SDK via client.agents.passages.update() or client.agents.passages.delete().

When should I use the SDK vs letting the agent handle archival?

Let the agent handle it when:

  • The agent needs to decide what’s worth remembering during conversations
  • You want the agent to curate its own knowledge base
  • Information emerges naturally from user interactions

Use the SDK when:

  • Pre-loading knowledge before the agent starts (backfilling)
  • Cleaning up incorrect or outdated information
  • Bulk operations (importing documentation, migrating data)
  • Managing memories outside of agent conversations

My agent isn’t using archival memory

Common causes:

  1. Agent doesn’t know to use it - Add guidance to the agent’s system prompt or create an archival_policies memory block
  2. Agent doesn’t need it yet - With small amounts of information, agents may rely on conversation history instead
  3. Model limitations - Some models are better at tool use than others

Solutions:

  • Add explicit instructions in the agent’s prompt about when to use archival
  • Use tool rules to enforce archival usage (see “Enforcing archival usage with tool rules” above)
  • Try a different model (OpenAI and Gemini models handle tool use well)

Search returns no results or wrong results

Common causes:

  1. Empty archive - Agent or developer hasn’t inserted any memories yet
  2. Query mismatch - Query doesn’t semantically match stored content
  3. Tag filters too restrictive - Filtering by tags that don’t exist or are too narrow

Solutions:

  • Verify memories exist using client.agents.passages.list() (uses cursor-based pagination with after, before, and limit parameters)
  • Try broader or rephrased queries
  • Check tags by listing passages to see what’s actually stored
  • Remove tag filters temporarily to see if that’s the issue

Agent inserting too many memories

Common causes:

  1. No guidance - Agent doesn’t know when to insert vs when not to
  2. Tool rules forcing insertion - Tool rules may require archival use
  3. Agent being overly cautious - Some models default to storing everything

Solutions:

  • Create an archival_policies block with clear guidelines (see “Create an archival policies block” above)
  • Review and adjust tool rules if you’re using them
  • Add explicit examples of what NOT to store in the agent’s prompt

Next steps