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.
architecture.md
Forgetful architecture
Reviewable, agent-authored overview, checked against source on 2026-10-08, with boundary changes checked on 2026-10-17 and Memory Plugin phases on 2026-10-19. This is a selective interpretation, not an exhaustive dependency inventory. The component groupings below are inferred for readability; the described execution paths and wiring were verified against source. Line numbers are inspection starting points and may drift.
Forgetful provides persistent, semantically searchable memories and related knowledge through MCP tools, HTTP endpoints, and a CLI. Its intended boundary is routes → services → protocols → repositories/adapters, as described in AGENTS.md. Protocols are Python contracts, not an extra runtime process: services call injected implementations. SQL, vector storage, provider clients, and database sessions normally stay behind those contracts. Operational exceptions are called out below rather than hidden by the diagram.
Component view
flowchart TD
MCP["MCP: three meta-tools"] --> Registry["ToolRegistry"]
Local["Local CLI executor"] --> Registry
Remote["Remote CLI executor"] --> MCP
Registry --> ToolAdapters["Tool adapters: identity, models, results"]
ToolAdapters --> Services["Domain services"]
HTTP["HTTP custom routes"] --> Services
Services --> Contracts["Repository protocols"]
Services --> PlanPlugin["PlanWritePluginService: create/update/delete, including automatic completion"]
Bootstrap --> PlanLoader["config.plan_plugin: trusted PlanPlugin loader"]
PlanLoader -. supplies registration .-> PlanPlugin
Services --> WritePlugin["WritePluginService: before_save and advisory after_save"]
WritePlugin --> Callable["MemoryPlugin: explicit operation-to-handler mappings"]
Services --> EntityWritePlugin["EntityWritePluginService: before_save and advisory after_save"]
EntityWritePlugin --> EntityCallable["EntityPlugin: create, update, delete mappings"]
Bootstrap --> Loader["config.write_plugin: trusted module:object loaders"]
Loader -. supplies registration .-> WritePlugin
Loader -. supplies registration .-> EntityWritePlugin
SQLite["SQLite repositories"] -. implements .-> Contracts
Postgres["PostgreSQL repositories"] -. implements .-> Contracts
SQLite --> SQLiteDB["SQLite adapter and sqlite-vec"]
Postgres --> PostgresDB["PostgreSQL adapter and pgvector"]
SQLite --> Providers["Embedding and rerank adapters"]
Postgres --> Providers
Services --> Events["Optional EventBus"]
Events --> Activity["ActivityService and memory access handler"]
Activity --> Contracts
Bootstrap["bootstrap.build_runtime"] -->|constructs and injects| Services
Bootstrap -->|registers implementations| Registry
Bootstrap -->|selects backend| SQLite
Bootstrap -->|selects backend| PostgresBoxes combine multiple classes/files; they are not declared packages or separate deployments. Solid arrows show source-verified use or explicitly labelled startup wiring. Dotted arrows mean structural implementation of a contract, not inheritance or a request passing through a protocol. Only memory/skill repositories use the embedding/rerank branch. Health/auth routes and operational commands have additional paths omitted here; the diagram does not assert universal layering.
Entry points and lifecycle
| Inspection point | Responsibility |
|---|---|
| main.py:46 | Server lifespan configures logging, calls build_runtime, attaches services/registry/scopes to the FastMCP instance, then disposes the runtime on normal shutdown. Logging is deferred to protect STDIO transport. |
| main.py:112, main.py:306 | Construct FastMCP with configured authentication; serve over STDIO or HTTP. The CORS branch wraps the HTTP app with Starlette middleware and runs Uvicorn. |
| bootstrap.py:224 | Composition root: choose providers and database, initialize schema, construct repositories, services, optional events, tool registry, and instance scope ceiling. |
| bootstrap.py:193 | Services and Runtime collect the instances for front doors; optional services are None when disabled. This is explicit constructor injection, not a DI container. |
| bootstrap.py:377 | Drain pending event handlers before closing the database; especially relevant to one-shot CLI execution. |
| parser.py:258 | Dispatch CLI serve, re-embed, tool discovery/calls, memory/project verbs, and authentication commands. |
The bootstrap factories select PostgreSQL or SQLite repositories at
bootstrap.py:91, passing embedding and rerank adapters to memory/skill repositories.
FILES_ENABLED, SKILLS_ENABLED, and PLANNING_ENABLED control matching repositories, services,
metadata registration, and HTTP route registration. GraphService receives memory/entity repositories
plus the other services, including optional ones (bootstrap.py:311).
The runtime owns the optional embedding adapter and closes its resources after
draining pending events, before database disposal. Startup failures also close the adapter;
the standalone re-embedding CLI closes it on every exit. FastEmbed uses one model and an
adapter-layer bounded executor shared by memory and skill operations. Admission precedes
submission; cancelled running inference remains counted until its worker finishes.
OpenAI and Azure OpenAI embedding HTTP calls each use one native async SDK client and a shared HTTP connection
pool capped by the same per-process setting. SDK retry backoff releases connection capacity.
This is a connection limit, not a logical-operation or request-rate limit; waiting callers
and remote processing after local cancellation are not bounded. Shutdown closes the SDK
client without draining in-flight OpenAI or Azure operations, through the same runtime,
startup-error and CLI exit paths.
Settings and validation live in settings.py:33.
The local executor:18 builds the same runtime, supplies a CLI context, checks the instance's permitted tools, and executes the registry in process. The remote executor:67 calls the server's three meta-tools through an MCP client; it does not build a second local database stack. Both conform to ToolExecutor:10.
MCP, HTTP, and identity
The active MCP surface is registered by meta_tools.py:473:
discover_forgetful_toolslists permitted tool metadata, optionally by category.how_to_use_forgetful_toolreturns detailed metadata for a permitted tool.execute_forgetful_toolchecks the name/permissions, injects context, and dispatches it.
The full operation set is dynamic: feature flags and scopes affect what a caller sees.
tool_metadata_registry.py:874 constructs adapter
callables and registers metadata/implementations together. Despite its filename, this is a module
of registration helpers, not a second ToolMetadataRegistry class.
ToolRegistry.execute:188 looks up and awaits the callable.
MemoryToolAdapters.create_memory:199 illustrates identity
resolution, argument conversion, model construction, service delegation, and response formatting.
The older category *_tools.py registration functions also appear in the map; their presence does
not mean they are mounted by main.py, which registers meta_tools at line 150.
HTTP endpoints are FastMCP custom routes accepting Starlette requests, rather than a separate
FastAPI application despite the opening docstring in main.py.
main.py:130 mounts health, auth info, domain CRUD, graph, and activity routes;
files, skills, plans, and tasks are conditional. The root service-info route starts at
main.py:115. Examples:
| Surface | Source and path |
|---|---|
| Health / auth discovery | health.py:19 /health; auth.py:32 /api/v1/auth/info. |
| Public capability discovery | capabilities.py:10 /.well-known, beneath the deployment prefix; reads feature settings directly without identity resolution or domain I/O. |
| Domain operations | memories.py:178 validates a create request and calls MemoryService directly; other domain routes follow this broad shape. |
| Graph exploration | graph.py:42 assembles a broad graph using domain services; graph.py:968 delegates bounded subgraph traversal to GraphService. |
| Activity history / streaming | activity.py:48 queries persisted events; activity.py:234 streams per-user events via SSE. |
build_auth_provider:106 selects configured GitHub/Google OAuth, JWT,
or introspection providers, or no authentication. MCP identity comes from validated tokens or a
default user (auth.py:106); HTTP identity has its own bearer-token
verification/cache path (auth.py:157). Services receive an internal user ID.
scope_resolver.py:162 intersects token permissions with
the instance ceiling for MCP. Token scopes come from the scope/scp claim; unrecognised scopes are
ignored, and a claim with scopes but none recognised permits nothing. Its empty-ceiling fallback
permits all registered tools; do not interpret an empty ceiling as deny-all. HTTP routes do not automatically inherit registry scope checks:
inspect their own authorization path before assuming parity. This overview is not a security audit.
Memory write, retrieval, and linking
Create: route/tool adapter → MemoryService.create_memory → optional before-save decision → repository → embedding provider
and database. memory_service.py:185 applies provenance
defaults, persists the memory, then optionally finds similar memories and creates links in a batch.
The repository builds embedding text and persists associations as part of its create operation:
PostgreSQL:191,
SQLite:258.
Memory creation and subsequent automatic linking are separate repository calls, not one service-wide transaction.
Automatic linking uses the configured neighbor limit and similarity threshold, excluding obsolete memories and the source memory (PostgreSQL:456, SQLite:516). Explicit linking is a separate service operation (memory_service.py:631); repository link methods maintain the bidirectional memory relation and only link memories owned by the calling user. Obsolescence is a soft state with reason and optional replacement; create responses can additionally warn about similar obsolete memories (memory_service.py:552).
Plan Plugin: config.plan_plugin validates one trusted PlanPlugin registration at startup,
including when planning is disabled. PlanWritePluginService dispatches explicit create/update/delete
maps with detached contexts; it cannot rewrite core input. PlanService retains ownership, status,
provenance and reference rules, rereading after a before-handler await. Serial successful mutations
invoke each registered phase once; absent plan CAS, concurrent callbacks can repeat. Transient write
results carry warnings to flat REST/MCP/CLI payloads without changing reads or stored models.
TaskService routes completion after task transition and deletion through this same policy. Rejection
or policy unavailability is advisory for the committed task; unrelated post-commit failures and genuine
cancellation retain existing propagation. Plan deletion cascades tasks/criteria/dependencies without
per-task hooks; project/user cascades do not dispatch Plan hooks. No durable delivery or rollback.
Entity Plugin: mirrors the Memory Plugin for entity create, update, and delete via
load_entity_plugin, EntityPlugin, and EntityWritePluginService. Handlers see detached entity
snapshots only; deleting an entity row cascades at the database to entity_project_association,
memory_entity_association, entity_file_association, and entity_relationships rows whose
source_entity_id / target_entity_id reference the entity, without separate plugin hooks.
Memory Plugin: app/config/write_plugin.py loads one trusted module:object registration before
costly resources. MemoryPlugin in app/protocols/write_plugin_protocol.py owns copied, frozen
before_save and after_save mappings from explicit operations to async handlers. Supported
operations are create, update, obsolete, and restore; an absent mapping skips that handler.
Invalid registrations fail startup. This replaces the unreleased function contract without a
compatibility layer. Bootstrap injects WritePluginService; services never import the loader.
app/models/write_plugin_models.py owns detached contexts, decisions, advisory warnings, and
internal write results. The existing MEMORY_WRITE_PLUGIN* settings remain.
Before create/update, the plugin gets separately detached submitted/previous/proposed snapshots,
with the writable candidate built by MemoryService after defaults and merging. Lifecycle contexts
use MemoryLifecycleRequest and MemoryLifecycleState: submitted ID/reason/replacement, full
previous memory, and proposed obsolete flag/reason/replacement. They do not pretend lifecycle state
is a MemoryCreate, or invent a database timestamp. Core permissions, ownership, validation, and
state checks still apply. Invalid operations skip policies; no-op updates skip both phases.
Repeating obsolete retains its existing mutation behavior, including a new obsolescence timestamp.
Enforce-mode rejection or before-handler failure blocks persistence/events; warn mode proceeds with warnings. No session spans a handler await. After a before-update handler completes, the service re-reads the owned memory and recomputes patch differences for embeddings and events. A resulting no-op retains timestamp and warnings without an event or after handler. Lifecycle mutations patch only lifecycle fields, refresh previous state after before-handler waits, and retain the repository's conditional restore check. Original policy snapshots are not re-evaluated. These measures remove avoidable stale overwrites caused by plugin waits; they do not make checks atomic or prevent later concurrent changes, including the existing embedding-provider await race. MemoryService still normalizes explicit-null updates before provenance/change detection (#95), preserving submitted snapshots. Non-null skill association update limitations (#96) remain.
After successful persistence, existing create similarity/link work, and event emission,
MemorySavedRequest supplies detached user/operation/previous/saved state. Create reuses existing
scored MemorySummary matches (four-decimal scores); saved link IDs report actual resulting links.
Similarity is None for other operations or disabled auto-linking, and [] for a computed empty
search. No new similarity query is introduced. Obsolete reads back saved state for a registered
after handler; restore reuses its existing read. A missing post-obsolete snapshot warns without
fabricating saved state. These reads are separate repository calls, not transaction-wide snapshots.
After handlers return PluginWarning or nothing. Exception, malformed return, or cooperative
timeout produces a sanitized diagnostic and a generic advisory warning in either mode; it cannot
veto or roll back the saved write. External cancellation propagates even after persistence, so a
cancelled request or lost response may leave a completed write. Cancellation raised inside an
after handler or its awaited child becomes advisory when the request task has no cancellation
pending. Before-save cancellation still propagates. There are no durable queues,
retries, delivery guarantees, duplicate prevention, merging, or link/entity hooks.
app/routes/write_plugin_responses.py combines nonempty-only before/after warnings. Create/update
shapes stay intact; lifecycle results use an internal success/warnings model, unwrapped to
{"success": true} plus optional warnings by live MCP/local CLI and REST DELETE. No REST restore
route is added. Stored/read memories and event payloads have no transient warnings. Before errors
remain WRITE_PLUGIN_REJECTED / WRITE_PLUGIN_UNAVAILABLE through MCP/CLI and 400/503 through REST.
REST DELETE validates supplied lifecycle field types before the service call, with or without a
plugin; absent-body defaults are preserved.
After failures return success with MEMORY_PLUGIN_AFTER_SAVE_UNAVAILABLE. The legacy unregistered
memory_tools.py unwraps lifecycle results to bool, without becoming a supported plugin transport.
CLI memory-save rendering shows warnings with success.
Bootstrap restores the core diagnostic logger and pre-initialization states of existing loggers for the configured module, every handler's defining module, and their children after Alembic's logger-disabling setup. Re-exports, partial handlers, and intentionally disabled loggers are preserved. Import errors identify module/reference, loading phase, and exception type. Runtime diagnostics identify phase, operation, exception type, and before-save mode, without exception text or memory snapshots. See the plugin contract for administrator examples.
Query: memory_service.py:77 asks the repository for
scored primary results, optionally expands one-hop links, deduplicates, and applies token/count
budgets. Project restrictions apply to primaries; linked memories use the same project filter only
when strict_project_filter is enabled. Budget allocation prioritizes primary results before links
(memory_service.py:767). Within each tier, the budget helper
sorts by importance (memory_service.py:844); the final response
is not an untouched vector-ranking list. Scores are returned for retained primaries.
The repositories embed the query and search active, user-owned memories with optional importance
and project filters. PostgreSQL uses pgvector cosine distance
(memory_repository.py:142); SQLite joins
memories to vec_memories and computes cosine distance
(memory_repository.py:151).
When reranking is enabled, they retrieve a larger candidate set and rerank when it exceeds k;
query_context enriches the rerank query, not the initial embedding query
(PostgreSQL:70,
SQLite:78).
When HYBRID_SEARCH_ENABLED is true, both backends also run a keyword leg (SQLite FTS5;
PostgreSQL tsvector + GIN via Alembic 20261103_memory_search_tsv), fuse the ranked id lists
with reciprocal rank fusion, then apply that same rerank pool. With the flag off, search stays
dense-only and MemoryScore omits keyword_rank / fusion_score.
Contracts, storage, and implementation variants
| Boundary | Implementations / inspection points |
|---|---|
| Domain persistence | MemoryRepository:21 and sibling files in app/protocols define service-facing contracts. Pydantic domain/request/result models live in app/models, separate from backend ORM tables. |
| PostgreSQL | PostgresDatabaseAdapter:18 owns async sessions, commit/rollback, initialization, and disposal. User sessions set app.current_user_id; repositories also apply user filters. Backend table definitions start at postgres_tables.py:26. |
| SQLite | SqliteDatabaseAdapter:46 owns file/in-memory connections and sessions, loads sqlite-vec, and creates vector virtual tables plus an FTS5 external-content index for hybrid keyword search. Repository queries enforce user ownership. Relational tables start at sqlite_tables.py:31. |
| Schema lifecycle | Both database adapters run Alembic during init_db; backend selection and migration execution live in alembic/env.py:1, with revisions in alembic/versions. Vector-storage initialization also has adapter-specific work. |
| Embeddings | EmbeddingsAdapter:6 defines generate_embedding. Implementations: local FastEmbed, Azure OpenAI, Google, OpenAI, and Ollama. Selection is explicit in bootstrap.py:27. |
| Reranking | RerankAdapter:13 has local FastEmbed cross-encoder and HTTP implementations. bootstrap.py:48 selects one or disables reranking. |
Memory/skill update embeddings and skill search reranking do not retain a borrowed database connection during provider waits. Skill description updates use a short owned-skill/project precheck, then embed, then re-fetch and recheck in the write transaction. Description and vector are saved atomically, including SQLite's separate vector table. Searches rerank detached summaries of the original candidates without refetching. Re-embedding search validation reads a title, embeds outside the session, then searches in a new session. These are connection-lifetime guarantees, not locking or full concurrency guarantees; the memory snapshot race described above still applies.
The two persistence backends implement the same broad contracts but use different SQL/vector mechanisms. This source review does not establish complete behavioral parity or transaction equivalence. Provider availability, model cache contents, and live database policy configuration were not exercised.
Other domain and operational components
These are explanatory groupings; they do not imply separate subsystems in the source tree.
| Group | Responsibilities and source anchors |
|---|---|
| Organization and entities | ProjectService:33 manages project metadata; EntityService:47 manages named entities, aliases, typed entity relationships, and links to memories/projects. Memory project membership is represented by project_ids associations. |
| Attached knowledge | DocumentService:40, CodeArtifactService:40, and optional FileService:40 manage long text, source snippets, and binary content. They use separate repository contracts and can be associated with memories. |
| Procedural knowledge | Optional SkillService:72 supports CRUD, semantic search, Markdown/frontmatter import/export, and links to memories/files/documents/code artifacts. Skill repositories receive the same provider adapters as memory repositories. |
| Planning | Optional PlanService:37 and TaskService:46 manage plans, task claims, criteria, and dependencies. transition_task:223 validates versions, state transitions, dependencies, and completion criteria; task completion can complete the parent plan. |
| Graph views | GraphService:73 combines repository traversal with domain-service lookups. get_subgraph:129 bounds depth/node count and asks MemoryRepository.get_subgraph_nodes for traversal results across supported object types. |
| Activity and usage | Optional EventBus:28 dispatches background handlers and per-user streams. ActivityService:24 persists and queries events; it remains queryable when event emission is disabled. Memory read/query events optionally update access counters via memory_service.py:895. |
| Re-embedding | ReEmbeddingService:40 coordinates full storage reset/batch embedding/validation and targeted rebuilds, using a memory contract and embedding adapter. main.py:153 is the operational CLI path. |
| Backup | BackupService:9 supplies the timestamp and delegates through BackupAdapter; DatabaseBackupAdapter:15 owns SQLite file copying and PostgreSQL pg_dump/psql. create_backup_service:19 connects them. |
Startup constructs ReEmbeddingService and supplies it to MCP handlers; handlers call its
validation and rebuild methods without accessing MemoryService.memory_repo.
Embedding interfaces live in app/protocols; shared text preparation lives in app/utils.
User repositories translate duplicate external IDs to ConflictError, which UserService
handles by fetching the existing user after the failed transaction has rolled back.
Activity handling is asynchronous and not part of the domain write transaction; it is not a durable queue.
Enforced import boundaries
The six contracts in pyproject.toml enforce these rules, including indirect imports:
| Source | Must not import |
|---|---|
| Models, protocols, events, utilities, settings, logging support, exceptions, version | Services, repositories, routes, bootstrap, authentication middleware/configuration, Memory/Plan Plugin loaders |
| Services | Repositories, routes, bootstrap, authentication middleware/configuration, Memory/Plan Plugin loaders |
| Repositories | Services, routes, bootstrap, authentication middleware/configuration, Memory/Plan Plugin loaders |
| Shared code above and services | sqlalchemy, openai, google, fastembed, httpx, ollama, subprocess, shutil |
| API/MCP routes, write response models, and authentication middleware | Repositories, bootstrap, or Memory/Plan Plugin loaders |
| CLI | Repositories, bootstrap, or Memory/Plan Plugin loaders, except the two startup imports below |
All Python files under app must be visible to the checker; a regression test verifies this.
Package markers are required, including for SQLite repositories, middleware, and utilities.
Bootstrap constructs implementations. The CLI has its own checked rule: only
app.routes.cli.local_executor and app.routes.cli.context may import bootstrap directly.
Other CLI modules may reach bootstrap through those startup imports, but may not import
repositories or bootstrap themselves. These exceptions belong only to the CLI rule;
API/MCP handlers still cannot reach bootstrap through CLI code.
Logging configuration may use app.middleware.logging_middleware as shared support.
Package initializers and generated version metadata are scanned; they are not extra application layers.
New source areas need an explicit decision about which rules apply.
main.py is a standalone startup/operational module, reviewed manually rather than scanned by
Import Linter; tests, migrations, and the evaluation harness are outside the production rules.
Static imports in functions, re-exports, and TYPE_CHECKING blocks are checked.
Dynamic imports, runtime attribute access, and arbitrary file/network operations are not checked;
review those in code review and cover behaviour with integration/E2E tests.
The external-library list is explicit, not a complete ban on every possible integration.
Run uv run lint-imports --no-cache for the rules alone, or
uv run pytest tests/architecture/ for the rules, source coverage, and deliberate-violation proofs.
The CI test job runs the latter; validation notes describe the proofs.
Tests and validation entry points
| Suite | What to inspect / run |
|---|---|
| Integration | tests/integration uses stubbed I/O for service workflows. Start at test_memory_service.py:16, test_bootstrap.py, and the scope, CLI, task, skill, graph, and event-bus tests. Run uv run pytest tests/integration/. |
| SQLite E2E | tests/e2e_sqlite exercises the stack with in-memory SQLite; conftest.py:157 builds the app and controls optional features. Run uv run pytest tests/e2e_sqlite/. |
| PostgreSQL E2E | tests/e2e exercises the PostgreSQL stack; conftest.py:265 manages the Docker database fixture. Run uv run pytest -m e2e with Docker available. |
| Agent walkthroughs | test_harness/walkthrough.py:128 orchestrates agent sessions; this is evaluation infrastructure, not a production request path. Generated run workspaces are excluded from the map. |
Backend-sensitive changes should exercise both relevant E2E suites; contract/business-rule changes
should first use the focused integration tests. Source links identify tests, not evidence that those
suites have passed for any particular revision. Repository lint command: uv tool run ruff check ..
Using the detailed map
The Mycelium map is supporting detail, not required reading in full. Do not load the entire file into context by default. It is a historical snapshot: the October 17 boundary changes moved embedding/backup types and rebuild wiring; use this overview and current source for those components.
Find the relevant declaration in the source index, reading that index in chunks if needed.
Search its diagram identifier for connections and read the relevant line ranges.
Expand to callers, contracts, alternative implementations, and tests as the task requires.
Check relevant warnings and filtering notices. Missing edges do not establish independence.
Verify important relationships against source; static call edges can be uncertain.
Useful IDs in this snapshot: c0016 bootstrap, c0276 main, c0240 ToolRegistry,
c0256 MemoryService, c0120 MemoryRepository, c0143 PostgreSQL memory repository,
c0171 SQLite memory repository, c0251 GraphService, and c0264 TaskService.
The source index begins at map line 4921;
relationships at 5233, warnings at
8246. IDs/positions can change on regeneration.
The map was freshly analyzed and exported using Mycelium 1.0.0 with
--max-classes 1000 --test-path tests --test-path test_harness/runs.
Repeating the export from the same map produced identical bytes. The output is nonempty and
contains one class diagram; it was checked as Markdown, without a rendered preview.
It contains 8,353 lines, 296 indexed boxes, 2,579 listed relationships,
and 106 extraction warnings. Test filtering removed 4,561 calls and 119 type relationships.
The box count is below the requested cap; full detail is not proof of complete extraction.
Warnings include unresolved or out-of-scope bases (Protocol, BaseModel, enums) and EventBus's
asyncio.Task binding. These mostly name third-party/builtin types, but the diagnostics do not reliably
classify the origin of every unresolved reference. A concrete heuristic mismatch: the map attributes TaskService.claim_task
calling _emit_event to PlanService; source calls its own handler at
task_service.py:336, defined at line 60.
Runtime registration, decorators, and dynamic attributes require source inspection even when edges exist.
This overview is selective and does not replace source inspection. This map excludes tests and
test_harness/runs, but includes harness implementation and some debug scripts. Inspect test sources
or request a test-inclusive export when needed. Neither the overview nor the map establishes gap-free coverage.
Maintenance
After major code or architecture changes, review the diagram and explanations and update them if needed. Mycelium is optional; a source-verified manual update is acceptable. Preserve reviewed explanations that remain accurate. Keep this overview at most 500 lines, with no column-width limit. If the generated backup is refreshed, use fresh analysis, keep its JSON outside the repository, and record exporter version/scope and material warnings. Recheck links and Mermaid rendering.
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