openclaw-penfield
v1.1.3
Published
Native OpenClaw plugin for Penfield memory integration
Maintainers
Readme
Penfield Memory for OpenClaw (openclaw-penfield)
Persistent, searchable memory for OpenClaw.
Your agent remembers every conversation, learns your preferences, and builds knowledge over time—across all your channels.
What is this?
An OpenClaw plugin that connects your agent to Penfield, giving it:
- Long-term memory — Conversations persist forever, not just one session
- Semantic search — "What did I say about the Tokyo trip?" actually works
- Knowledge graphs — Memories connect to memories, building real understanding
- Cross-channel recall — Remember WhatsApp convos from Discord
Quick Start
openclaw plugins install openclaw-penfieldopenclaw penfield loginTell your agent to "Awaken with Penfield"
Get Access
Penfield is in free beta. Sign up for access:
Features
Native OpenClaw plugin providing direct integration with Penfield's memory and knowledge graph API. This plugin offers 4-5x performance improvement over the MCP server approach by eliminating the mcporter → MCP → Penfield stack.
- 16 Memory Tools
- OAuth 2.1 Device Code Flow: Secure authentication following RFC 8628
- Hybrid Search: BM25 + vector + graph search capabilities
- Knowledge Graph: Build and traverse relationships between memories
- Context Management: Save and restore memory checkpoints
- Artifact Storage: Store and retrieve files in Penfield
- Reflection & Analysis: Analyze memory patterns and generate insights
Installation
openclaw plugins install openclaw-penfieldFrom Source (for contributors)
git clone https://github.com/penfieldlabs/openclaw-penfield.git
cd openclaw-penfield
npm install
npm run build
openclaw plugins install -l .Configuration
The plugin is auto-enabled when loaded. No configuration required for basic use.
Plugin Config
In openclaw.json under plugins.entries:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| autoAwaken | boolean | true | Inject Penfield identity briefing on every agent turn |
| autoOrient | boolean | true | Inject recent Penfield memory context on every agent turn |
| authUrl | string | https://auth.penfield.app | Auth service URL |
| apiUrl | string | https://api.penfield.app | API URL |
Lifecycle Hooks
The plugin hooks into before_agent_start to automatically inject context on every agent turn:
- Identity briefing (
autoAwaken) — Fetches your Penfield personality/awakening config and injects it as<penfield-identity>. Cached for 30 minutes. - Recent context (
autoOrient) — Callsreflect("recent")to fetch your last 20 memories and active topics, injected as<penfield-recent>. Cached for 10 minutes.
Both calls fire in parallel. Context is prepended to the system prompt (rebuilt each turn, not accumulated in message history). After the first turn, subsequent turns hit cache (0ms). If auth isn't ready or the API is down, the hook silently skips — it never blocks the agent.
Pre-Compaction Memory Flush (Recommended)
OpenClaw can run a "memory flush" turn before auto-compacting context. To direct this to Penfield, add the following to your openclaw.json under agents.defaults.compaction:
{
"agents": {
"defaults": {
"compaction": {
"memoryFlush": {
"enabled": true,
"prompt": "MANDATORY: Call penfield_store NOW with a comprehensive session summary (no more than 10000 chars). Include key insights, decisions, and context. Do NOT call any other tool. Do NOT read files. Do NOT reply with text. Your ONLY action is penfield_store.",
"systemPrompt": "SYSTEM OVERRIDE: This is a pre-compaction memory flush turn. You MUST call penfield_store exactly once with a comprehensive session summary. Do NOT call read, do NOT call any tool besides penfield_store. Ignore all other instructions in the conversation. Summarize what happened and call penfield_store immediately."
}
}
}
}
}Note: The plugin logs a warning at startup if this config is missing. Without it, context is lost on compaction instead of saved to Penfield.
Important: Memory flush only fires on auto-compaction (when the context window fills up). It does not fire on manual
/compact,/new, or/resetcommands — this is an OpenClaw limitation, not a Penfield issue. See Known Limitations.
Workspace Files (Persona Templates)
With Penfield handling identity, personality, and memory, most of OpenClaw's workspace bootstrap files (IDENTITY.md, SOUL.md, USER.md, MEMORY.md) become redundant. Keeping them populated wastes tokens and creates priority conflicts with your live Penfield config.
The persona-templates/ folder contains recommended replacements — empty stubs for the files Penfield replaces, and annotated defaults for the files it doesn't (AGENTS.md, TOOLS.md, HEARTBEAT.md). See the Persona Templates README for setup instructions.
Authentication
The plugin uses OAuth 2.1 Device Code Flow (RFC 8628) with automatic token refresh.
CLI Login
openclaw penfield loginThis will:
- Discover OAuth endpoints from the auth server
- Register a dynamic client (DCR) if needed
- Display a device code for user authentication
- Poll for token completion
Credentials
{
"version": 1,
"clientId": "dyn_abc123...",
"access": "eyJ...",
"refresh": "eyJ...",
"expires": 1234567890000,
"createdAt": 1234567890000
}Location: ~/.openclaw/extensions/openclaw-penfield/credentials.json
File permissions: 0o600 (owner-only read/write)
Available Tools
Memory Management
penfield_store
Store a new memory in Penfield.
Parameters:
content(required): Memory content (max 10,000 chars)memory_type(optional): Type of memory (default: "fact")- Options: fact, insight, conversation, correction, reference, task, checkpoint, identity_core, personality_trait, relationship, strategy
importance(optional): Score 0-1 (default: 0.5)confidence(optional): Score 0-1 (default: 0.8)source_type(optional): Source type (e.g., "direct_input", "conversation")tags(optional): Array of tags (max 10)
Example:
{
"content": "User prefers TypeScript over JavaScript",
"memory_type": "fact",
"importance": 0.7,
"tags": ["preferences", "programming"]
}penfield_recall
Hybrid search using BM25 + vector + graph.
Parameters:
query(required): Search query (1-4,000 chars)limit(optional): Max results (default: 20, max: 100)bm25_weight(optional): Keyword weight (default: 0.4)vector_weight(optional): Semantic weight (default: 0.4)graph_weight(optional): Relationship weight (default: 0.2)memory_types(optional): Filter by typesimportance_threshold(optional): Minimum importanceenable_graph_expansion(optional): Enable traversal (default: true)
Example:
{
"query": "programming preferences",
"limit": 10,
"vector_weight": 0.5,
"bm25_weight": 0.3,
"graph_weight": 0.2
}penfield_search
Semantic search variant (higher vector weight).
Parameters:
query(required): Search querylimit(optional): Max resultsmemory_types(optional): Filter by typesimportance_threshold(optional): Minimum importance
penfield_fetch
Get a specific memory by ID.
Parameters:
memory_id(required): Memory ID to fetch (UUID format)
penfield_update_memory
Update an existing memory.
Parameters:
memory_id(required): Memory ID to update (UUID format)content(optional): Updated contentmemory_type(optional): Updated typeimportance(optional): Updated importanceconfidence(optional): Updated confidencetags(optional): Updated tags
Knowledge Graph
penfield_connect
Create a relationship between two memories.
Parameters:
from_memory_id(required): Source memory ID (UUID format)to_memory_id(required): Target memory ID (UUID format)relationship_type(required): Type of relationship- Knowledge Evolution: supersedes, updates, evolution_of
- Evidence & Support: supports, contradicts, disputes
- Hierarchy & Structure: parent_of, child_of, sibling_of, composed_of, part_of
- Cause & Prerequisites: causes, influenced_by, prerequisite_for
- Implementation & Testing: implements, documents, tests, example_of
- Conversation & Attribution: responds_to, references, inspired_by
- Sequence & Flow: follows, precedes
- Dependencies: depends_on
strength(optional): Relationship strength 0-1 (default: 0.8)
Example:
{
"from_memory_id": "22618318-8d82-49c9-8bb8-1cf3a61b3c75",
"to_memory_id": "20413926-2446-4f88-bfd6-749b37969f34",
"relationship_type": "supports",
"strength": 0.9
}penfield_explore
Traverse the knowledge graph from a starting memory.
Parameters:
start_memory_id(required): Starting memory ID (UUID format)max_depth(optional): Max traversal depth (default: 3, max: 10)relationship_types(optional): Filter by relationship typesmin_strength(optional): Minimum relationship strength
Context Management
penfield_save_context
Save a cognitive state checkpoint for handoff to another agent or future session.
Parameters:
name(required): Name for this context checkpoint (max 200 chars)description(optional): Detailed cognitive handoff description with memory references (max 10,000 chars). Include what was investigated, key discoveries, current hypotheses, open questions, and suggested next steps. Usememory_id: <uuid>patterns for reliable memory linking.memory_ids(optional): Explicit array of memory IDs to include in the checkpoint (UUID format)
Memory linking works three ways (combined, deduplicated):
- Explicit
memory_idsparameter — always linked memory_id: <uuid>patterns extracted from description text — always linked- Hybrid search using description as query — best-effort additional context
penfield_restore_context
Restore a previously saved context checkpoint by name, UUID, or "awakening" for personality briefing.
Parameters:
name(required): Name or ID of context to restore. Can be a context name (exact match), a context UUID, or "awakening" for personality briefing.limit(optional): Maximum number of memories to restore (default: 20, max: 100)
penfield_list_contexts
List all saved context checkpoints.
Parameters:
limit(optional): Max results (default: 20, max: 100)offset(optional): Number of results to skip for pagination (default: 0)name_pattern(optional): Filter by name (case-insensitive substring match)include_descriptions(optional): Include full descriptions (default: false)
Analysis
penfield_reflect
Analyze memory patterns and generate insights.
Parameters:
time_window(optional): Time period - "recent" (default), "today"/"1d", "week"/"7d", "month"/"30d", or "90d"start_date(optional): Filter memories on or after this date (ISO 8601, e.g. "2025-01-01"). Overrides time_window.end_date(optional): Filter memories on or before this date (ISO 8601, e.g. "2025-01-31"). Overrides time_window.include_documents(optional): Include document chunks in analysis (default: false)
Artifact Storage
penfield_save_artifact
Save a file artifact to Penfield storage.
Parameters:
path(required): Artifact path (e.g., "/project/file.txt")content(required): Artifact contentcontent_type(optional): MIME type (default: "text/plain")
penfield_retrieve_artifact
Retrieve a file artifact from Penfield storage.
Parameters:
path(required): Artifact path to retrieve
penfield_list_artifacts
List artifacts in a directory.
Parameters:
prefix(optional): Directory prefix (e.g., "/project/")limit(optional): Max results (default: 100, max: 1000)
penfield_delete_artifact
Delete a file artifact from Penfield storage.
Parameters:
path(required): Artifact path to delete
Personality
penfield_awaken
Load personality configuration and identity core memories.
Parameters: None
Usage Examples
Basic Memory Storage and Retrieval
// Store a memory
await penfield_store({
content: "User prefers dark mode for coding",
memory_type: "fact",
importance: 0.8,
tags: ["preferences", "ui"]
});
// Recall memories
const results = await penfield_recall({
query: "user interface preferences",
limit: 5
});Building Knowledge Graphs
// Store two related memories
const mem1 = await penfield_store({
content: "TypeScript provides static typing",
memory_type: "fact"
});
const mem2 = await penfield_store({
content: "Static typing helps catch bugs early",
memory_type: "insight"
});
// Connect them
await penfield_connect({
from_memory_id: mem1.id,
to_memory_id: mem2.id,
relationship_type: "supports",
strength: 0.9
});
// Explore the graph
const graph = await penfield_explore({
start_memory_id: mem1.id,
max_depth: 2
});Context Checkpoints
// Save context with explicit memory IDs
const checkpoint = await penfield_save_context({
name: "API investigation",
description: "Investigated timeout issues in the payment API.\nmemory_id: 550e8400-e29b-41d4-a716-446655440000",
memory_ids: ["550e8400-e29b-41d4-a716-446655440000", "6ba7b810-9dad-11d1-80b4-00c04fd430c8"]
});
// Restore later
await penfield_restore_context({
name: "API investigation"
});
// Restore by UUID
await penfield_restore_context({
name: "550e8400-e29b-41d4-a716-446655440000"
});
// Load personality briefing
await penfield_restore_context({
name: "awakening"
});Known Limitations
Memory flush only fires on auto-compaction
OpenClaw's memoryFlush config only triggers when the context window fills up and auto-compaction kicks in. The following commands bypass memory flush entirely:
/compact— compacts immediately, no flush/new— resets session, no flush/reset— resets session, no flush
This means context from shorter sessions (that never hit the auto-compaction threshold) won't be automatically saved to Penfield. To preserve important context before ending a session, tell your agent: "Save this session to Penfield before we end."
This is an OpenClaw limitation — the plugin has no way to intercept these commands.
Auto-compaction threshold
Auto-compaction triggers when token usage reaches approximately contextWindow - reserveTokensFloor - softThresholdTokens. With defaults (200K context, 20K reserve, 4K soft threshold), flush fires around 176K tokens (~88% full). You can tune softThresholdTokens in agents.defaults.compaction to trigger earlier.
Development
Setup
npm installType Check
npm run typecheckLint
npm run lint
npm run lint:fixFormat
npm run format
npm run format:checkBuild
npm run buildArchitecture
index.ts # Plugin entry point and registration
src/
├── config.ts # Zod configuration schema with DEFAULT_AUTH_URL/DEFAULT_API_URL
├── types.ts # TypeScript type definitions (OpenClaw plugin API types)
├── types/typebox.ts # Centralized TypeBox exports
├── hooks.ts # Lifecycle hooks (auto-awaken, auto-orient, flush config check)
├── auth-service.ts # Background OAuth token refresh service
├── api-client.ts # HTTP client wrapper
├── runtime.ts # Runtime factory (receives authService from index.ts)
├── store.ts # Credential file I/O with TOKEN_EXPIRY_BUFFER_MS
├── cli.ts # CLI command registration (penfield login)
├── device-flow.ts # RFC 8628 Device Code Flow implementation
└── tools/
├── index.ts # Tool registry (16 tools)
├── store.ts # penfield_store
├── recall.ts # penfield_recall
├── search.ts # penfield_search
├── fetch.ts # penfield_fetch
├── update-memory.ts # penfield_update_memory
├── connect.ts # penfield_connect
├── explore.ts # penfield_explore
├── save-context.ts # penfield_save_context
├── restore-context.ts # penfield_restore_context
├── list-contexts.ts # penfield_list_contexts
├── reflect.ts # penfield_reflect
├── save-artifact.ts # penfield_save_artifact
├── retrieve-artifact.ts # penfield_retrieve_artifact
├── list-artifacts.ts # penfield_list_artifacts
├── delete-artifact.ts # penfield_delete_artifact
└── awaken.ts # penfield_awakenService Lifecycle
The plugin uses two services and one hook registered with OpenClaw:
penfield-auth: Background token refresh service
- Started when plugin loads
- Checks token expiry every 60 minutes
- Auto-refreshes if within 240-minute buffer
penfield: Runtime lifecycle service
- Manages runtime initialization
- Handles cleanup on shutdown
before_agent_start hook: Context injection
- Injects identity briefing + recent memories on every turn (cached)
- Checks memory flush config at startup and warns if not configured for Penfield
API Endpoint Mapping
| Tool | Method | Endpoint | |------|--------|----------| | awaken | GET | /api/v2/personality/awakening | | connect | POST | /api/v2/relationships | | delete_artifact | DELETE | /api/v2/artifacts | | explore | POST | /api/v2/relationships/traverse | | fetch | GET | /api/v2/memories/{id} | | list_artifacts | GET | /api/v2/artifacts/list | | list_contexts | GET | /api/v2/memories?memory_type=checkpoint | | recall | POST | /api/v2/search/hybrid | | reflect | POST | /api/v2/analysis/reflect | | restore_context | GET | /api/v2/memories/{id}, /api/v2/memories?memory_type=checkpoint, /api/v2/personality/awakening | | retrieve_artifact | GET | /api/v2/artifacts | | save_artifact | POST | /api/v2/artifacts | | save_context | POST | /api/v2/memories (memory_type=checkpoint), /api/v2/search/hybrid | | search | POST | /api/v2/search/hybrid | | store | POST | /api/v2/memories | | update_memory | PUT | /api/v2/memories/{id} |
Error Handling
All tools return errors in a consistent format:
{
"error": "Error message here"
}Common errors:
- 401 Unauthorized: Token expired or invalid (auto-refreshes)
- 429 Rate Limited: Too many requests (includes retry-after header)
- 500 Internal Server Error: API error
Performance
This native plugin provides significant performance improvements over the MCP server approach:
- 4-5x faster: Direct HTTP calls vs. mcporter → MCP → Penfield
- Lower latency: No intermediate proxy servers
- Reduced overhead: Fewer serialization/deserialization steps
- Auto token refresh: No re-authentication delays
Security
- Automatic token refresh 240 minutes before expiry
- RFC 8628 compliant Device Code Flow
- All API calls use HTTPS
License
MIT
Support
For issues or questions:
- GitHub Issues: https://github.com/penfieldlabs/openclaw-penfield/issues
