forgetful
Memory server
Created by Scott
Published in ScottRBK/forgetful. Publisher page
339 GitHub stars
What it is
Opensource Memory for Agents
AutoGineer overview, from the brain’s own files
Forgetful is a storage and retrieval tool designed as a Model Context Protocol (MCP) server. It provides AI agents with persistent, semantically searchable memory, enabling them to maintain context across sessions and different agentic applications. By imposing the Zettelkasten principle, Forgetful requires memories to be atomic, which facilitates the automatic construction of a knowledge graph through semantic embedding and linking. It supports flexible storage backends including SQLite for local development and PostgreSQL for production, and uses local embedding models to ensure privacy and performance. Beyond simple memory, it supports entities, projects, and procedural skills, allowing agents to coordinate tasks and maintain complex relationships between data points.
How it works
Memory model: Hybrid
AutoGineer overview, from the brain’s own files
Forgetful functions as an MCP server that exposes meta-tools to connected AI agents. When an agent records a memory, it must provide a title, content, and context, which the server then converts into semantic embeddings using local models. The system automatically links new memories to existing ones based on similarity scores, building a knowledge graph. It manages the agent's context window by enforcing a token budget and ranking retrieved information by importance. The system also supports entities and relationships, allowing for structured data management alongside unstructured memory notes.
| Folder | Role | Files |
|---|---|---|
| .github | agent-config | 10 |
| app | source-code | 153 |
| docs | docs | 46 |
| examples | examples | 1 |
| skills | agent-instructions | 13 |
| tests | tests | 182 |
| alembic | folder | 18 |
| benchmarks | folder | 6 |
| docker | folder | 5 |
| nix | folder | 1 |
| test_harness | folder | 12 |
Requirements
Runtimes: Python >=3.12
Databases: PostgreSQL, Qdrant, SQLite
API keys (by name): FORGETFUL_TOKEN
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Google Antigravity, Kiro, OpenCode, Amp, Roo Code, Cline, JetBrains Junie, Devin (ex-Windsurf)
Set it up
This brain runs code automatically: 2 scripts. Review app/bootstrap.py, pyproject.toml before opening the folder in Claude Code. No step below turns a hook on for you.
app/bootstrap.py:python app/bootstrap.pypyproject.toml:hatch build hook vcs (hatch_build.py)
- Not scanned by AutoGineerThe author’s README also describes installing it with Docker Compose. Read its install section: AutoGineer did not scan that path. https://github.com/ScottRBK/forgetful/blob/9f85ddcf2ca1ae0264358e0b4b50860948ec1e03/README.md#option-3-docker-deployment-productionscale
- Not scanned by AutoGineerThe author’s README also describes installing it from a clone of its repository. Read its install section: AutoGineer did not scan that path. https://github.com/ScottRBK/forgetful/blob/9f85ddcf2ca1ae0264358e0b4b50860948ec1e03/README.md#quick-start
- Not scanned by AutoGineerIts dependencies are installed by pip or uv when you run it and were not scanned by AutoGineer (28 declared). https://pypi.org/project/forgetful-ai/
Created by Scott. Published in ScottRBK/forgetful. Licence: MIT License.
Usage
AutoGineer overview, from the brain’s own files
- Connect to AI agents via MCP (stdio or HTTP).
- Store atomic memories with context and tags.
- Query memories using natural language with semantic search.
- Manage projects and link memories to specific work streams.
- Track entities and their relationships for team or system context.
- Execute procedural skills stored as step-by-step instructions.
- “Create a memory about a technical decision.”
- The agent saves an atomic note linked to a project, which is then semantically indexed and linked to related past decisions.
- “Find information about a specific team member's role.”
- The agent retrieves the entity record for the person and any associated memories or relationship metadata.
Documentation by Scott
<h1 align="center">Forgetful</h1>
<p align="center"> <img src="https://img.shields.io/badge/python-3.12%2B-blue" alt="Python"> <img src="https://img.shields.io/badge/license-MIT-green" alt="License"> <img src="https://img.shields.io/badge/MCP-server-purple" alt="MCP"> <a href="https://github.com/jlowin/fastmcp"> <img src="https://img.shields.io/badge/FastMCP-powered-orange" alt="FastMCP"> </a> <a href="https://github.com/qdrant/fastembed"> <img src="https://img.shields.io/badge/FastEmbed-powered-orange" alt="FastEmbed"> </a> <a href="https://discord.gg/ngaUjKWkFJ"> <img src="https://img.shields.io/badge/Discord-Join%20Us-7289da?logo=discord&logoColor=white" alt="Discord"> </a> </p>
Forgetful is a storage and retrieval tool for AI Agents. Designed as a Model Context Protocol (MCP) server built using the FastMCP framework. Once connected to this service, MCP clients such as Coding Agents, Chat Bots or your own custom built Agents can store and retrieve information from the same knowledge base.
Table of Contents
Overview
Features
Quick Start
CLI
Usage Examples
How It Works
Configuration
Documentation
Contributing
License
Overview
A lot of us are using AI Agents now, especially in the realm of software development. The pace at which work and decisions are made can make it difficult for you to keep up from a notes and context persistence perspective.
So if you are following something like the BMAD Method for example and you want to take your brain storming session you've just had with Claude on your desktop/mobile and use it for the basis of your next Claude Code session, then having a shared knowledge base across the two agents can help with this.
This is just one example use case to illustrate the point, more and more agentic applications are going to surface and the use cases for sharing data across them is going to increase.
Knowledge bases are going to become a key infrastructure component for your interactions with AIs. There are many excellent knowledge base solutions available (many for free on github) and I would encourage you to check them out and find one that works for you (even if Forgetful doesn't) as I found from personal experience that interactions with my agents got easier and more rewarding once they knew more about me, my work and previous interactions that I had had with them or other AI systems.
What makes Forgetful different from other Memory based MCP services is that it is a rather opinionated view on how AI Agents such store and retrieve data.
Forgetful imposes the Zettelkasten principle when clients wish to record memories, that is each memory must be atomic (one concept per note). Along with the note (title and content), we also ask the client / agent to provide context around what it was doing when creating the note, along with keywords and tags. With this information we create semantic embeddings and store these to aid with later retrieval and in addition to this we also automatically link the memory to existing memories that have a particular similarity score, allowing for the automatic construction of a knowledge graph.
In this sense Forgetful becomes a little bit like Obsidian for AI Agents, where the auto linking nudges them in building up a graph of the knowledge.
We find, as do others (A-MEM: Agentic Memory or LLM Agents), all this helps in ensuring that when the agent requires relevant information from the memory system later, the correct information is returned.
In addition to just memories, Forgetful also has the concept of entities (think organisation, people, products), projects, documents, code artifacts, skills (procedural knowledge following the Agent Skills standard), and plans with tasks for multi-agent coordination, all of which can be associated with one or more memories.
Features
Configure either STDIO or HTTP transport mechanism (or stand up two services to support both)
Multiple Authentication supported, flows see FastMCP docs for full list
Meta Tool Discovery, only three tools exposed to client application to preserve context window.
Flexible Storage– SQLite (default, zero-config) or PostgreSQL (for scale and production deployments)
Stores memories as vectors and allowing memories to be retrieved from natural language queries from AI.
Cross Encoder reranking to improve recall and precision of memory retrieval.
Flexible ranking (embedding and cross encoder) providers, run everything locally without calls to the cloud thanks to FastEmbed
Automatic linking of semantically similar memories, automating the creation of the knowledge graph.
Plans and Tasks for multi-agent coordination -- structure work into plans with tasks that have acceptance criteria, state management with optimistic locking, and dependency tracking with cycle detection.
Skills for procedural memory -- store step-by-step instructions and agent capabilities with semantic search, import/export in Agent Skills SKILL.md format, and cross-referencing with memories.
For the complete roadmap, see Features Roadmap.
Quick Start
Option 1: PyPI (Recommended)
# Run directly with uvx (no installation needed)
uvx forgetful-ai
# Or install globally
uv tool install forgetful-ai
forgetfulData stored in platform-appropriate locations (~/.local/share/forgetful on Linux/Mac, AppData on Windows).
By default, runs with stdio transport for MCP clients. For HTTP:
uvx forgetful-ai --transport http --port 8020Option 2: From Source
git clone https://github.com/ScottRBK/forgetful.git
cd forgetful
# Install dependencies with uv
uv sync
# Run the server (uses SQLite by default)
uv run main.pyThe server starts with stdio transport. For HTTP: uv run main.py --transport http
Option 3: Docker Deployment (Production/Scale)
Forgetful provides two Docker deployment options:
SQLite with Docker (Simpler, Single-Container)
cd docker
cp .env.example .env
# Edit .env: Set DATABASE=SQLite and SQLITE_PATH=data/forgetful.db
docker compose -f docker-compose.sqlite.yml up -dThe SQLite database persists in the ./data directory on the host.
PostgreSQL with Docker (Recommended for multitenant)
See docker-compose.postgres.yml and .env.example
cd docker
cp .env.example .env
# Edit .env: Set DATABASE=Postgres and configure POSTGRES_* settings
docker compose -f docker-compose.postgres.yml up -dNote: If no .env file exists, the application uses defaults from app/config/settings.py.
For all configuration options, see Configuration Guide.
Connecting to An Agent
For detailed connection guides (Claude Code, Claude Desktop, other clients that support MCP), see Connectivity Guide.
Copilot CLI (includes custom agents and skills)
Gemini CLI (includes custom commands)
Opencode (includes custom commands and skills)
Add Forgetful to your MCP client configuration:
stdio transport (recommended for local use):
{
"mcpServers": {
"forgetful": {
"type": "stdio",
"command": "uvx",
"args": ["forgetful-ai"]
}
}
}HTTP transport (for Docker/remote):
{
"mcpServers": {
"forgetful": {
"type": "http",
"url": "http://localhost:8020/mcp"
}
}
}CLI
The forgetful command is also a full terminal client over the same tool registry the
MCP meta-tools use - against your local database by default, or a remote deployment
after auth login.
uv tool install forgetful-ai
# Curated verbs for daily use
forgetful memory save "Set generateResolvConf false to fix WSL2 DNS" \
--title "WSL2 DNS fix" --importance 7
forgetful memory search "wsl dns" -c "wsl networking" -n 5
forgetful memory get 812
forgetful memory recent -n 10 -p my-project
forgetful project list
# Generic passthrough to any available tool
forgetful tools list --category memory
forgetful tools info query_memory
forgetful call create_project --args '{"name": "Homelab", "description": "...", "project_type": "personal"}'
# Remote deployment (browser OAuth; saves FORGETFUL_SERVER to ~/.config/forgetful/.env)
forgetful auth login --server https://forgetful.example.com
forgetful auth status
forgetful memory search "wsl dns" -c "wsl networking" # now runs remotely
forgetful memory search "wsl dns" -c "wsl networking" --local # force local mode per invocation
# Scripting: --json emits machine-readable output
forgetful memory search "wsl dns" -c "wsl networking" --json | jq '.primary_memories[0].id'forgetful serve is the canonical way to run the MCP server (forgetful serve --transport http --port 8020); the bare forgetful / uvx forgetful-ai invocation and
the legacy --transport/--re-embed flags keep working indefinitely, so existing MCP
client configurations are unaffected. Headless environments can set FORGETFUL_TOKEN
(bearer) instead of the OAuth flow. See the
Configuration Guide for precedence rules, or walk
through the forgetful-cli-setup skill for install,
auth, and verification steps end-to-end.
Usage Examples
Forgetful exposes only 3 meta-tools to MCP clients. The tools available through
execute_forgetful_tool depend on the enabled feature flags. Use
discover_forgetful_tools for the current runtime catalog.
Example 1: Project-Scoped Memory
Create a memory linked to a project for better organization and scoped retrieval.
# Create project for organizing related knowledge
project = execute_forgetful_tool(
"create_project",
{
"name": "E-Commerce Platform Redesign",
"project_type": "work",
"status": "active"
}
)
# Create memory linked to project
memory = execute_forgetful_tool(
"create_memory",
{
"title": "Payment gateway: Stripe chosen over PayPal",
"content": "Selected Stripe for its API, fees, and fraud detection.",
"context": "Choosing the payment provider for the redesign",
"keywords": ["payment", "stripe", "paypal"],
"tags": ["payment", "decision"],
"importance": 9,
"project_ids": [project["id"]]
}
)
# Later, query within project scope
results = execute_forgetful_tool(
"query_memory",
{
"query": "payment processing implementation",
"query_context": "Implementing payments for the redesign",
"project_ids": [project["id"]]
}
)
# Returns: Stripe decision + auto-linked related memoriesExample 2: Knowledge Graph with Entities
Track people, organizations, and relationships - perfect for team and infrastructure management.
# New engineer joins your company
new_hire = execute_forgetful_tool(
"create_entity",
{
"name": "Jordan Taylor",
"entity_type": "Individual",
"description": "Backend Engineer - Payments Team",
"tags": ["engineering", "backend", "payments"]
}
)
# Get company entity (create if needed)
company = execute_forgetful_tool(
"create_entity",
{
"name": "TechFlow Systems",
"entity_type": "Organization",
"description": "SaaS platform company"
}
)
# Create employment relationship
execute_forgetful_tool(
"create_entity_relationship",
{
"from_entity_id": new_hire["id"],
"to_entity_id": company["id"],
"relationship_type": "works_for",
"metadata": {
"role": "Backend Engineer II",
"department": "Payments",
"start_date": "2025-01-20"
}
}
)
# Create memory about hiring
hire_memory = execute_forgetful_tool(
"create_memory",
{
"title": "Jordan Taylor hired - payments focus",
"content": "Jordan joins to build the Stripe integration and handle PCI compliance.",
"context": "Recording ownership and experience for the payments work",
"keywords": ["jordan", "stripe", "payments", "pci"],
"tags": ["team", "hiring", "payments"],
"importance": 7
}
)
# Link person to memory
execute_forgetful_tool(
"link_entity_to_memory",
{
"entity_id": new_hire["id"],
"memory_id": hire_memory["id"]
}
)
# Query Jordan's related knowledge
results = execute_forgetful_tool(
"query_memory",
{
"query": "Jordan payment implementation",
"query_context": "Finding ownership and experience for payments work"
}
)
# Returns: Hiring memory + linked entity + relationship contextTool Categories
The core catalog covers users, memories, projects, entities, code artifacts, and documents. Skills, files, plans, and tasks appear when their feature flags are enabled.
For complete documentation with extensive examples, see Complete Tool Reference.
How It Works
Atomic Memory Principle
Inspired by Zettelkasten, each memory stores one concept in ~300-400 words:
Easily titled – Forces clarity (200 char limit)
Self-contained – Understandable without external context
Linkable – Small units enable precise knowledge graphs
For detailed content, use Documents and extract 3-7 atomic memories that link to the parent document.
Automatic Knowledge Graph
When you create a memory:
Embedding generated – FastEmbed converts content to 384-dimensional vector
Similarity search – Finds related memories (similarity ≥0.7 by default)
Auto-linking – Creates bidirectional links to top 3-5 matches (configurable)
Graph traversal – Queries return primary results + 1-hop linked memories
Entities and Knowledge Graphs
Entities represent concrete, real-world things (people, organizations, teams, devices) that can be linked to memories:
Typed entities – Organizations, Individuals, Teams, Devices, Systems, or custom types
Relationships – Directional connections (e.g., "Person works_at Organization") with strength and metadata
Memory linking – Associate entities with relevant memories for context
Knowledge graph – Build networks showing how entities relate to each other and your knowledge base
Use entities for concrete things (Sarah Chen, TechFlow Systems, Cache Server 01) and memories for abstract concepts (architectural patterns, decisions, learnings).
Token Budget Management
Prevents context window overflow:
Configurable budget (default 8K tokens)
Search finds relevant memories; primary results are then sorted by importance (high first)
Equal-importance primary results keep their search order, even when nothing is truncated
Truncates gracefully if over budget
Respects max memory count (default 20)
This keeps query results within the LLM's context budget.
For vector search and optional cross-encoder reranking, see Search Documentation.
Configuration
No configuration required – Forgetful uses sensible defaults out of the box.
Key Settings (Optional)
MEMORY_TOKEN_BUDGET– Max tokens for query results (default:8000)EMBEDDING_MODEL– Embedding model (default:BAAI/bge-small-en-v1.5)MEMORY_NUM_AUTO_LINK– Auto-link count (default:3, set0to disable)MEMORY_SIMILARITY_THRESHOLD– Minimum cosine similarity for auto-links (default:0.7)SERVER_PORT– HTTP server port (default:8020)MAX_GRAPH_LIMIT– Upper bound for/api/v1/graph?limitand/api/v1/graph/subgraph?max_nodes(default:2000)
For all 40+ environment variables with detailed explanations, see Configuration Guide.
Documentation
Guides
Core Concepts – Memories vs Entities vs Documents explained
Complete Tool Reference – Runtime tools and examples
REST API Reference – HTTP endpoints for web UI integration
Configuration Guide – All environment variables explained
Connectivity Guide – Connect Claude and other MCP clients
Self-Hosting Guide – Deploy on a VPS with Docker
Nix Guide – Reproducible dev shell, builds and OCI image with Nix flakes
Search Documentation – Embedding pipeline and retrieval architecture
Embedding Migration – Switch embedding providers safely
Features Roadmap – Planned features and priorities
External Resources
MCP Protocol Specification – Model Context Protocol docs
pgvector – PostgreSQL vector extension
FastEmbed – Local embedding generation
Zettelkasten Principle – Atomic note-taking method
Contributing
We welcome contributions! Forgetful uses integration + E2E testing with Docker Compose orchestration.
See the contributor guide for:
Testing workflows (integration tests, E2E tests, GitHub Actions)
Development setup (local vs Docker)
CI/CD pipeline details
Release process
License
MIT License - see LICENSE for details.
docs/tool_reference.md
Forgetful MCP Server - Complete Tool Reference
This guide provides comprehensive documentation for all tools available in the Forgetful MCP server.
Table of Contents
Meta-Tools Pattern
Tool Categories Overview
User Tools
Memory Tools
Project Tools
Code Artifact Tools
Document Tools
Skill Tools
Entity Tools
Plan Tools
Task Tools
Cross-Category Workflows
Meta-Tools Pattern
Forgetful uses a meta-tools pattern to preserve your LLM's context window. Only 3 meta-tools are visible to MCP clients; the inner tool catalog depends on the enabled feature flags.
The Three Meta-Tools
1. discover_forgetful_tools
List available tools, optionally filtered by category.
Parameters:
category(optional): Filter by category (user,memory,project,code_artifact,document,entity,plan,task,skill)
Returns:
tools_by_category: Tools grouped by categorytotal_count: Total number of toolscategories_available: List of all categoriesfiltered_by: Applied filter (if any)
Example:
# Discover all memory tools
discover_forgetful_tools(category="memory")
# Discover all available tools
discover_forgetful_tools()2. how_to_use_forgetful_tool
Get detailed documentation for a specific tool.
Parameters:
tool_name: Name of the tool
Returns:
Complete tool documentation with JSON schema, parameters, and examples
Example:
how_to_use_forgetful_tool(tool_name="create_memory")3. execute_forgetful_tool
Execute any registered tool dynamically.
Parameters:
tool_name: Name of the tool to executearguments: Dictionary of arguments for the tool
Returns:
Tool execution result (format depends on specific tool)
Example:
execute_forgetful_tool(
tool_name="create_memory",
arguments={
"title": "Database choice: PostgreSQL",
"content": "Selected PostgreSQL for pgvector support",
"context": "Choosing the database for vector search",
"keywords": ["postgresql", "pgvector"],
"tags": ["database", "decision"],
"importance": 9
}
)Tool Categories Overview
The core catalog covers users, memories, projects, code artifacts, documents, and entities.
Skills, files, plans, and tasks appear only when their feature flags are enabled. Call
discover_forgetful_tools() for the exact catalog exposed by the running server.
User Tools
Manage user authentication and profile information.
get_current_user
Returns information about the currently authenticated user.
Parameters: None
Returns:
user_id: Unique user identifierusername: User's usernameemail: User's emailnotes: User profile notescreated_at: Account creation timestamp
Example:
user = execute_forgetful_tool("get_current_user", {})
# Returns: {"user_id": 1, "username": "alex_smith", "email": "[e-mail address on the upstream page](https://github.com/ScottRBK/forgetful/blob/9f85ddcf2ca1ae0264358e0b4b50860948ec1e03/docs/tool_reference.md)", ...}update_user_notes
Update the notes field for the current user's profile.
Parameters:
notes: Text content for user notes
Returns:
Updated user object
Example:
execute_forgetful_tool(
"update_user_notes",
{"notes": "Prefers TypeScript over JavaScript. Works on microservices architecture."}
)Memory Tools
Memory create/update/obsolete/restore can be checked by an administrator's
Memory Plugin. Success adds plugin_warnings only when
nonempty; each entry contains outcome="warn", a client-safe message, and optional code.
Create keeps its existing confirmation fields and obsolete_matches. Update stays a flat memory
object. Lifecycle tools keep {"success": true} plus any warnings. Reads, lists, queries, and
events do not contain these transient warnings.
A warning means the write succeeded: review the message without creating a duplicate. Rejection
raises WRITE_PLUGIN_REJECTED: <message> and leaves the write unapplied. Correct the stated issue
within the user's authorization before making another attempt. Before-handler failure/timeout raises
WRITE_PLUGIN_UNAVAILABLE: Memory Write Plugin unavailable. in enforce mode; warn mode writes
with that generic warning instead. Do not automatically retry or claim a rejected write succeeded.
After handlers are advisory in both modes. Failure adds warning code
MEMORY_PLUGIN_AFTER_SAVE_UNAVAILABLE while retaining success. Create's after handler can use
existing scored matches and links to warn about near duplicates after persistence; it cannot
prevent creation. No-op updates skip both phases. Linking/unlinking and entity tools are unaffected.
External cancellation or network failure can lose a response after persistence; verify state
before retrying.
The core of Forgetful - atomic knowledge storage and semantic retrieval.
create_memory
Create an atomic memory with automatic linking to related memories.
Parameters:
title(required): Short, searchable title (max 200 chars)content(required): Memory content - ONE concept (max 2000 chars, ~300-400 words)importance(required): Importance score 1-10 (9-10 = foundational, 7-8 = patterns, 5-6 = context)context(required): Why the memory matters (max 500 chars)keywords(required): Search keywords (max 10)tags(required): Categorization tags (max 10)project_ids(optional): Project IDs to linkdocument_ids(optional): Document IDs to linkfile_ids(optional): Existing file IDs to link (files must belong to the current user; unknown IDs fail)code_artifact_ids(optional): Code artifact IDs to link
Provenance Tracking (optional):
source_repo(optional): Repository source (e.g., 'owner/repo', max 200 chars)source_files(optional): List of file paths that informed this memorysource_url(optional): URL to original source material (max 2048 chars)confidence(optional): Encoding confidence score (0.0-1.0)encoding_agent(optional): Agent/process that created this memory (max 100 chars)encoding_version(optional): Version of encoding process/prompt (max 50 chars)
Returns:
id: Created memory IDtitle: Created memory titlelinked_memory_ids: Automatically linked memory IDssimilar_memories: Summaries of the automatic-link candidates; each entry includessimilarity(cosine similarity to the new memory)obsolete_matches: Up to 3 obsolete memories similar to the new content (on by default viaOBSOLETE_WARNING_ENABLED); each match includesid,title,similarity,obsolete_reason,superseded_by,obsoleted_at,project_ids. Warning-only; never blocks creation. Empty when the feature is disabled.
Example:
memory = execute_forgetful_tool(
"create_memory",
{
"title": "API rate limiting: 100 req/min per user",
"content": "Implemented rate limiting at 100 requests per minute per authenticated user to prevent abuse. Uses Redis for distributed counting across instances.",
"importance": 8,
"context": "Performance and security discussion during API redesign",
"keywords": ["rate-limiting", "api", "redis", "performance"],
"tags": ["api", "security", "performance"],
"project_ids": [12]
}
)
# Returns: {"id": 156, "linked_memory_ids": [142, 148, 151], ...}Example with provenance:
# Memory created by AI agent with source tracking
memory = execute_forgetful_tool(
"create_memory",
{
"title": "FastAPI dependency injection pattern",
"content": "Use Depends() for request-scoped dependencies.",
"context": "Recording a reusable FastAPI implementation pattern",
"keywords": ["fastapi", "depends", "dependency-injection"],
"tags": ["fastapi", "pattern", "dependency-injection"],
"importance": 8,
"source_repo": "tiangolo/fastapi",
"source_files": ["docs/tutorial/dependencies.md", "docs/advanced/async-database.md"],
"source_url": "https://fastapi.tiangolo.com/tutorial/dependencies/",
"confidence": 0.92,
"encoding_agent": "claude-sonnet-4-20250514",
"encoding_version": "1.0.0"
}
)query_memory
Semantic search across all memories with context-aware ranking.
Parameters:
query(required): Natural language search queryquery_context(required): Why the search is being performedk(optional): Number of primary results (default: 3, maximum: 20)include_links(optional): Include linked memories (default: true)max_links_per_primary(optional): Linked memories per primary result (default: 5)importance_threshold(optional): Minimum importance scoreproject_ids(optional): Project IDs to searchstrict_project_filter(optional): Apply the project filter to linked memories
Returns:
List of memories ranked by semantic relevance
Each memory includes linked artifacts and 1-hop graph connections
scores: OneMemoryScoreper primary memory (memory_id,similarity,rerank_score), aligned by index withprimary_memories. Primaries are importance-sorted after retrieval, so list position is not similarity rank.access_count/last_accessed_aton each returned fullMemory(not onMemorySummary). On upstream they increment whenmemory.queriedfires, which requiresACTIVITY_TRACK_READS=trueand an EventBus. Not request parameters.
Example:
results = execute_forgetful_tool(
"query_memory",
{
"query": "how do we handle authentication",
"query_context": "Implementing authentication for the API",
"project_ids": [12],
"importance_threshold": 7,
"k": 5
}
)
# Returns: {"primary_memories": [...], "linked_memories": [...], ...}get_memory
Retrieve complete memory details by ID.
Parameters:
memory_id(required): Memory ID
Returns:
Complete memory object with all fields and relationships
access_count/last_accessed_aton the fullMemory. On upstream they increment whenmemory.readfires, which requiresACTIVITY_TRACK_READS=trueand an EventBus. Not writable viaupdate_memory.
Example:
memory = execute_forgetful_tool("get_memory", {"memory_id": 156})update_memory
Update existing memory fields (PATCH semantics - only updates provided fields).
Parameters:
memory_id(required): Memory IDtitle(optional): Updated titlecontent(optional): Updated contentimportance(optional): Updated importance scorecontext(optional): Updated contextkeywords(optional): Updated keywordstags(optional): Updated tagsfile_ids(optional): Replaces existing file links;[]clears them; omit to leave them unchanged
Provenance Tracking (optional):
source_repo(optional): Repository source (e.g., 'owner/repo')source_files(optional): List of file pathssource_url(optional): URL to source materialconfidence(optional): Confidence score (0.0-1.0)encoding_agent(optional): Agent/process identifierencoding_version(optional): Version of encoding process
Returns:
Updated memory object
Example:
execute_forgetful_tool(
"update_memory",
{
"memory_id": 156,
"importance": 9, # Increased importance after realizing how critical this is
"tags": ["api", "security", "performance", "production"]
}
)Example - Adding provenance after creation:
# Add provenance to an existing memory
execute_forgetful_tool(
"update_memory",
{
"memory_id": 156,
"source_repo": "company/api-gateway",
"confidence": 0.95,
"encoding_agent": "manual-review"
}
)link_memories
Manually create bidirectional links between memories.
Parameters:
memory_id(required, int): Source memory ID (aliases:source_id,from_id,id)related_ids(required, List[int] or int): Target memory IDs (aliases:target_id,target_ids,related_id,linked_ids)memory_ids(optional, List[int]): Pair/list of memory IDs[src, target1, target2, ...]
Returns:
Dict with
linked_memory_ids(list of target IDs newly linked). Target IDs that do not exist, belong to another user, or are already linked are skipped.
Examples:
# Standard syntax
execute_forgetful_tool(
"link_memories",
{
"memory_id": 156, # Rate limiting decision
"related_ids": [201] # Redis caching strategy
}
)
# Alias syntax with source_id and target_id
execute_forgetful_tool(
"link_memories",
{
"source_id": 156,
"target_id": 201
}
)
# Pair list syntax
execute_forgetful_tool(
"link_memories",
{
"memory_ids": [156, 201]
}
)unlink_memories
Remove bidirectional link(s) between memories.
Parameters:
source_id(required, int): Source memory ID (aliases:memory_id,from_id,id)target_id(required, int or List[int]): Target memory ID(s) to unlink (aliases:target_ids,related_id,related_ids,linked_ids)memory_ids(optional, List[int]): List of memory IDs[src, target1, target2, ...]
Returns:
Dict with
successboolean (True if all requested links were removed)
Examples:
execute_forgetful_tool(
"unlink_memories",
{
"source_id": 156,
"target_id": 201
}
)
execute_forgetful_tool(
"unlink_memories",
{
"memory_id": 156,
"related_ids": [201, 202]
}
)
execute_forgetful_tool(
"unlink_memories",
{
"memory_ids": [156, 201, 202]
}
)mark_memory_obsolete
Soft delete a memory with audit trail and supersession tracking.
Parameters:
memory_id(required): Memory ID to mark obsoletereason(required): Reason for obsolescencesuperseded_by(optional): ID of replacement memory
Returns:
{"success": true}, withplugin_warningsonly when nonempty
Example:
execute_forgetful_tool(
"mark_memory_obsolete",
{
"memory_id": 78, # Old "Docker Swarm deployment" memory
"reason": "Migrated to Kubernetes",
"superseded_by": 312 # New K8s memory
}
)unobsolete_memory
Restore a memory previously marked obsolete (undo mark_memory_obsolete).
Parameters:
memory_id(required): ID of the obsolete memory to restore
Returns:
{"success": true}, withplugin_warningsonly when nonempty
Example:
execute_forgetful_tool(
"unobsolete_memory",
{"memory_id": 78},
)get_recent_memories
Retrieve most recent memories sorted by creation timestamp.
Parameters:
limit(optional): Max memories to return (default: 10)project_ids(optional): Scope to specific projects
Returns:
An object (not a bare list) with two keys:
memories: list of recent memories, sorted bycreated_atDESC (newest first)total_count: total number of matching memories
Each memory's
linked_memory_idsincludes both directions of links (same set asget_memory).
Example:
result = execute_forgetful_tool(
"get_recent_memories",
{"limit": 10, "project_ids": [12]}
)
recent = result["memories"] # the list of memories
total = result["total_count"] # how many matched in totalBehavior change (PR #49) — the return shape is now an envelope.
This tool used to return a bare JSON array of memories. It now returns an object:
{"memories": [...], "total_count": N}.Why: MCP structured content requires an object root. A bare
[]carries no structured content over the wire, so an empty result collapsed tonullfor remote consumers and could not be told apart from "no result". Wrapping the list in an object lets empty results survive the wire and matches thelist_*tool family.Migration: read
result["memories"]instead of indexing the bare result, and readresult["total_count"]if you need the total. For example, replacefor m in result:withfor m in result["memories"]:. The REST endpoint is unaffected — this change is only in the MCP tool surface.
Project Tools
Organize memories, code artifacts, and documents by project context.
Project Types
personal,work,learning,development,infrastructuretemplate,product,marketing,finance,documentationdevelopment-environment,third-party-library,open-source
Project Statuses
active,archived,completed
create_project
Create a new project for organizing knowledge.
Parameters:
name(required): Project nameproject_type(optional): Project type (see list above)description(optional): Project descriptionstatus(optional): Project status (default:active)repository_url(optional): Git repository URLmetadata(optional): Additional JSON metadatalast_encoding_point(optional): Opaque caller-managed encoding checkpoint (e.g. a Git commit SHA). The server never infers or advances it; the encoding client updates it only after a successful run.
Returns:
Created project with
project_id
Example:
project = execute_forgetful_tool(
"create_project",
{
"name": "E-Commerce Platform Redesign",
"project_type": "work",
"description": "Complete redesign of checkout and payment flows",
"status": "active",
"repository_url": "https://github.com/company/ecommerce-v2"
}
)
# Returns: {"project_id": 22, "name": "E-Commerce Platform Redesign", ...}list_projects
List projects with optional filtering.
Parameters:
project_type(optional): Filter by project typestatus(optional): Filter by statusrepository_url(optional): Filter by repository
Returns:
List of matching projects
Example:
# Get all active work projects
active_work = execute_forgetful_tool(
"list_projects",
{"project_type": "work", "status": "active"}
)get_project
Retrieve complete project details by ID.
Parameters:
project_id(required): Project ID
Returns:
Complete project object
Errors:
Raises an error (not
null) whenproject_iddoes not exist or is not visible to the caller
Example:
project = execute_forgetful_tool("get_project", {"project_id": 22})update_project
Update project metadata (PATCH semantics).
Parameters:
project_id(required): Project IDname(optional): Updated namedescription(optional): Updated descriptionstatus(optional): Updated statusrepository_url(optional): Updated repository URLmetadata(optional): Updated metadatalast_encoding_point(optional): Opaque caller-managed encoding checkpoint (e.g. a Git commit SHA). The server never infers or advances it; the encoding client updates it only after a successful run. Unchanged if omitted; set to empty string to clear.
Returns:
Updated project object
Example:
# Mark project as completed
execute_forgetful_tool(
"update_project",
{
"project_id": 22,
"status": "completed",
"metadata": {"completion_date": "2025-01-15", "outcome": "shipped to production"}
}
)delete_project
Delete project while preserving linked memories, artifacts, and documents.
Parameters:
project_id(required): Project ID
Returns:
Confirmation of deletion
Example:
execute_forgetful_tool("delete_project", {"project_id": 22})Code Artifact Tools
Store and retrieve reusable code snippets and patterns.
create_code_artifact
Store a reusable code snippet.
Parameters:
title(required): Artifact titlecontent(required): Code contentlanguage(required): Programming languagedescription(optional): Artifact descriptiontags(optional): Categorization tagsproject_id(optional): Link to projectframework(optional): Framework name (e.g., "React", "FastAPI")version(optional): Version string
Returns:
Created artifact with
code_artifact_id
Example:
artifact = execute_forgetful_tool(
"create_code_artifact",
{
"title": "Async Retry Decorator with Exponential Backoff",
"content": '''
import asyncio
from functools import wraps
def async_retry(max_attempts=3, base_delay=1.0):
def decorator(func):
@wraps(func)
async def wrapper(*args, **kwargs):
for attempt in range(max_attempts):
try:
return await func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts - 1:
raise
delay = base_delay * (2 ** attempt)
await asyncio.sleep(delay)
return wrapper
return decorator
''',
"language": "python",
"description": "Reusable retry logic for async operations - use for API calls",
"tags": ["async", "retry", "decorator", "resilience"],
"project_id": 12
}
)
# Returns: {"code_artifact_id": 45, ...}list_code_artifacts
List code artifacts with optional filtering.
Parameters:
project_id(optional): Filter by projectlanguage(optional): Filter by programming languagetags(optional): Filter by tags
Returns:
List of matching code artifacts
Example:
# Find all Python utilities
python_utils = execute_forgetful_tool(
"list_code_artifacts",
{"language": "python", "tags": ["utility"]}
)get_code_artifact
Retrieve complete code artifact by ID.
Parameters:
code_artifact_id(required): Artifact ID
Returns:
Complete artifact object with code content
Example:
artifact = execute_forgetful_tool("get_code_artifact", {"code_artifact_id": 45})update_code_artifact
Update code artifact (PATCH semantics).
Parameters:
code_artifact_id(required): Artifact IDtitle,content,language,description,tags,framework,version(all optional)
Returns:
Updated artifact object
Example:
execute_forgetful_tool(
"update_code_artifact",
{
"code_artifact_id": 45,
"version": "2.0.0",
"tags": ["async", "retry", "decorator", "resilience", "production"]
}
)delete_code_artifact
Delete code artifact (cascades memory associations).
Parameters:
code_artifact_id(required): Artifact ID
Returns:
Confirmation of deletion
Example:
execute_forgetful_tool("delete_code_artifact", {"code_artifact_id": 45})Document Tools
Store long-form content (>400 words) like architecture decision records, research notes, and detailed documentation.
Document Types
text- Plain text documentsmarkdown- Markdown-formatted documentscode- Code documentationCustom types - Define your own
create_document
Create a document for long-form content.
Parameters:
title(required): Document titlecontent(required): Document content (no character limit)document_type(optional): Document type (default:text)description(optional): Document descriptiontags(optional): Categorization tagsproject_id(optional): Link to project
Returns:
Created document with
document_id
Example:
doc = execute_forgetful_tool(
"create_document",
{
"title": "ADR-003: Migration to Event-Driven Architecture",
"content": '''
# Architecture Decision Record: Event-Driven Architecture
## Status
Accepted
## Context
Our monolithic architecture faces scaling challenges:
- Tight coupling between services creates deployment bottlenecks
- Database contention during peak loads
- Difficulty adding new features without affecting existing systems
[... 2000+ words of detailed analysis ...]
## Decision
Adopt event-driven architecture using Apache Kafka as message broker.
## Consequences
### Positive
- Loose coupling enables independent service scaling
- Event sourcing provides audit trail
- Easier to add new consumers
### Negative
- Increased operational complexity
- Eventual consistency requires careful handling
- Team needs training on distributed systems
## Implementation Plan
[... detailed steps ...]
''',
"document_type": "markdown",
"tags": ["adr", "architecture", "event-driven", "kafka"],
"project_id": 22
}
)
# Returns: {"id": 89, ...}
# Extract atomic memories from this document
memory1 = execute_forgetful_tool(
"create_memory",
{
"title": "Architecture decision: Event-driven with Kafka",
"content": "Adopted event-driven architecture using Kafka.",
"context": "Capturing the decision from the architecture document",
"keywords": ["architecture", "kafka", "events"],
"tags": ["architecture", "decision"],
"importance": 10,
"document_ids": [89],
"project_ids": [22]
}
)list_documents
List documents with optional filtering.
Parameters:
project_id(optional): Filter by projectdocument_type(optional): Filter by typetags(optional): Filter by tags
Returns:
List of matching documents
Example:
# Find all ADRs
adrs = execute_forgetful_tool(
"list_documents",
{"tags": ["adr"], "document_type": "markdown"}
)get_document
Retrieve complete document by ID.
Parameters:
document_id(required): Document ID
Returns:
Complete document object with full content
Example:
doc = execute_forgetful_tool("get_document", {"document_id": 89})update_document
Update document (PATCH semantics).
Parameters:
document_id(required): Document IDtitle,content,document_type,description,tags(all optional)
Returns:
Updated document object
Example:
execute_forgetful_tool(
"update_document",
{
"document_id": 89,
"tags": ["adr", "architecture", "event-driven", "kafka", "implemented"]
}
)delete_document
Delete document (cascades memory associations).
Parameters:
document_id(required): Document ID
Returns:
Confirmation of deletion
Example:
execute_forgetful_tool("delete_document", {"document_id": 89})Skill Tools
Store and manage procedural knowledge (step-by-step instructions, agent capabilities) following the Agent Skills open standard.
create_skill
Create a skill for storing procedural knowledge.
Parameters:
name(required): Kebab-case skill name (e.g., 'code-review'). Must match^[a-z0-9]+(-[a-z0-9]+)*$description(required): What the skill does and when to use it. Gets embedded for semantic search (max 1024 chars)content(required): Full SKILL.md body - markdown instructions, steps, examples (max 100KB)license(optional): License identifier (e.g., 'MIT', 'Apache-2.0')compatibility(optional): Environment requirements (e.g., 'Requires Python 3.14+ and uv')allowed_tools(optional): Tool restrictions (e.g.,['Bash(python:*)', 'Read', 'WebFetch'])metadata(optional): Custom key-value pairs (author, version, mcp-server, etc.)tags(optional): Categorization tags (max 10)importance(optional): Importance 1-10 (default: 7)project_id(optional): Link to project
Returns:
Complete Skill with generated ID and timestamps
Example:
skill = execute_forgetful_tool(
"create_skill",
{
"name": "code-review",
"description": "Systematic code review process for pull requests",
"content": "# Code Review\n\n## Steps\n1. Check for breaking changes...",
"tags": ["development", "review", "quality"],
"importance": 8
}
)list_skills
List skills with optional filtering.
Parameters:
project_id(optional): Filter by projecttags(optional): Filter by tags (OR logic - skills with ANY of these tags)importance_threshold(optional): Minimum importance level (1-10)
Returns:
List of SkillSummary (excludes full content)
Example:
skills = execute_forgetful_tool(
"list_skills",
{"tags": ["deployment"], "importance_threshold": 7}
)get_skill
Retrieve complete skill by ID.
Parameters:
skill_id(required): Skill ID
Returns:
Complete skill with full content and metadata
Example:
skill = execute_forgetful_tool("get_skill", {"skill_id": 5})update_skill
Update skill (PATCH semantics).
Parameters:
skill_id(required): Skill IDname,description,content,license,compatibility,allowed_tools,metadata,tags,importance,project_id(all optional)
Returns:
Updated skill object
Example:
execute_forgetful_tool(
"update_skill",
{
"skill_id": 5,
"content": "# Updated Code Review\n\n## Steps\n1. Run linter first...",
"importance": 9
}
)delete_skill
Delete skill (cascades memory and artifact associations).
Parameters:
skill_id(required): Skill ID
Returns:
Confirmation of deletion
Example:
execute_forgetful_tool("delete_skill", {"skill_id": 5})search_skills
Semantic search across skills by description similarity.
Parameters:
query(required): Search query string (semantic, not keyword-only)k(optional): Number of results (default: 5)project_id(optional): Filter by project
Returns:
List of SkillSummary ranked by relevance
Example:
results = execute_forgetful_tool(
"search_skills",
{"query": "how to deploy to production", "k": 3}
)import_skill
Import a skill from Agent Skills markdown format (SKILL.md).
Parameters:
skill_md_content(required): Raw SKILL.md content with YAML frontmatterproject_id(optional): Project associationimportance(optional): Importance level (default: 7)
Scalar frontmatter values may contain unquoted colons (for example Keywords: in a description); the importer quotes them before parsing.
YAML references (*name referring to an &name anchor) are not supported in frontmatter.
Write the referenced values directly instead. Quoted strings such as "*person" and Markdown
asterisks in the body remain valid.
Returns:
Created Skill with generated ID
Example:
skill_md = """---
name: code-review
description: Systematic code review
license: MIT
---
# Code Review
## Steps
1. Check for...
"""
skill = execute_forgetful_tool(
"import_skill",
{
"skill_md_content": skill_md,
"project_id": 3,
"importance": 8
}
)export_skill
Export a skill to Agent Skills markdown format (SKILL.md).
Parameters:
skill_id(required): Skill ID to export
Returns:
Formatted SKILL.md string with YAML frontmatter
Example:
skill_md = execute_forgetful_tool("export_skill", {"skill_id": 5})
# Returns: "---\nname: code-review\ndescription: ...\n---\n\n# Code Review\n..."link_skill_to_memory
Link a skill to a memory (bidirectional association).
Parameters:
skill_id(required): Skill IDmemory_id(required): Memory ID
Returns:
Confirmation dict
Example:
execute_forgetful_tool(
"link_skill_to_memory",
{"skill_id": 5, "memory_id": 123}
)unlink_skill_from_memory
Remove association between a skill and a memory.
Parameters:
skill_id(required): Skill IDmemory_id(required): Memory ID
Returns:
Confirmation dict
Example:
execute_forgetful_tool(
"unlink_skill_from_memory",
{"skill_id": 5, "memory_id": 123}
)Entity Tools
Track real-world entities (people, organizations, teams, devices) and build knowledge graphs through relationships.
Entity Types
Organization- Companies, institutionsIndividual- People, team membersTeam- Groups within organizationsDevice- Servers, infrastructureOther- Custom entity types (requirescustom_typefield)
Relationship Types
works_for- Employment relationshipsmember_of- Team membershipowns- Ownershipreports_to- Reporting structurecollaborates_with- CollaborationCustom types - Define your own
Entity CRUD Operations
create_entity
Create an entity representing a real-world thing.
Parameters:
name(required): Entity nameentity_type(required): Type (Organization,Individual,Team,Device,System,Other)description(optional): Entity descriptiontags(optional): Categorization tagsaka(optional): Alternative names/aliases (max 10). Searchable viasearch_entities.project_id(optional): Link to projectcustom_type(optional): Custom type name (required if entity_type isOther)metadata(optional): Additional JSON metadata
Returns:
Flat entity fields after create, with
plugin_warningsonly when nonempty when an Entity Plugin is registered. Before-save errors:WRITE_PLUGIN_REJECTEDorWRITE_PLUGIN_UNAVAILABLE.
Example:
# Create a person with aliases
person = execute_forgetful_tool(
"create_entity",
{
"name": "Sarah Chen",
"entity_type": "Individual",
"description": "Senior Backend Engineer, specializes in distributed systems",
"tags": ["engineering", "backend", "distributed-systems"],
"aka": ["Sarah", "S.C."], # Alternative names for search
"metadata": {"start_date": "2024-03-15", "location": "San Francisco"}
}
)
# Returns: {"entity_id": 42, "name": "Sarah Chen", "aka": ["Sarah", "S.C."], ...}
# Create an organization with stock ticker alias
org = execute_forgetful_tool(
"create_entity",
{
"name": "TechFlow Systems",
"entity_type": "Organization",
"description": "SaaS platform for workflow automation",
"tags": ["company", "saas", "b2b"],
"aka": ["TechFlow", "TFS"] # Can search by "TFS" to find this
}
)
# Returns: {"entity_id": 43, ...}
# Create infrastructure
server = execute_forgetful_tool(
"create_entity",
{
"name": "Cache Server 01",
"entity_type": "Device",
"description": "Redis cluster primary node - production",
"tags": ["infrastructure", "cache", "production", "redis"],
"aka": ["redis-primary", "cache-01"],
"metadata": {"ip": "10.0.1.50", "region": "us-west-2"}
}
)
# Returns: {"entity_id": 44, ...}list_entities
List entities with optional filtering.
Parameters:
entity_type(optional): Filter by typetags(optional): Filter by tagsproject_id(optional): Filter by project
Returns:
List of matching entities
Example:
# Find all team members
team = execute_forgetful_tool(
"list_entities",
{"entity_type": "Individual", "tags": ["engineering"]}
)search_entities
Search entities by name or alternative names (aka). Case-insensitive text matching.
Parameters:
query(required): Search term (matches name or any aka, partial match supported)entity_type(optional): Filter by entity typetags(optional): Filter by tagslimit(optional): Maximum results (1-100, default 20)
Returns:
List of entities matching the search term (via name or aka)
Example:
# Find entities with "Chen" in the name
results = execute_forgetful_tool(
"search_entities",
{"query": "Chen"}
)
# Returns: [{"entity_id": 42, "name": "Sarah Chen", "aka": ["Sarah", "S.C."], ...}, ...]
# Search by alias - finds "TechFlow Systems" via its "TFS" alias
results = execute_forgetful_tool(
"search_entities",
{"query": "TFS"}
)
# Returns: [{"entity_id": 43, "name": "TechFlow Systems", "aka": ["TechFlow", "TFS"], ...}]get_entity
Retrieve complete entity details by ID.
Parameters:
entity_id(required): Entity ID
Returns:
Complete entity object
Example:
entity = execute_forgetful_tool("get_entity", {"entity_id": 42})update_entity
Update entity (PATCH semantics - only provided fields changed).
Parameters:
entity_id(required): Entity IDname,description,tags,aka,metadata(all optional)aka: Replaces existing aliases. Empty list[]clears all aliases.
Returns:
Updated entity object
Example:
# Update description and add aliases
execute_forgetful_tool(
"update_entity",
{
"entity_id": 42,
"description": "Principal Backend Engineer, Tech Lead for distributed systems",
"aka": ["Sarah", "S.C.", "Chen"], # Replaces existing aka list
"metadata": {"promotion_date": "2025-01-01", "title": "Principal Engineer"}
}
)delete_entity
Delete entity (cascade removes memory links and relationships).
Parameters:
entity_id(required): Entity ID
Returns:
Confirmation of deletion
Example:
execute_forgetful_tool("delete_entity", {"entity_id": 42})Entity-Memory Linking
link_entity_to_memory
Link an entity to a memory (establishes reference relationship).
Parameters:
entity_id(required): Entity IDmemory_id(required): Memory ID
Returns:
Confirmation of link
Example:
# Link Sarah to a memory about an architecture decision she made
execute_forgetful_tool(
"link_entity_to_memory",
{
"entity_id": 42, # Sarah Chen
"memory_id": 156 # "API rate limiting decision"
}
)unlink_entity_from_memory
Remove entity-memory link.
Parameters:
entity_id(required): Entity IDmemory_id(required): Memory ID
Returns:
Confirmation of unlink
Example:
execute_forgetful_tool(
"unlink_entity_from_memory",
{"entity_id": 42, "memory_id": 156}
)get_memory_entities
Get every entity directly linked to a memory (reverse of get_entity_memories).
Parameters:
memory_id(required): Memory ID
Returns:
entity_ids: Linked entity IDs, ordered by IDcount: Number of linked entitiesentities:{id, name, entity_type}objects in the same order asentity_idsThe full set is always returned (no pagination). An existing memory with no links returns empty lists; a missing or inaccessible memory raises a not found error.
Example:
execute_forgetful_tool("get_memory_entities", {"memory_id": 156})
# Returns: {"entity_ids": [42], "count": 1, "entities": [{"id": 42, "name": "Sarah Chen", "entity_type": "Individual"}]}Entity-Project Linking
link_entity_to_project
Link an entity to a project for organizational grouping.
Parameters:
entity_id(required): Entity IDproject_id(required): Project ID
Returns:
{"success": true}on success
Example:
# Link Sarah to the API Gateway project
execute_forgetful_tool(
"link_entity_to_project",
{
"entity_id": 42, # Sarah Chen
"project_id": 12 # API Gateway project
}
)unlink_entity_from_project
Remove entity-project link.
Parameters:
entity_id(required): Entity IDproject_id(required): Project ID
Returns:
{"success": true}if unlinked,{"success": false}if link didn't exist
Example:
execute_forgetful_tool(
"unlink_entity_from_project",
{"entity_id": 42, "project_id": 12}
)Entity Relationships (Knowledge Graph)
Build directional knowledge graphs showing how entities relate to each other.
create_entity_relationship
Create a typed relationship between two entities.
Parameters:
from_entity_id(required): Source entity IDto_entity_id(required): Target entity IDrelationship_type(required): Relationship type (see list above, or custom)strength(optional): Relationship strength 0.0-1.0 (default: 1.0)confidence(optional): Confidence level 0.0-1.0 (default: 1.0)metadata(optional): Additional JSON metadata
Returns:
Created relationship with
relationship_id
Example:
# Sarah works for TechFlow
relationship = execute_forgetful_tool(
"create_entity_relationship",
{
"from_entity_id": 42, # Sarah Chen
"to_entity_id": 43, # TechFlow Systems
"relationship_type": "works_for",
"strength": 1.0,
"metadata": {
"role": "Principal Backend Engineer",
"department": "Platform Engineering",
"start_date": "2024-03-15"
}
}
)
# Returns: {"relationship_id": 12, ...}
# Server owned by TechFlow
execute_forgetful_tool(
"create_entity_relationship",
{
"from_entity_id": 43, # TechFlow Systems
"to_entity_id": 44, # Cache Server 01
"relationship_type": "owns",
"metadata": {"purchased": "2024-06-01", "cost_center": "engineering"}
}
)get_entity_relationships
Get relationships for an entity with optional filtering.
Parameters:
entity_id(required): Entity IDrelationship_type(optional): Filter by relationship typedirection(optional):outgoing,incoming, orboth(default:both)
Returns:
List of relationships
Example:
# Get all of Sarah's relationships
relationships = execute_forgetful_tool(
"get_entity_relationships",
{"entity_id": 42}
)
# Get only employment relationships
employment = execute_forgetful_tool(
"get_entity_relationships",
{
"entity_id": 42,
"relationship_type": "works_for",
"direction": "outgoing"
}
)update_entity_relationship
Update entity relationship (PATCH semantics).
Parameters:
relationship_id(required): Relationship IDrelationship_type,strength,confidence,metadata(all optional)
Returns:
Updated relationship object
Example:
# Update Sarah's role after promotion
execute_forgetful_tool(
"update_entity_relationship",
{
"relationship_id": 12,
"metadata": {
"role": "Engineering Director",
"department": "Platform Engineering",
"promotion_date": "2025-01-01"
}
}
)delete_entity_relationship
Delete entity relationship (removes knowledge graph edge).
Parameters:
relationship_id(required): Relationship ID
Returns:
Confirmation of deletion
Example:
execute_forgetful_tool("delete_entity_relationship", {"relationship_id": 12})Plan Tools
Create and manage plans within projects. Plans serve as containers for organizing tasks toward a specific goal.
Plan Statuses
draft,active,completed,archived
create_plan
Create a new plan within a project.
Parameters:
title(required): Plan titleproject_id(required): Parent project IDgoal(optional): High-level goal for the plancontext(optional): Additional context or backgroundstatus(optional): Plan status (default:draft)external_ref(optional): Opaque reference unique across the authenticated user's plans
Returns:
Created plan with
idandexternal_ref(null when not supplied)
Example:
plan = execute_forgetful_tool(
"create_plan",
{
"title": "Migrate Authentication to OAuth2",
"project_id": 12,
"goal": "Replace legacy session-based auth with OAuth2 + JWT",
"context": "Current auth system has scaling issues and no SSO support",
"status": "draft"
}
)
# Returns: {"id": 5, "title": "Migrate Authentication to OAuth2", ...}update_plan
Update plan metadata (PATCH semantics - only provided fields changed).
Parameters:
plan_id(required): Plan IDtitle(optional): Updated titlegoal(optional): Updated goalcontext(optional): Updated contextstatus(optional): Updated statusexternal_ref(optional): Replacement reference; omitted or null leaves it unchanged
Returns:
Updated plan object
Example:
# Move plan from draft to active
execute_forgetful_tool(
"update_plan",
{
"plan_id": 5,
"status": "active",
"goal": "Replace legacy auth with OAuth2 + JWT by end of Q2"
}
)get_plan
Retrieve complete plan details by ID.
Parameters:
plan_id(required): Plan ID
Returns:
Complete plan object with all fields
Errors:
Raises an error (not
null) whenplan_iddoes not exist or is not visible to the caller
Example:
plan = execute_forgetful_tool("get_plan", {"plan_id": 5})list_plans
List plans with optional filtering.
Parameters:
project_id(optional): Filter by projectstatus(optional): Filter by statusexternal_ref(optional): Exact reference lookup within your plans
Returns:
Object with
planssummaries (includingexternal_ref) andtotal_count
Example:
# Get all active plans for a project
active_plans = execute_forgetful_tool(
"list_plans",
{"project_id": 12, "status": "active"}
)External reference rules and conflict recovery
References are opaque strings: surrounding whitespace is trimmed on create, update, and lookup.
The trimmed value must contain 1–255 characters. Matching is case-sensitive; all other characters
are preserved. For example, github:ScottRBK/factory#42 and github:scottrbk/factory#42 differ.
No GitHub parsing or synchronization is performed. Callers must manage changes to their identifiers,
such as repository renames, or choose stable identifiers.
A reference is unique across all of your projects and plan statuses, including completed and
archived plans. Different users can use the same reference. Multiple plans without a reference
are allowed. Existing plans keep a null reference after migration; source_url remains independent
provenance and is never used to backfill or enforce uniqueness.
Duplicate creates or updates fail with a conflict error. The database enforces uniqueness even for concurrent requests, and a rejected update leaves the entire plan unchanged. Recover the existing plan by looking up the reference without project or status filters:
result = execute_forgetful_tool(
"list_plans", {"external_ref": "github:ScottRBK/factory#42"}
)
# result["plans"] contains zero or one summary; its "id" can be passed to get_plan.Omitting external_ref or supplying null during an update leaves it unchanged. There is no clear
operation: empty/whitespace-only strings are rejected. Replacing the reference or deleting the
plan releases the old value for reuse. Completing or archiving a plan retains its reference.
A unique reference prevents duplicate plans; it does not claim tasks or prevent duplicate agents.
Generic CLI calls accept the same arguments:
forgetful call create_plan --args '{
"title": "Factory issue", "project_id": 12, "external_ref": "github:ScottRBK/factory#42"
}'
forgetful call list_plans --args '{"external_ref":"github:ScottRBK/factory#42"}'Task Tools
Manage tasks within plans, including acceptance criteria, dependencies, and agent assignment with optimistic locking.
Task States
Tasks follow a lifecycle defined by TaskState (see app/models/plan_models.py):
todo(default) — not starteddoing— in progresswaiting— blocked / awaiting external inputdone— completedcancelled— will not be completed
Valid transitions (enforced by VALID_TASK_TRANSITIONS):
| From → To | Allowed |
|---|---|
todo → | doing, waiting, cancelled |
doing → | done, waiting, todo, cancelled |
waiting → | todo, doing, cancelled |
done → | todo (reopen only) |
cancelled → | todo (reinstate only) |
Any other transition is rejected by transition_task with a validation error.
Task Priorities
P0- CriticalP1- HighP2- Medium (default)P3- Low
create_task
Create a task within a plan.
Parameters:
title(required): Task titleplan_id(required): Parent plan IDdescription(optional): Detailed task descriptionpriority(optional): Task priority (default:P2)assigned_agent(optional): Agent identifier to assign the task tocriteria(optional): Inline list of acceptance criterion descriptionsdependency_ids(optional): List of task IDs this task depends on
Returns:
Created task with
task_id
Example:
task = execute_forgetful_tool(
"create_task",
{
"title": "Implement JWT token generation endpoint",
"plan_id": 5,
"description": "Create /auth/token endpoint that issues JWT tokens with refresh token rotation",
"priority": "P1",
"assigned_agent": "backend-agent",
"criteria": [
"Endpoint returns access + refresh token pair",
"Access tokens expire after 15 minutes",
"Refresh tokens support rotation"
],
"dependency_ids": [10, 12]
}
)
# Returns: {"task_id": 25, "title": "Implement JWT token generation endpoint", ...}update_task
Update task metadata (not state - use transition_task for state changes).
Parameters:
task_id(required): Task IDtitle(optional): Updated titledescription(optional): Updated descriptionpriority(optional): Updated priority
Returns:
Updated task object
Example:
execute_forgetful_tool(
"update_task",
{
"task_id": 25,
"priority": "P0",
"description": "Create /auth/token endpoint - now critical path for launch"
}
)get_task
Get task with its acceptance criteria and dependency IDs.
Parameters:
task_id(required): Task ID
Returns:
Complete task object including criteria and dependency_ids
Errors:
Raises an error (not
null) whentask_iddoes not exist or is not visible to the caller
Example:
task = execute_forgetful_tool("get_task", {"task_id": 25})
# Returns: {"task_id": 25, "criteria": [...], "dependency_ids": [10, 12], ...}query_tasks
Query tasks within a plan with optional filtering.
Parameters:
plan_id(required): Plan IDstate(optional): Filter by task statepriority(optional): Filter by priorityassigned_agent(optional): Filter by assigned agent
Returns:
List of matching tasks
Example:
# Find all todo P0/P1 tasks assigned to an agent
critical_tasks = execute_forgetful_tool(
"query_tasks",
{
"plan_id": 5,
"state": "todo",
"priority": "P1",
"assigned_agent": "backend-agent"
}
)claim_task
Claim a task for an agent. Uses optimistic locking to prevent concurrent claims.
Parameters:
task_id(required): Task IDagent_id(required): Agent identifier claiming the taskversion(required): Current task version (for optimistic locking)
Returns:
Updated task object with new version
Example:
# First get the task to obtain current version
task = execute_forgetful_tool("get_task", {"task_id": 25})
# Claim with version check
claimed = execute_forgetful_tool(
"claim_task",
{
"task_id": 25,
"agent_id": "backend-agent-01",
"version": task["version"]
}
)transition_task
Transition a task to a new state. Uses optimistic locking to prevent conflicting state changes.
Parameters:
task_id(required): Task IDstate(required): Target stateversion(required): Current task version (for optimistic locking)
Returns:
Updated task object with new state and version
Example:
# Move task from todo to doing
task = execute_forgetful_tool("get_task", {"task_id": 25})
execute_forgetful_tool(
"transition_task",
{
"task_id": 25,
"state": "doing",
"version": task["version"]
}
)
# Later, mark as done
task = execute_forgetful_tool("get_task", {"task_id": 25})
execute_forgetful_tool(
"transition_task",
{
"task_id": 25,
"state": "done",
"version": task["version"]
}
)add_criterion
Add an acceptance criterion to a task.
Parameters:
task_id(required): Task IDdescription(required): Criterion description
Returns:
Created criterion with
criterion_id
Example:
criterion = execute_forgetful_tool(
"add_criterion",
{
"task_id": 25,
"description": "Token endpoint returns 401 for invalid credentials"
}
)
# Returns: {"criterion_id": 78, "description": "Token endpoint returns 401 for invalid credentials", ...}verify_criterion
Mark an acceptance criterion as met or unmet.
Parameters:
criterion_id(required): Criterion IDmet(required): Whether the criterion is met (true/false)
Returns:
Updated criterion object
Example:
# Mark criterion as satisfied
execute_forgetful_tool(
"verify_criterion",
{"criterion_id": 78, "met": true}
)delete_criterion
Delete an acceptance criterion from a task.
Parameters:
criterion_id(required): Criterion ID
Returns:
Confirmation of deletion
Example:
execute_forgetful_tool("delete_criterion", {"criterion_id": 78})add_dependency
Add a dependency between tasks. The dependent task cannot proceed until the dependency is completed.
Parameters:
task_id(required): Task that depends on anotherdepends_on_task_id(required): Task that must be completed first
Returns:
Confirmation of dependency creation
Example:
# Task 25 depends on task 20 being completed first
execute_forgetful_tool(
"add_dependency",
{
"task_id": 25,
"depends_on_task_id": 20
}
)remove_dependency
Remove a dependency between tasks.
Parameters:
task_id(required): Task with the dependencydepends_on_task_id(required): Task to remove as dependency
Returns:
Confirmation of dependency removal
Example:
execute_forgetful_tool(
"remove_dependency",
{
"task_id": 25,
"depends_on_task_id": 20
}
)Cross-Category Workflows
Real-world scenarios demonstrating how tools work together.
Scenario 1: Documenting a Complete Feature
Context: You've implemented a new authentication system and want to capture all knowledge.
# 1. Create project
project = execute_forgetful_tool(
"create_project",
{
"name": "Authentication System V2",
"project_type": "development",
"status": "active"
}
)
project_id = project["id"]
# 2. Store architecture decision document
adr = execute_forgetful_tool(
"create_document",
{
"title": "ADR-001: OAuth2 + JWT Authentication Strategy",
"content": "[... full 3000-word architecture decision record ...]",
"document_type": "markdown",
"tags": ["adr", "authentication", "oauth2", "jwt"],
"project_id": project_id
}
)
# 3. Extract key decision as atomic memory
decision_memory = execute_forgetful_tool(
"create_memory",
{
"title": "Auth strategy: OAuth2 for third-party + JWT for sessions",
"content": "Use OAuth2 for social login and JWT for internal sessions.",
"context": "Capturing the authentication architecture decision",
"keywords": ["authentication", "oauth2", "jwt"],
"tags": ["authentication", "decision"],
"importance": 10,
"project_ids": [project_id],
"document_ids": [adr["id"]]
}
)
# 4. Store reusable JWT middleware
middleware = execute_forgetful_tool(
"create_code_artifact",
{
"title": "JWT Authentication Middleware",
"description": "FastAPI middleware that validates JWT bearer tokens",
"code": '''
from fastapi import Request, HTTPException
from jose import jwt, JWTError
async def verify_jwt(request: Request):
token = request.headers.get("Authorization", "").replace("Bearer ", "")
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
return payload
except JWTError:
raise HTTPException(status_code=401, detail="Invalid token")
''',
"language": "python",
"tags": ["authentication", "jwt", "middleware"],
"project_id": project_id
}
)
# 5. Create entity for the engineer who implemented it
engineer = execute_forgetful_tool(
"create_entity",
{
"name": "Alex Kim",
"entity_type": "Individual",
"notes": "Senior Full-Stack Engineer",
"tags": ["engineering", "fullstack"],
"aka": ["Alex", "A.K."]
}
)
# 6. Link engineer to the decision memory
execute_forgetful_tool(
"link_entity_to_memory",
{
"entity_id": engineer["id"],
"memory_id": decision_memory["id"]
}
)
# 7. Later, query everything about auth
results = execute_forgetful_tool(
"query_memory",
{
"query": "authentication implementation",
"query_context": "Reviewing the authentication implementation",
"project_ids": [project_id]
}
)
# Returns decision_memory + auto-linked memories + linked document + code artifact + entityScenario 2: New Team Member Onboarding
Context: A new engineer joins, you want to capture their information and link relevant knowledge.
# 1. Create entity for new engineer
new_hire = execute_forgetful_tool(
"create_entity",
{
"name": "Jordan Taylor",
"entity_type": "Individual",
"notes": "Backend Engineer - Payments Team",
"tags": ["engineering", "backend", "payments"],
"aka": ["Jordan", "J.T."]
}
)
# 2. Get company entity (assuming it exists) - can search by name or alias
company = execute_forgetful_tool(
"search_entities",
{"query": "TechFlow"}
)
company_id = company["entities"][0]["id"]
# 3. Create employment relationship
execute_forgetful_tool(
"create_entity_relationship",
{
"from_entity_id": new_hire["id"],
"to_entity_id": company_id,
"relationship_type": "works_for",
"metadata": {
"role": "Backend Engineer II",
"department": "Payments",
"team": "Checkout"
}
}
)
# 4. Create onboarding memory
onboarding_memory = execute_forgetful_tool(
"create_memory",
{
"title": "Jordan Taylor joined - Payments team focus areas",
"content": "Jordan will focus on payment integrations and PCI compliance.",
"context": "New hire onboarding for the payments team",
"keywords": ["jordan", "payments", "stripe", "pci"],
"tags": ["team", "onboarding", "payments"],
"importance": 7
}
)
# 5. Link new hire to onboarding memory
execute_forgetful_tool(
"link_entity_to_memory",
{
"entity_id": new_hire["id"],
"memory_id": onboarding_memory["id"]
}
)
# 6. Query existing payment system memories and link relevant ones
payment_memories = execute_forgetful_tool(
"query_memory",
{
"query": "payment gateway stripe paypal",
"query_context": "Finding onboarding material for the payments team",
"k": 5
}
)
for memory in payment_memories["primary_memories"]:
execute_forgetful_tool(
"link_entity_to_memory",
{
"entity_id": new_hire["id"],
"memory_id": memory["id"]
}
)Scenario 3: Infrastructure Incident Documentation
Context: Redis server failed, you resolved it and want to document for future reference.
# 1. Get the server entity (can also search by alias like "redis-primary")
server = execute_forgetful_tool(
"search_entities",
{"query": "Cache Server 01"}
)
server_id = server["entities"][0]["id"]
# 2. Create incident memory
incident = execute_forgetful_tool(
"create_memory",
{
"title": "Redis failover incident - memory exhaustion",
"content": "Cache Server 01 ran out of memory due to unbounded key growth. Implemented maxmemory-policy=allkeys-lru and set maxmemory=4gb. Also added monitoring alerts at 80% memory usage.",
"importance": 9,
"tags": ["incident", "redis", "infrastructure", "production"],
"context": "Production incident on 2025-01-18, resolved in 45 minutes",
"keywords": ["redis", "memory", "failover", "monitoring"]
}
)
# 3. Link incident to server
execute_forgetful_tool(
"link_entity_to_memory",
{
"entity_id": server_id,
"memory_id": incident["id"]
}
)
# 4. Update server metadata with fix
execute_forgetful_tool(
"update_entity",
{
"entity_id": server_id,
"notes": "4 GB maxmemory, allkeys-lru policy, monitoring enabled"
}
)
# 5. Create code artifact for monitoring script
monitoring_script = execute_forgetful_tool(
"create_code_artifact",
{
"title": "Redis Memory Monitoring Script",
"code": '''
import redis
import os
def check_redis_memory(threshold=0.8):
r = redis.Redis(host='cache-server-01', port=6379)
info = r.info('memory')
used = info['used_memory']
max_mem = info['maxmemory']
if max_mem > 0 and (used / max_mem) > threshold:
send_alert(f"Redis memory at {(used/max_mem)*100:.1f}%")
''',
"language": "python",
"tags": ["monitoring", "redis", "alerting"],
"description": "Alert when Redis memory usage exceeds threshold"
}
)
# 6. Link monitoring script to incident memory
execute_forgetful_tool(
"create_memory",
{
"title": "Implemented Redis memory monitoring",
"content": "Added an alert at 80% memory usage to prevent future incidents.",
"context": "Follow-up action from the Redis memory exhaustion incident",
"keywords": ["redis", "memory", "monitoring", "alert"],
"tags": ["monitoring", "prevention", "redis"],
"importance": 8,
"code_artifact_ids": [monitoring_script["id"]]
}
)Scenario 4: Research and Decision Making
Context: Researching database options, documenting findings, and making a decision.
# 1. Create research project
research_project = execute_forgetful_tool(
"create_project",
{
"name": "Database Technology Evaluation 2025",
"project_type": "learning",
"status": "active"
}
)
project_id = research_project["id"]
# 2. Create comprehensive research document
research_doc = execute_forgetful_tool(
"create_document",
{
"title": "Vector Database Comparison: pgvector vs Qdrant vs Weaviate",
"description": "Comparison of vector database options",
"content": "[... 5000-word detailed comparison of features, performance, costs ...]",
"document_type": "markdown",
"tags": ["research", "database", "vector-db", "embeddings"],
"project_id": project_id
}
)
# 3. Extract atomic insights as memories
insight1 = execute_forgetful_tool(
"create_memory",
{
"title": "pgvector: Best for existing PostgreSQL setups",
"content": "pgvector avoids a separate vector database when PostgreSQL is in use.",
"context": "Capturing a conclusion from the vector database comparison",
"keywords": ["pgvector", "postgresql", "vector-database"],
"tags": ["database", "pgvector", "vectors"],
"importance": 8,
"project_ids": [project_id],
"document_ids": [research_doc["id"]]
}
)
insight2 = execute_forgetful_tool(
"create_memory",
{
"title": "Qdrant: Best performance for large-scale vector search",
"content": "Qdrant performs well at large scale but requires a separate service.",
"context": "Capturing a conclusion from the vector database comparison",
"keywords": ["qdrant", "vector-database", "performance"],
"tags": ["database", "qdrant", "vectors"],
"importance": 8,
"project_ids": [project_id],
"document_ids": [research_doc["id"]]
}
)
# 4. Make decision and create decision memory
decision = execute_forgetful_tool(
"create_memory",
{
"title": "Decision: pgvector for Forgetful project",
"content": "Selected pgvector because Forgetful already uses PostgreSQL.",
"context": "Final decision from the vector database evaluation",
"keywords": ["pgvector", "postgresql", "database-decision"],
"tags": ["decision", "database", "pgvector", "forgetful"],
"importance": 10,
"project_ids": [project_id],
"document_ids": [research_doc["id"]]
}
)
# 5. Manually link related insights to decision
execute_forgetful_tool(
"link_memories",
{"memory_id": decision["id"], "related_ids": [insight1["id"]]}
)
execute_forgetful_tool(
"link_memories",
{"memory_id": decision["id"], "related_ids": [insight2["id"]]}
)
# 6. Mark project as completed
execute_forgetful_tool(
"update_project",
{
"project_id": project_id,
"status": "completed",
"notes": "Selected pgvector; evaluation completed 2025-01-15"
}
)Best Practices
Memory Creation
One concept per memory - Follow atomic memory principle
Title it first - If you can't easily title it, break it down further
High importance for reusable knowledge - Use 8-10 for architectural decisions and patterns
Always provide context - Future you will thank past you
Tag consistently - Develop a tagging taxonomy for your knowledge domain
Project Organization
Scope queries to projects - Dramatically improves search relevance
Use project types consistently - Helps with filtering and organization
Archive completed projects - Don't delete - preserve knowledge with context
Link related projects - Create memories that reference multiple projects
Entity & Knowledge Graph
Entities for concrete things, memories for concepts - "Sarah Chen" is an entity, "Sarah's API design preference" is a memory
Build relationships as you learn - Don't wait to build complete graphs
Use metadata liberally - Capture temporal and contextual information
Link entities to relevant memories - Creates rich context for queries
Code Artifacts & Documents
Code artifacts for reusable snippets (<200 lines) - Utilities, patterns, configs
Documents for detailed content (>400 words) - ADRs, research, specifications
Always extract atomic memories - Documents are storage, memories are searchable knowledge
Link atoms to documents - Preserve connection to detailed source
Search & Retrieval
Query early and often - Check existing knowledge before creating duplicates
Use natural language - Semantic search works better than keyword matching
Filter by project for focus - Especially in multi-project environments
Check auto-linked memories - Often find related context you didn't know existed
Token Budget & Performance
Forgetful protects your LLM context window with configurable token budgets:
Default: 8,000 tokens per query result
Max 20 memories returned per query
Primary result order: Importance (high first); ties keep search order, even without truncation
Graceful truncation: If over budget, lower-priority memories excluded
Configure via environment variables:
MEMORY_TOKEN_BUDGET=8000
MEMORY_MAX_MEMORIES=20Additional Resources
Configuration Guide - All environment variables
Connectivity Guide - MCP client setup
Search Documentation - Embedding pipeline details
MCP Protocol - MCP specification
Last Updated: 2025-01-22 Forgetful Version: 0.1.x
Plan policy warnings
create_plan, update_plan and transition_task keep their existing flat success
shape, adding plugin_warnings only when nonempty. get_plan, list_plans and
Task reads remain unchanged. An administrator's Plan Plugin can return direct
PLAN_PLUGIN_REJECTED, PLAN_PLUGIN_UNAVAILABLE or PLAN_PLUGIN_STATE_CHANGED
errors. Both generic CLI call modes use the same contracts.
A successful task transition may include plan_auto_completion_rejected or
plan_auto_completion_unavailable: the task committed, but that attempt did not
complete its parent plan. Do not repeat the task mutation merely to retry parent
policy. Unrelated errors and request cancellation can still occur after commit;
read current state first. automatic is administrator context only, never a tool
argument. No delete_plan or delete_task MCP tool is introduced; those remain
REST operations. See Plan Plugin configuration.
472 files · 452 not served here
- .dockerignore (not served here)
- .github/ISSUE_TEMPLATE/bug_report.yml (not served here)
- .github/ISSUE_TEMPLATE/config.yml (not served here)
- .github/ISSUE_TEMPLATE/feature_request.yml (not served here)
- .github/PULL_REQUEST_TEMPLATE.md (not served here)
- .github/dependabot.yml (not served here)
- .github/workflows/build.yml (not served here)
- .github/workflows/ci.yml (not served here)
- .github/workflows/e2e.yml (not served here)
- .github/workflows/nix-cache.yml (not served here)
- .github/workflows/publish.yml (not served here)
- .gitignore (not served here)
- .python-version (not served here)
- AGENTS.md
- ATTRIBUTION.md
- AUTOGINEER-RUNS.md
- CLAUDE.md
- CODE_OF_CONDUCT.md
- CONTRIBUTING.md
- LICENCE.md
- README.md
- SECURITY.md
- _typos.toml (not served here)
- alembic.ini (not served here)
- alembic/README (not served here)
- alembic/_db_helpers/__init__.py (not served here)
- alembic/_db_helpers/db_postgres_impl.py (not served here)
- alembic/_db_helpers/db_sqlite_impl.py (not served here)
- alembic/env.py (not served here)
- alembic/script.py.mako (not served here)
- alembic/versions/0c7b964dd1e7_initial_schema_with_entity_many_to_many.py (not served here)
- alembic/versions/20251216143413_add_aka_to_entities.py (not served here)
- alembic/versions/20260106_add_activity_log_table.py (not served here)
- alembic/versions/20260106_add_provenance_tracking_to_memories.py (not served here)
- alembic/versions/20260312_add_plans_tasks_criteria_dependencies.py (not served here)
- alembic/versions/20260315_add_files_table.py (not served here)
- alembic/versions/20260321_add_skills_table.py (not served here)
- alembic/versions/20260408_add_provenance_to_all_object_types.py (not served here)
- alembic/versions/20260704_add_memory_usage_tracking.py (not served here)
- alembic/versions/20260822_add_project_last_encoding_point.py (not served here)
- alembic/versions/20261008_add_plan_external_ref.py (not served here)
- alembic/versions/20261103_add_memory_search_tsv.py (not served here)
- app/__init__.py (not served here)
- app/bootstrap.py (not served here)
- app/config/__init__.py (not served here)
- app/config/auth.py (not served here)
- app/config/logging_config.py (not served here)
- app/config/plan_plugin.py (not served here)
- app/config/settings.py (not served here)
- app/config/write_plugin.py (not served here)
- app/events/__init__.py (not served here)
- app/events/event_bus.py (not served here)
- app/exceptions.py (not served here)
- app/middleware/__init__.py (not served here)
- app/middleware/auth.py (not served here)
- app/middleware/logging_middleware.py (not served here)
- app/models/__init__.py (not served here)
- app/models/activity_models.py (not served here)
- app/models/code_artifact_models.py (not served here)
- app/models/document_models.py (not served here)
- app/models/entity_models.py (not served here)
- app/models/file_models.py (not served here)
- app/models/graph_models.py (not served here)
- app/models/memory_models.py (not served here)
- app/models/models.py (not served here)
- app/models/plan_models.py (not served here)
- app/models/plan_plugin_models.py (not served here)
- app/models/project_models.py (not served here)
- app/models/skill_models.py (not served here)
- app/models/tool_registry_models.py (not served here)
- app/models/user_models.py (not served here)
- app/models/write_plugin_models.py (not served here)
- app/protocols/__init__.py (not served here)
- app/protocols/activity_protocol.py (not served here)
- app/protocols/backup_protocol.py (not served here)
- app/protocols/code_artifact_protocol.py (not served here)
- app/protocols/document_protocol.py (not served here)
- app/protocols/embedding_protocol.py (not served here)
- app/protocols/entity_protocol.py (not served here)
- app/protocols/executor.py (not served here)
- app/protocols/file_protocol.py (not served here)
- app/protocols/memory_protocol.py (not served here)
- app/protocols/plan_plugin_protocol.py (not served here)
- app/protocols/plan_protocol.py (not served here)
- app/protocols/project_protocol.py (not served here)
- app/protocols/skill_protocol.py (not served here)
- app/protocols/task_protocol.py (not served here)
- app/protocols/user_protocol.py (not served here)
- app/protocols/write_plugin_protocol.py (not served here)
- app/repositories/__init__.py (not served here)
- app/repositories/backup_adapter.py (not served here)
- app/repositories/embeddings/__init__.py (not served here)
- app/repositories/embeddings/bounded_executor.py (not served here)
- app/repositories/embeddings/embedding_adapter.py (not served here)
- app/repositories/embeddings/fastembed_offline.py (not served here)
- app/repositories/embeddings/reranker_adapter.py (not served here)
- app/repositories/postgres/__init__.py (not served here)
- app/repositories/postgres/activity_repository.py (not served here)
- app/repositories/postgres/code_artifact_repository.py (not served here)
- app/repositories/postgres/document_repository.py (not served here)
- app/repositories/postgres/entity_repository.py (not served here)
- app/repositories/postgres/file_repository.py (not served here)
- app/repositories/postgres/memory_repository.py (not served here)
- app/repositories/postgres/plan_repository.py (not served here)
- app/repositories/postgres/postgres_adapter.py (not served here)
- app/repositories/postgres/postgres_tables.py (not served here)
- app/repositories/postgres/project_reference.py (not served here)
- app/repositories/postgres/project_repository.py (not served here)
- app/repositories/postgres/skill_repository.py (not served here)
- app/repositories/postgres/task_repository.py (not served here)
- app/repositories/postgres/user_repository.py (not served here)
- app/repositories/sqlite/__init__.py (not served here)
- app/repositories/sqlite/activity_repository.py (not served here)
- app/repositories/sqlite/code_artifact_repository.py (not served here)
- app/repositories/sqlite/document_repository.py (not served here)
- app/repositories/sqlite/entity_repository.py (not served here)
- app/repositories/sqlite/file_repository.py (not served here)
- app/repositories/sqlite/memory_repository.py (not served here)
- app/repositories/sqlite/plan_repository.py (not served here)
- app/repositories/sqlite/project_reference.py (not served here)
- app/repositories/sqlite/project_repository.py (not served here)
- app/repositories/sqlite/skill_repository.py (not served here)
- app/repositories/sqlite/sqlite_adapter.py (not served here)
- app/repositories/sqlite/sqlite_tables.py (not served here)
- app/repositories/sqlite/task_repository.py (not served here)
- app/repositories/sqlite/user_repository.py (not served here)
- app/routes/__init__.py (not served here)
- app/routes/api/__init__.py (not served here)
- app/routes/api/activity.py (not served here)
- app/routes/api/auth.py (not served here)
- app/routes/api/capabilities.py (not served here)
- app/routes/api/code_artifacts.py (not served here)
- app/routes/api/documents.py (not served here)
- app/routes/api/entities.py (not served here)
- app/routes/api/files.py (not served here)
- app/routes/api/graph.py (not served here)
- app/routes/api/health.py (not served here)
- app/routes/api/memories.py (not served here)
- app/routes/api/plans.py (not served here)
- app/routes/api/projects.py (not served here)
- app/routes/api/skills.py (not served here)
- app/routes/api/tasks.py (not served here)
- app/routes/cli/__init__.py (not served here)
- app/routes/cli/auth_commands.py (not served here)
- app/routes/cli/context.py (not served here)
- app/routes/cli/local_executor.py (not served here)
- app/routes/cli/parser.py (not served here)
- app/routes/cli/paths.py (not served here)
- app/routes/cli/remote_executor.py (not served here)
- app/routes/cli/render.py (not served here)
- app/routes/cli/token_storage.py (not served here)
- app/routes/cli/verbs.py (not served here)
- app/routes/mcp/__init__.py (not served here)
- app/routes/mcp/code_artifact_tools.py (not served here)
- app/routes/mcp/document_tools.py (not served here)
- app/routes/mcp/entity_tools.py (not served here)
- app/routes/mcp/memory_tools.py (not served here)
- app/routes/mcp/meta_tools.py (not served here)
- app/routes/mcp/pagination.py (not served here)
- app/routes/mcp/project_tools.py (not served here)
- app/routes/mcp/scope_resolver.py (not served here)
- app/routes/mcp/skill_tools.py (not served here)
- app/routes/mcp/tool_adapters.py (not served here)
- app/routes/mcp/tool_metadata_registry.py (not served here)
- app/routes/mcp/tool_registry.py (not served here)
- app/routes/mcp/user_tools.py (not served here)
- app/routes/plan_plugin_responses.py (not served here)
- app/routes/write_plugin_responses.py (not served here)
- app/services/__init__.py (not served here)
- app/services/activity_service.py (not served here)
- app/services/backup_service.py (not served here)
- app/services/code_artifact_service.py (not served here)
- app/services/document_service.py (not served here)
- app/services/entity_service.py (not served here)
- app/services/entity_write_plugin_service.py (not served here)
- app/services/file_service.py (not served here)
- app/services/graph_service.py (not served here)
- app/services/memory_service.py (not served here)
- app/services/plan_service.py (not served here)
- app/services/plan_write_plugin_service.py (not served here)
- app/services/project_service.py (not served here)
- app/services/re_embedding_service.py (not served here)
- app/services/skill_service.py (not served here)
- app/services/task_service.py (not served here)
- app/services/user_service.py (not served here)
- app/services/write_plugin_service.py (not served here)
- app/utils/__init__.py (not served here)
- app/utils/embedding_helpers.py (not served here)
- app/utils/keyword_query.py (not served here)
- app/utils/provenance.py (not served here)
- app/utils/pydantic_helper.py (not served here)
- app/utils/rank_fusion.py (not served here)
- app/utils/repository_identity.py (not served here)
- app/utils/token_counter.py (not served here)
- app/version.py (not served here)
- architecture.md
- benchmarks/retrieval/README.md (not served here)
- benchmarks/retrieval/build_corpus.py (not served here)
- benchmarks/retrieval/corpus.jsonl (not served here)
- benchmarks/retrieval/eval_lib.py (not served here)
- benchmarks/retrieval/queries_curated.jsonl (not served here)
- benchmarks/retrieval/run_eval.py (not served here)
- default.nix (not served here)
- docker/.env.example (not served here)
- docker/Dockerfile (not served here)
- docker/docker-compose.postgres.yml (not served here)
- docker/docker-compose.sqlite.yml (not served here)
- docker/docker-compose.yml (not served here)
- docs/OFFLINE_SETUP.md (not served here)
- docs/api_reference.md
- docs/assets/mycelium_class_diagram.md (not served here)
- docs/concepts.md
- docs/configuration.md (not served here)
- docs/connectivity_guide.md (not served here)
- docs/copilot-cli/README.md (not served here)
- docs/copilot-cli/agents/forgetful-memory.agent.md (not served here)
- docs/copilot-cli/agents/knowledge-explorer.agent.md (not served here)
- docs/copilot-cli/agents/memory-curator.agent.md (not served here)
- docs/copilot-cli/skills/README.md (not served here)
- docs/dev/architecture-tests.md (not served here)
- docs/dev/cli_plan.md (not served here)
- docs/embedding_migration.md
- docs/features_roadmap.md
- docs/gemini-cli/README.md (not served here)
- docs/gemini-cli/commands/encode-repo.toml (not served here)
- docs/gemini-cli/commands/forgetful-setup.toml (not served here)
- docs/gemini-cli/commands/memory-explore.toml (not served here)
- docs/gemini-cli/commands/memory-list.toml (not served here)
- docs/gemini-cli/commands/memory-save.toml (not served here)
- docs/gemini-cli/commands/memory-search.toml (not served here)
- docs/images/Forgetful Architecture.drawio.png (not served here)
- docs/images/Forgetful Architecture.drawio_transparent.png (not served here)
- docs/images/avatar.png (not served here)
- docs/images/hero_banner.png (not served here)
- docs/images/layers.png (not served here)
- docs/nix.md
- docs/opencode/README.md (not served here)
- docs/opencode/commands/encode-repo.md (not served here)
- docs/opencode/commands/forgetful-setup.md (not served here)
- docs/opencode/commands/memory-explore.md (not served here)
- docs/opencode/commands/memory-list.md (not served here)
- docs/opencode/commands/memory-save.md (not served here)
- docs/opencode/commands/memory-search.md (not served here)
- docs/opencode/skills/README.md (not served here)
- docs/prompts/comprehensive_project_understanding_prompt.md (not served here)
- docs/prompts/custom_agent_integration.md (not served here)
- docs/prompts/example_system_prompt.md (not served here)
- docs/prompts/knowledge_base_bootstrap_prompt.md (not served here)
- docs/prompts/prompts_overview.md (not served here)
- docs/prompts/rapid_project_scan_prompt.md (not served here)
- docs/release_notes.md
- docs/search.md
- docs/self-hosting-guide.md
- docs/tool_reference.md
- examples/plan_policy.py (not served here)
- flake.lock (not served here)
- flake.nix (not served here)
- main.py (not served here)
- nix/test-fixtures.nix (not served here)
- org_knowledge_proposal.md
- pyproject.toml (not served here)
- pytest.ini (not served here)
- ruff.toml (not served here)
- shell.nix (not served here)
- skills/README.md (not served here)
- skills/forgetful-cli-setup/SKILL.md (not served here)
- skills/forgetful-context-gather/SKILL.md (not served here)
- skills/forgetful-encode-repo/SKILL.md (not served here)
- skills/forgetful-encode-repo/references/first-encode.md (not served here)
- skills/forgetful-encode-repo/references/refresh.md (not served here)
- skills/forgetful-entities/SKILL.md (not served here)
- skills/forgetful-explore/SKILL.md (not served here)
- skills/forgetful-files/SKILL.md (not served here)
- skills/forgetful-mcp-setup/SKILL.md (not served here)
- skills/forgetful-procedures/SKILL.md (not served here)
- skills/forgetful-recall/SKILL.md (not served here)
- skills/forgetful-remember/SKILL.md (not served here)
- test_harness/README.md (not served here)
- test_harness/__init__.py (not served here)
- test_harness/__main__.py (not served here)
- test_harness/config.py (not served here)
- test_harness/container.py (not served here)
- test_harness/docker/Dockerfile (not served here)
- test_harness/docker/opencode.json (not served here)
- test_harness/docker/runner.py (not served here)
- test_harness/prompts.py (not served here)
- test_harness/report.py (not served here)
- test_harness/server.py (not served here)
- test_harness/walkthrough.py (not served here)
- tests/__init__.py (not served here)
- tests/architecture/test_contracts.py (not served here)
- tests/backup_restore_cases.py (not served here)
- tests/docker/test_offline_image.py (not served here)
- tests/e2e/README.md (not served here)
- tests/e2e/conftest.py (not served here)
- tests/e2e/test_activity_user_scope_e2e.py (not served here)
- tests/e2e/test_api_activity.py (not served here)
- tests/e2e/test_api_memories_e2e.py (not served here)
- tests/e2e/test_auth_e2e.py (not served here)
- tests/e2e/test_auto_link_threshold_e2e.py (not served here)
- tests/e2e/test_backup_recovery_e2e.py (not served here)
- tests/e2e/test_cli_postgres_e2e.py (not served here)
- tests/e2e/test_code_artifact_tools_e2e.py (not served here)
- tests/e2e/test_cross_user_reference_checks_e2e.py (not served here)
- tests/e2e/test_document_tools_e2e.py (not served here)
- tests/e2e/test_embedding_concurrency.py (not served here)
- tests/e2e/test_entity_tools_e2e.py (not served here)
- tests/e2e/test_file_tools_e2e.py (not served here)
- tests/e2e/test_graph_e2e.py (not served here)
- tests/e2e/test_health_e2e.py (not served here)
- tests/e2e/test_hybrid_search_e2e.py (not served here)
- tests/e2e/test_link_memories_no_autolink_e2e.py (not served here)
- tests/e2e/test_memory_link_ownership_e2e.py (not served here)
- tests/e2e/test_memory_tools_e2e.py (not served here)
- tests/e2e/test_memory_usage_e2e.py (not served here)
- tests/e2e/test_memory_usage_tracking_disabled_e2e.py (not served here)
- tests/e2e/test_meta_tools_e2e.py (not served here)
- tests/e2e/test_obsolete_matches_e2e.py (not served here)
- tests/e2e/test_plan_external_ref_e2e.py (not served here)
- tests/e2e/test_plan_plugin_e2e.py (not served here)
- tests/e2e/test_plan_tools_e2e.py (not served here)
- tests/e2e/test_project_tools_e2e.py (not served here)
- tests/e2e/test_provenance_e2e.py (not served here)
- tests/e2e/test_re_embedding_e2e.py (not served here)
- tests/e2e/test_reranking_e2e.py (not served here)
- tests/e2e/test_retrieval_scores_e2e.py (not served here)
- tests/e2e/test_skill_tools_e2e.py (not served here)
- tests/e2e/test_task_tools_e2e.py (not served here)
- tests/e2e/test_user_creation_e2e.py (not served here)
- tests/e2e/test_user_tools_e2e.py (not served here)
- tests/e2e/test_zz_backup_restore_e2e.py (not served here)
- tests/e2e_provider_sessions/__init__.py (not served here)
- tests/e2e_provider_sessions/conftest.py (not served here)
- tests/e2e_provider_sessions/test_provider_sessions.py (not served here)
- tests/e2e_sqlite/conftest.py (not served here)
- tests/e2e_sqlite/test_api_activity_sqlite.py (not served here)
- tests/e2e_sqlite/test_api_auth.py (not served here)
- tests/e2e_sqlite/test_api_code_artifacts.py (not served here)
- tests/e2e_sqlite/test_api_documents.py (not served here)
- tests/e2e_sqlite/test_api_entities.py (not served here)
- tests/e2e_sqlite/test_api_files.py (not served here)
- tests/e2e_sqlite/test_api_graph.py (not served here)
- tests/e2e_sqlite/test_api_graph_limit_settings.py (not served here)
- tests/e2e_sqlite/test_api_memories.py (not served here)
- tests/e2e_sqlite/test_api_plans.py (not served here)
- tests/e2e_sqlite/test_api_projects.py (not served here)
- tests/e2e_sqlite/test_api_skills.py (not served here)
- tests/e2e_sqlite/test_api_task_actions.py (not served here)
- tests/e2e_sqlite/test_api_tasks.py (not served here)
- tests/e2e_sqlite/test_auth_cache_sqlite.py (not served here)
- tests/e2e_sqlite/test_auth_sqlite.py (not served here)
- tests/e2e_sqlite/test_auth_token_cache_sqlite.py (not served here)
- tests/e2e_sqlite/test_auto_link_threshold_sqlite.py (not served here)
- tests/e2e_sqlite/test_backup_restore_sqlite.py (not served here)
- tests/e2e_sqlite/test_cli_passthrough.py (not served here)
- tests/e2e_sqlite/test_cli_remote.py (not served here)
- tests/e2e_sqlite/test_cli_verbs.py (not served here)
- tests/e2e_sqlite/test_code_artifact_tools_sqlite.py (not served here)
- tests/e2e_sqlite/test_cross_user_reference_checks_sqlite.py (not served here)
- tests/e2e_sqlite/test_document_tools_sqlite.py (not served here)
- tests/e2e_sqlite/test_embedding_concurrency_sqlite.py (not served here)
- tests/e2e_sqlite/test_entity_tools_sqlite.py (not served here)
- tests/e2e_sqlite/test_feature_flags_sqlite.py (not served here)
- tests/e2e_sqlite/test_file_tools_sqlite.py (not served here)
- tests/e2e_sqlite/test_harness_server.py (not served here)
- tests/e2e_sqlite/test_health_sqlite.py (not served here)
- tests/e2e_sqlite/test_hybrid_search.py (not served here)
- tests/e2e_sqlite/test_link_memories_no_autolink_sqlite.py (not served here)
- tests/e2e_sqlite/test_memory_file_ids_sqlite.py (not served here)
- tests/e2e_sqlite/test_memory_link_ownership_sqlite.py (not served here)
- tests/e2e_sqlite/test_memory_tools_sqlite.py (not served here)
- tests/e2e_sqlite/test_meta_tools_sqlite.py (not served here)
- tests/e2e_sqlite/test_obsolete_matches_sqlite.py (not served here)
- tests/e2e_sqlite/test_plan_external_ref_storage.py (not served here)
- tests/e2e_sqlite/test_plan_plugin_storage.py (not served here)
- tests/e2e_sqlite/test_plan_tools_sqlite.py (not served here)
- tests/e2e_sqlite/test_project_tools_sqlite.py (not served here)
- tests/e2e_sqlite/test_provenance_sqlite.py (not served here)
- tests/e2e_sqlite/test_re_embedding_sqlite.py (not served here)
- tests/e2e_sqlite/test_reranking_concurrency_sqlite.py (not served here)
- tests/e2e_sqlite/test_reranking_sqlite.py (not served here)
- tests/e2e_sqlite/test_retrieval_scores_sqlite.py (not served here)
- tests/e2e_sqlite/test_scoped_permissions_sqlite.py (not served here)
- tests/e2e_sqlite/test_skill_tools_sqlite.py (not served here)
- tests/e2e_sqlite/test_task_tools_sqlite.py (not served here)
- tests/e2e_sqlite/test_token_scope_fail_open_sqlite.py (not served here)
- tests/e2e_sqlite/test_user_creation_sqlite.py (not served here)
- tests/e2e_sqlite/test_user_tools_sqlite.py (not served here)
- tests/integration/conftest.py (not served here)
- tests/integration/entity_plugin_helpers.py (not served here)
- tests/integration/plan_plugin_helpers.py (not served here)
- tests/integration/test_auth.py (not served here)
- tests/integration/test_auth_cache.py (not served here)
- tests/integration/test_auth_factory.py (not served here)
- tests/integration/test_auth_info.py (not served here)
- tests/integration/test_auth_token_cache.py (not served here)
- tests/integration/test_azure_embedding_concurrency.py (not served here)
- tests/integration/test_azure_embeddings_adapter.py (not served here)
- tests/integration/test_backup_service.py (not served here)
- tests/integration/test_bootstrap.py (not served here)
- tests/integration/test_capabilities.py (not served here)
- tests/integration/test_cli_dispatch.py (not served here)
- tests/integration/test_cli_local_executor.py (not served here)
- tests/integration/test_cli_remote_executor.py (not served here)
- tests/integration/test_cli_verbs_mapping.py (not served here)
- tests/integration/test_code_artifact_service.py (not served here)
- tests/integration/test_config_precedence.py (not served here)
- tests/integration/test_dns_record_security.py (not served here)
- tests/integration/test_document_service.py (not served here)
- tests/integration/test_entity_plugin_cli.py (not served here)
- tests/integration/test_entity_plugin_phases.py (not served here)
- tests/integration/test_entity_plugin_runtime.py (not served here)
- tests/integration/test_entity_plugin_transports.py (not served here)
- tests/integration/test_entity_service.py (not served here)
- tests/integration/test_event_bus.py (not served here)
- tests/integration/test_fastembed_concurrency.py (not served here)
- tests/integration/test_fastembed_offline.py (not served here)
- tests/integration/test_file_service.py (not served here)
- tests/integration/test_graph_service_plan_task.py (not served here)
- tests/integration/test_harness_cli.py (not served here)
- tests/integration/test_harness_config.py (not served here)
- tests/integration/test_harness_container.py (not served here)
- tests/integration/test_harness_report.py (not served here)
- tests/integration/test_harness_walkthrough.py (not served here)
- tests/integration/test_http_reranker_adapter.py (not served here)
- tests/integration/test_keyword_query.py (not served here)
- tests/integration/test_local_reranker_concurrency.py (not served here)
- tests/integration/test_memory_fts_unicode.py (not served here)
- tests/integration/test_memory_null_transports.py (not served here)
- tests/integration/test_memory_null_updates.py (not served here)
- tests/integration/test_memory_plugin_phases.py (not served here)
- tests/integration/test_memory_score_serialization.py (not served here)
- tests/integration/test_memory_service.py (not served here)
- tests/integration/test_memory_usage_tracking.py (not served here)
- tests/integration/test_memory_write_plugin.py (not served here)
- tests/integration/test_meta_tools_docstrings.py (not served here)
- tests/integration/test_obsolete_warning_gate.py (not served here)
- tests/integration/test_obsolete_warning_settings.py (not served here)
- tests/integration/test_ollama_embeddings_adapter.py (not served here)
- tests/integration/test_onnx_providers.py (not served here)
- tests/integration/test_openai_embedding_concurrency.py (not served here)
- tests/integration/test_openai_embeddings_adapter.py (not served here)
- tests/integration/test_plan_plugin_baseline.py (not served here)
- tests/integration/test_plan_plugin_cli.py (not served here)
- tests/integration/test_plan_plugin_runtime.py (not served here)
- tests/integration/test_plan_plugin_transports.py (not served here)
- tests/integration/test_plan_service.py (not served here)
- tests/integration/test_project_service.py (not served here)
- tests/integration/test_provenance.py (not served here)
- tests/integration/test_rank_fusion.py (not served here)
- tests/integration/test_re_embedding_service.py (not served here)
- tests/integration/test_rest_auth.py (not served here)
- tests/integration/test_retrieval_benchmark_lib.py (not served here)
- tests/integration/test_rrf_tie_break.py (not served here)
- tests/integration/test_scope_resolver.py (not served here)
- tests/integration/test_service_activity_events.py (not served here)
- tests/integration/test_skill_frontmatter_quoting.py (not served here)
- tests/integration/test_skill_service.py (not served here)
- tests/integration/test_targeted_rebuild_sqlite.py (not served here)
- tests/integration/test_task_service.py (not served here)
- tests/integration/test_token_scope_fail_open.py (not served here)
- tests/integration/test_tool_registry.py (not served here)
- tests/integration/test_trace_context_security.py (not served here)
- tests/integration/test_unobsolete_memory.py (not served here)
- tests/integration/test_user_service.py (not served here)
- tests/integration/test_write_plugin_cli.py (not served here)
- tests/integration/test_write_plugin_runtime.py (not served here)
- tests/integration/test_write_plugin_transports.py (not served here)
- tests/plan_external_ref_cases.py (not served here)
- tests/plan_plugin_cases.py (not served here)
- tests/user_creation_cases.py (not served here)
- uv.lock (not served here)
Advantages
- Automatic knowledge graph construction through semantic linking of atomic memories. evidence: README.md
- Maintains context window efficiency via configurable token budgets and importance-based ranking. evidence: README.md
- Flexible deployment options ranging from zero-config local SQLite to scalable PostgreSQL. evidence: README.md
Limitations
- Requires adherence to the Zettelkasten principle, which may be restrictive for some workflows. evidence: README.md
- Limits the number of tools exposed to the agent to preserve context window, potentially hiding advanced functionality. evidence: README.md
Security
Risk level: Medium risk
This brain runs
Agent instructions that run or fetch something (34)
AGENTS.md:Run `uv run pytest tests/architecture/` to check and prove the agreed import boundaries.AGENTS.md:**Location**: `tests/integration/` **Purpose**: Test business logic with stubbed I/O (no real database required) **Run locally**:AGENTS.md:uv run pytest tests/integration/AGENTS.md:These tests use in-memory stubs and run fast (~seconds).AGENTS.md:**Location**: `tests/e2e_sqlite/` **Purpose**: Test complete stack with in-memory SQLite **Requirements**: None (no Docker required) **Run locally**:AGENTS.md:uv run pytest tests/e2e_sqlite/AGENTS.md:**Location**: `tests/e2e/` **Purpose**: Test complete stack with real PostgreSQL **Requirements**: PostgreSQL running in Docker **Run locally**:AGENTS.md:uv run pytest -m e2eAGENTS.md:Ensure that you run ruff following any changes and address any issues raisedAGENTS.md:uv tool run ruff check .skills/forgetful-cli-setup/SKILL.md:The CLI is the shell-native surface: same tool registry as MCP, reachable by anything that can run a command.skills/forgetful-cli-setup/SKILL.md:After changing embedding provider or model: `forgetful re-embed --dry-run` to preview, then `forgetful re-embed` (batch size tunable via `--batch-size`).skills/forgetful-context-gather/SKILL.md:Run MCP-flavored gathers in the main conversation.skills/forgetful-context-gather/SKILL.md:Done when: every angle has run and its outcome is recorded.skills/forgetful-encode-repo/SKILL.md:this skill moves it, and only after a run has reviewed every change up to the new commit.skills/forgetful-encode-repo/SKILL.md:Run git in the repository being encoded (the current directory unless the user named one).skills/forgetful-encode-repo/SKILL.md:**HEAD**: `git rev-parse HEAD`.skills/forgetful-encode-repo/SKILL.md:Unless the user names another range end, this is the end commit: everything this run writes describes it.skills/forgetful-encode-repo/SKILL.md:**Clean worktree**: `git status --porcelain` prints nothing.skills/forgetful-encode-repo/SKILL.md:**Project**: `git remote get-url origin` → `owner/repo` → `list_projects` with `repo_name`.skills/forgetful-encode-repo/SKILL.md:Checks: the checkpoint is a commit here when `git rev-parse --verify --quiet <sha>^{commit}` prints the stored value itself;skills/forgetful-encode-repo/SKILL.md:`git merge-base --is-ancestor <sha> <end>` succeeds when it is an ancestor.skills/forgetful-encode-repo/SKILL.md:Done when: the branch decision is written, and each value in it comes from a command or tool result in this run.skills/forgetful-encode-repo/SKILL.md:**Retrieval**: when the run wrote knowledge, `query_memory` scoped to the project with `strict_project_filter` true and the questions this encoding should answer (how the system fits together, each changed area under its current name).skills/forgetful-encode-repo/SKILL.md:**Pinning**: `git rev-parse HEAD` still matches Step 1, `git status --porcelain` still prints nothing, and `get_project` still shows the checkpoint read in Step 1.skills/forgetful-encode-repo/SKILL.md:Advance the checkpoint only when the run recorded no gaps and the range leaves no unreviewed commit (see user ranges in Step 2).skills/forgetful-encode-repo/SKILL.md:Build it from tool results in this run: an ID or count appears only when a response confirmed it, and a read that failed is reported as unknown.skills/forgetful-encode-repo/SKILL.md:Correct the call against the operation's schema and run it again;skills/forgetful-mcp-setup/SKILL.md:**stdio** — the client spawns the server per session: command `uvx forgetful-ai` (equivalently `forgetful serve --transport stdio`).skills/forgetful-mcp-setup/SKILL.md:Recognised scopes in verified token `scope`/`scp` claims can narrow MCP access further;· uses the networkskills/forgetful-mcp-setup/SKILL.md:Run Forgetful MCP calls in the main conversation — subagents do not inherit MCP tool access.skills/forgetful-procedures/SKILL.md:All skill operations run through the standard invocation surface below, the same as every other domain.skills/forgetful-recall/SKILL.md:Run it as a deliberate step, then continue into normal recall as the task demands.skills/forgetful-remember/SKILL.md:Derive the candidate from the repo: `git remote get-url origin` → `owner/repo` → `list_projects` with `repo_name`.
MCP servers (2)
README.md(forgetful):uvx forgetful-aiREADME.md(forgetful):http://localhost:8020/mcp· uses the network
Install scripts (1)
app/bootstrap.py:python app/bootstrap.py
Package scripts (1)
pyproject.toml(build-hook):hatch build hook vcs (hatch_build.py)
- Medium risk: runs-mcp-server-unpinned-runner (README.md:159)
- Medium risk: runs-instruction-instruction-network (skills/forgetful-mcp-setup/SKILL.md:51)
- Low risk: scripts-present (app/bootstrap.py)
- Low risk: network-instructions (skills/forgetful-cli-setup/SKILL.md:25)
Attribution and licence
- Created by
- Scott
- Declared authors
- Scott (declared in pyproject.toml)
- Publisher
- Scott Raisbeck (Community)
- Source
- ScottRBK/forgetful · commit 9f85ddc
- Licence
- MIT License (files served here)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Scott.
Install from source
452 of its files are not served here, so there is no ZIP. ScottRBK/forgetful at 9f85ddc