Skip to main content
Use <private> tags to mark content you don’t want persisted in Claude Mem’s observation database. Claude can see and use the content during the current session, but it will never be saved as an observation or stored in any search index.

How it works

Wrap any content in <private> tags:
<private>
This content will not be stored in memory.
</private>
Tags are stripped at the hook layer — during storage, not from the live conversation. Claude sees the full content including the tags throughout the session; the tags only take effect when content is written to the database.
No configuration required. Private tag stripping is always active.

Use cases

Sensitive credentials or connection details

Please analyze this error:

<private>
Error: Database connection failed
Host: internal-db-prod.company.com
Port: 5432
User: admin_user
</private>

What might be causing this?
Claude sees the full error context. Only the question itself gets stored.

API keys

<private>
API_KEY=sk-proj-abc123xyz789
</private>

Test this API connection for me.
The key is available to Claude during the session but never written to disk.

Temporary session context

<private>
Background for this session only:
- Project deadline is tomorrow
- This is a hotfix for production
- Manager asked for this specifically
</private>

Help me fix this bug quickly.

Large debug output

<private>
Debug output from previous run:
[... 500 lines of logs ...]
</private>

Based on these logs, what's the root cause?

Exploratory notes

<private>
I'm just brainstorming here, not making a final decision.
</private>

What are some unconventional approaches to solving this?
Personal context helps Claude understand your request without polluting your observation history.

What gets filtered

Private content is stripped from every storage path:
Storage pathWhat happens
User prompt storageTags stripped before saving to the user_prompts table
Tool inputsParameters passed to tools are filtered before observation creation
Tool responsesOutput from tools is filtered before observation creation
Search indicesPrivate content never reaches the database or Chroma embeddings

What does not get filtered

  • Session summaries — generated only from non-private observations
  • Claude’s responses — not captured by Claude Mem at all

Tag behavior

BehaviorDetails
MultilineTags can wrap multiple lines
Multiple tagsYou can use several <private> sections in one message
Nested tagsInner tags are included in outer tag removal
Always activeNo configuration or setup needed

Architecture: edge processing

The <private> tag uses an edge processing pattern — content is filtered before it ever reaches the worker service or database:
  • UserPromptSubmit hook — strips tags from user prompts before saving to the user_prompts table
  • PostToolUse hook — strips tags from serialized tool_input and tool_response JSON before observation creation
This keeps the worker service simple and maintains a clean separation between ephemeral and persistent data. Tags remain visible in the live conversation but are stripped from all persistent storage.
The implementation strips tags from the serialized JSON representations of tool inputs and responses, not from the original conversation UI text. Your typed prompt is stored separately in the user_prompts table, where tags are also stripped before storage.

Verifying that tags work

Submit a prompt with <private> content, then check the database directly:
# Check the most recent stored prompt
sqlite3 ~/.claude-mem/claude-mem.db \
  "SELECT prompt_text FROM user_prompts ORDER BY created_at_epoch DESC LIMIT 1;"

# Check the most recent observation narrative
sqlite3 ~/.claude-mem/claude-mem.db \
  "SELECT narrative FROM observations ORDER BY created_at_epoch DESC LIMIT 1;"
The private content should not appear in either result. The <private> tags themselves should also be absent.

Best practices

  1. Don’t over-tag — Claude’s understanding of your project builds from observations. Excessive private tagging reduces the quality of future context.
  2. Use proper secrets management<private> prevents storage, but sensitive data like production credentials should still be handled through dedicated secrets tooling.
  3. Check the log if unsure~/.claude-mem/silent.log records tag-stripping activity and any errors.

Troubleshooting

  1. Verify correct syntax: <private>content</private>
  2. Check ~/.claude-mem/silent.log for errors
  3. Ensure the worker is running: npm run worker:status
  4. Restart the worker: npm run worker:restart
If content appears partially in observations:
  • Ensure tags are properly closed with </private>
  • Check for typos in the tag name
  • Verify the content is inside a tool execution, not only in your prompt text
If you see entries like this in ~/.claude-mem/silent.log:
[save-hook] stripMemoryTags received non-string: { type: 'object' }
This is usually harmless — it indicates defensive type checking is working correctly. If you see it frequently, please report it at github.com/thedotmack/claude-mem/issues.

Search tools

Search and retrieve past observations

Configuration

System settings and environment variables

Build docs developers (and LLMs) love