Skip to main content
Glama

A totem stands watch over what a tribe has learned. Totem does the same for a codebase. It's a Git-aware memory server for coding agents: decisions, invariants, and gotchas persist across sessions, backed by evidence, and flagged the moment the code underneath them changes.

Why

AI coding agents lose engineering context between sessions. They re-discover the same gotchas, re-debate the same decisions, and forget invariants that were already established. totem persists this knowledge locally and serves it back to agents as structured context, ordered by relevance.

Related MCP server: arcane

Install

Requires Python 3.13+.

npm install @emiliano-go/totem
npx @emiliano-go/totem

The npx command auto-installs or upgrades the Python MCP server, pins its version, and configures enforcement plugins for OpenCode, Claude Code, and Kimi Code. For Kimi Code it also registers a user-level MCP entry (~/.kimi-code/mcp.json) so totem is available in every project.

Supported agents

Agent

Hook type

Auto-configured?

OpenCode

tool.execute.before JS plugin

Yes

Claude Code

PreToolUse/PostToolUse hooks (~/.claude/settings.json)

Yes

Kimi Code

[[hooks]] in ~/.kimi-code/config.toml

Yes

Features

  • 14 memory types with type-specific metadata validation

  • 34 MCP tools (19 core + 15 typed wrappers)

  • Staleness detection via SHA256 content hashing on evidence

  • Conflict detection on overlapping evidence and contradictory claims

  • Full-text search via Turso FTS5

  • Hybrid memory (project + user databases)

  • Context assembly with scored pipeline and token budget

  • Agent enforcement blocks reads/grep/bash when memory exists, forces search-first workflow

  • Commit gates block all tools until agent registers file reads and writes

  • History audit on every create, update, and delete

How it works

Project and user memory flow into the context compiler, which hands the agent scored, provenance-aware context.

             ┌─────────────────┐
             │   User facts    │
             └────────┬────────┘
                      │
             ┌────────▼────────┐
             │     Project     │
             │      memory     │
             └────────┬────────┘
                      │
       ┌──────────────┼──────────────┐
       │              │              │
   evidence       relations     provenance
       │              │              │
       └──────────────┼──────────────┘
                      │
             ┌────────▼────────┐
             │ context compiler│
             └────────┬────────┘
                      │
             ┌────────▼────────┐
             │      agent      │
             └─────────────────┘
Agent reads file for the first time
  → commit-gate blocks → agent registers read → memory stored → done

Agent reads file again (memory exists)
  → blocked → redirected to memory tools
  → searches memory → finds context → done

Agent writes a file
  → commit-gate blocks → agent registers write with reason → change documented → done

Agent reads file but finds nothing in memory
  → allowed to read → commit-gate requires registration → done

Setup

OpenCode

Add to ~/.config/opencode/opencode.json (or let npx @emiliano-go/totem write it):

{
  "plugin": ["@emiliano-go/totem"],
  "mcp": {
    "totem": {
      "type": "local",
      "command": ["uvx", "totem-mcp==<version>"],
      "enabled": true
    }
  }
}

The installer pins <version> to the npm package version and pre-warms the uvx cache, so agent startups use the cached environment and never hit the network.

Claude Code

claude mcp add totem -- totem-mcp

Kimi Code

MCP server and hooks are auto-configured by npx @emiliano-go/totem: the MCP server goes in user-level ~/.kimi-code/mcp.json (every project), and the hooks go in ~/.kimi-code/config.toml.

Manual setup

If you prefer manual configuration:

# Initialize totem in your project
totem init

# For a different project
totem init --project /path/to/other

Quick start

MCP tools (from your agent)

# Store a decision
memory_create_tool(type="decision", title="Use FTS5 for search",
  statement="SQLite FTS5 is sufficient for our search needs",
  tags=["search", "sqlite"],
  metadata={"rationale": "No external dependency needed"})

# Get full context for a task
engineering_context_tool(tags=["api", "database"],
  current_task="Adding JWT refresh endpoint")

# Search memory
memory_search_tool(query="authentication", tags=["auth"])

# Store a command outcome
memory_create_tool(type="gotcha", title="uv pip install -e . works",
  statement="Editable install works with uv pip on PEP 668 systems",
  tags=["cmd:uv-pip-install", "python"])

CLI

# Create a memory item
totem create --type decision --title "Use FTS5 for search" \
  --statement "SQLite FTS5 is sufficient for our search needs" \
  --tags "search,sqlite" --metadata '{"rationale": "No external dependency needed"}'

# Search
totem search --query "FTS5" --tags "sqlite"

# Assemble context
totem context --tags "search,sqlite" --current-task "Implementing search" --budget 4096

# Export/import
totem export -o backup.json
totem import backup.json

Memory types

Type

Purpose

Required metadata

decision

A choice that was made

rationale (recommended)

invariant

A rule that must hold

verificationMethod, condition

gotcha

A non-obvious pitfall

(none)

rejected_idea

A proposal declined

proposal, reasonRejected

assumption

A claim with epistemic status

claimCategory, basis

open_question

An unresolved question

question, impact, blocking

ambiguity

An ambiguous requirement

question, interpretations, impact

contract

Observable behavior

subject

constraint

Implementation restriction

constraint

hypothesis

Plausible explanation

hypothesis

observation

Something seen in code

observation

bug

A defect with state machine

symptom, severity, state

architecture

Component mapping

component, responsibility

implementation

Codebase facts

subject, kind, path

MCP tools (34)

Tool

Description

totem_init_tool

Initialize totem for a project

memory_create_tool

Create a memory item (warns on duplicate title)

memory_get_tool

Retrieve by ID with staleness check

memory_update_tool

Update any field (provides audit trail)

memory_delete_tool

Soft-delete (requires reason)

memory_list_tool

Filtered listing with sort and type/tag filters

memory_recent_tool

List recently created memories

memory_tasks_tool

List in-progress task memories (task:*)

memory_commands_tool

List command outcomes (cmd:*)

memory_search_tool

FTS5 full-text search with type/tag filters

resolve_conflict_tool

Mark conflict as resolved

engineering_context_tool

Scored context assembly with task relevance

memory_export_tool

Export all memories as JSON

memory_import_tool

Import memories from JSON (skips duplicates)

memory_gc_tool

Purge terminal-state memories past retention (dry-run default)

memory_verify_tool

Record that a memory was verified (sets verified_at/commit, confidence 1.0)

memory_revalidate_tool

Void verifications whose evidence changed

register_file_read_tool

Store facts learned from reading a file (auto-hashes)

register_file_write_tool

Register file changes with reason (auto-hashes)

*_create (14)

Typed wrappers for each memory type

flag_ambiguity

Convenience wrapper for ambiguity creation

CLI commands (17)

Command

Description

totem init

Initialize totem and install agent instructions

totem create

Create a new memory item

totem get <ID>

Retrieve by ID

totem update <ID>

Update an item

totem delete <ID>

Soft-delete (requires --reason)

totem list

List with filters

totem recent

List recently created memories

totem tasks

List in-progress task memories

totem commands

List command outcomes

totem resolve <ID>

Mark conflict as resolved

totem search

Full-text search

totem export

Export memories as JSON

totem import <FILE>

Import memories from JSON

totem gc

Purge terminal-state memories past retention (--apply)

totem verify <ID>

Record that a memory was verified

totem revalidate

Void verifications whose evidence changed (--apply)

totem context

Assemble scored context

Context assembly

Scoring formula:

score = 0.30*tag_match + 0.20*task_similarity + 0.25*importance
      + 0.15*confidence + 0.10*recency

Invariants, constraints, and ambiguities get a 1.25x multiplier. Potentially stale items get a 0.5x penalty.

Output sections (BLOCKING AMBIGUITIES, CONFLICTS, and STALE WARNINGS are never budget-truncated):

  1. TASK (if provided)

  2. BLOCKING AMBIGUITIES

  3. CONTEXT CONFLICTS

  4. CRITICAL CONSTRAINTS

  5. CRITICAL INVARIANTS

  6. RELEVANT CONTRACTS

  7. ARCHITECTURE

  8. DECISIONS

  9. KNOWN AMBIGUITIES (non-blocking)

  10. OBSERVATIONS

  11. GOTCHAS

  12. KNOWN BUGS

  13. HYPOTHESES

  14. CODEBASE FACTS

  15. OPEN QUESTIONS

  16. REJECTED IDEAS

  17. STALE KNOWLEDGE WARNINGS

Workspace scoping

totem auto-detects your project root via git rev-parse --show-toplevel. Override with --project <path> on any CLI command or project parameter on any MCP tool.

Hybrid memory

  • Project memories: .totem/totem.db

  • User memories: ~/.local/share/totem/totem.db

engineering_context searches both, with project memories taking precedence.

Trust and provenance

asserted_by records who asserted a claim (user, test, source, git, doc, runtime, agent); it is not a verification signal. Each provenance sets a default confidence: test 0.95, user/source/git/doc 0.9, runtime 0.7, agent 0.6 (hypotheses cap at 0.4). Nothing reaches 1.0 by provenance alone. A user-asserted claim is trusted, not proven.

Verification is separate and explicit. memory_verify (totem verify <ID>) records that a claim was checked: it sets verified_at and verified_commit (HEAD by default), raises confidence to 1.0, and writes a history event; an optional verified_by relation links the verification artifact. A verification holds only while its evidence still matches (truth maintenance: evidence is the premise, the verification the derived belief). When evidence changes, the verification is retracted and confidence drops back to its provenance default; memory_get does this on read, and memory_revalidate (totem revalidate) scans for it. The enforcement hook clears its verify:<file> gate only when a fresh verification record exists.

Deployment boundary

Totem is a single-user, local memory layer. It has no tenancy or authorization model, and this is intentional:

  • the user DB lives at ~/.local/share/totem/totem.db, owned by the OS user that runs totem (override with TOTEM_USER_DB);

  • the project DB lives in the project's .totem/ directory, scoped to whoever can read the checkout;

  • MCP tools run with the full privileges of that user.

Do not expose a totem MCP server to multiple untrusted users on one host, and do not point several OS users at one shared user DB. If you need multi-user isolation, run one totem instance (and one user DB) per user. The boundary is enforced by the filesystem and the OS user, not by totem itself.

Tag conventions

  • task:<name>: In-progress work. Query with memory_tasks_tool.

  • cmd:<command>: Command outcomes. Query with memory_commands_tool.

  • architecture:<module>: Structural facts about a module.

  • outcome:<what>: Measurable results (performance wins, bug fix impact, etc.).

Companion skill

The skills/precision-first/ directory contains a precision-first software engineering methodology designed to pair with totem.

Development

# Run JS tests
cd plugins/totem-enforce && node test-tokenize.js

# Run Python package tests
uv run pytest

# Run Python hook tests
cd plugins/totem-enforce && python3 test-enforce.py

License

MIT

Available Tools

37 tools
ambiguity_createC

Create an ambiguity memory. impact: low/medium/high/critical. high/critical = blocking.

Inputs: tags (required), title (required), impact (required), question (required), +5 more. Returns: result

architecture_createC

Create an architecture memory for component structure mapping.

Inputs: tags (required), title (required), component (required), statement (required), +7 more. Returns: result

assumption_createD

Create an assumption memory. classify: fact/assumption/hypothesis/guarantee.

Inputs: tags (required), basis (required), title (required), statement (required), +4 more. Returns: result

bug_createC

Create a bug memory. State machine: open→confirmed→fixed→verified.

Inputs: tags (required), title (required), symptom (required), severity (required), +7 more. Returns: result

constraint_createC

Create a constraint memory for implementation restrictions.

Inputs: tags (required), title (required), statement (required), constraint (required), +4 more. Returns: result

contract_createC

Create a contract memory for observable behavior of functions/APIs.

Inputs: tags (required), title (required), subject (required), statement (required), +7 more. Returns: result

decision_createA

Create a decision memory. Always provide rationale explaining WHY.

Inputs: tags (required), title (required), rationale (required), statement (required), +3 more. Returns: result

engineering_context_toolB

Assemble engineering context with output ordering.

Pipeline: tag match -> score -> sort -> truncate -> serialize. Conflicts and warnings are NEVER dropped for budget.

Args: tags: Tags to match against task: Optional task description (shown in output header) token_budget: Optional token budget for truncation types: Filter by memory types include_stale: Whether to include potentially stale items current_task: Description of what you're working on right now. Boosts scoring for memories relevant to this task. paths: Filter items whose evidence matches these file paths project: Optional project root path. Auto-detected from git root if omitted.

Inputs: tags (required), task, paths, types, +4 more. Returns: result

flag_ambiguityC

Flag an ambiguity. Convenience wrapper for ambiguity_create. impact: low/medium/high/critical.

Inputs: tags (required), title (required), impact (required), question (required), +3 more. Returns: result

gotcha_createC

Create a gotcha memory for non-obvious behaviors.

Inputs: tags (required), title (required), statement (required), details, +2 more. Returns: result

hypothesis_createB

Create a hypothesis memory. Never auto-promote to invariant/decision.

Inputs: tags (required), title (required), statement (required), hypothesis (required), +6 more. Returns: result

implementation_createC

Create an implementation memory for codebase facts (API, function, module, type, config, schema).

Inputs: kind (required), path (required), tags (required), title (required), +8 more. Returns: result

invariant_createD

Create an invariant memory. Requires verificationMethod and condition.

Inputs: tags (required), title (required), condition (required), statement (required), +4 more. Returns: result

memory_commands_toolA

List command outcome memories (gotchas tagged with cmd:*).

Args: limit: Maximum items to return (default 20) project: Optional project root path. Auto-detected from git root if omitted.

Inputs: limit, project. Returns: result

memory_create_toolA

Create a new memory item.

Args: type: One of: decision, invariant, gotcha, rejected_idea, assumption, open_question, ambiguity, contract, constraint, hypothesis, observation, bug, architecture, implementation title: Short title for the memory statement: The factual claim being stored tags: At least one tag for categorization details: Optional additional details confidence: 0 to 1; derived from asserted_by when omitted (user 1.0, test 0.95, source/git/doc 0.9, runtime 0.7, agent 0.6; hypotheses cap at 0.4) importance: 0 to 1, default 0.5 evidence: List of evidence objects with path, startLine, endLine, contentHash related_memory_ids: IDs of related memory items metadata: Extra metadata. Decision items accept 'rationale' (strongly recommended: explain WHY this decision was made, alternatives considered). Invariant items require 'verificationMethod' and 'condition' asserted_by: Who established the claim: user, test, source, git, doc, runtime, agent (default agent) applicability: current, legacy, deprecated, planned (orthogonal to status) scope: user, project, path, task — or JSON {"kind": "...", "value": "..."} supersedes_id: ID of a memory this one replaces (marks it superseded) project: Optional project root path. Auto-detected from git root if omitted.

Inputs: tags (required), type (required), title (required), statement (required), +15 more. Returns: result

memory_delete_toolB

Soft-delete a memory item. Reason is required.

Args: id: The memory item ID reason: Required reason for deletion project: Optional project root path. Auto-detected from git root if omitted.

Inputs: id (required), reason (required), actor, project, +3 more. Returns: result

memory_export_toolA

Export all memories and conflicts as portable JSON.

Args: project: Optional project root path. Auto-detected from git root if omitted.

Inputs: project. Returns: result

memory_gc_toolA

Purge terminal-state memories older than a retention window.

Only superseded/invalidated/resolved items untouched for retention_days and not referenced by any relation are eligible. Defaults to dry-run.

Args: retention_days: Age threshold in days (default 90) dry_run: Report candidates without deleting (default True) project: Optional project root path. Auto-detected from git root if omitted.

Inputs: actor, dry_run, project, retention_days. Returns: result

memory_get_toolA

Retrieve a memory item by ID with staleness check.

Args: id: The memory item ID include_evidence: Whether to check evidence staleness (default True) project: Optional project root path. Auto-detected from git root if omitted.

Inputs: id (required), project, include_evidence. Returns: result

memory_history_toolC

Show the immutable timeline of a memory: created, updated fields, deleted.

Inputs: id (required), project. Returns: result

memory_import_toolA

Import memories from a previously exported dict. Skips duplicate IDs.

Args: data: The export dict containing 'items' and optionally 'conflicts' project: Optional project root path. Auto-detected from git root if omitted.

Inputs: data (required), project. Returns: result

memory_list_toolA

List memory items with optional filters.

Args: type: Filter by type (decision, invariant, gotcha, rejected_idea) tags: Filter by tags (items must have at least one) status: Filter by status (active, potentially_stale, invalidated) sort: Sort by 'created_at', 'updated_at' (default), or 'importance' limit: Maximum items to return (default 50) project: Optional project root path. Auto-detected from git root if omitted.

Inputs: sort, tags, type, limit, +2 more. Returns: result

memory_recent_toolA

List most recently created memories.

Args: limit: Maximum items to return (default 5) project: Optional project root path. Auto-detected from git root if omitted.

Inputs: limit, project. Returns: result

memory_relate_toolB

Create a typed relation between two memories.

Args: from_id: Source memory ID to_id: Target memory ID kind: supersedes, contradicts, invalidates, derived_from, verified_by, refines, depends_on (supersedes/invalidates update the target status) project: Optional project root path.

Inputs: kind (required), to_id (required), from_id (required), actor, +4 more. Returns: result

memory_relations_toolC

List the typed relations involving a memory.

Inputs: id (required), project. Returns: result

memory_revalidate_toolB

Void verifications whose evidence changed since they were made.

Args: dry_run: Report candidates without changing them (default True) project: Optional project root path. Auto-detected from git root if omitted.

Inputs: actor, dry_run, project. Returns: result

memory_search_toolA

Hybrid tag + full-text search.

Args: query: Search query (full-text via Turso FTS5) types: Filter by memory types tags: Filter by tags include_stale: Whether to include potentially stale items limit: Maximum results (default 20) project: Optional project root path. Auto-detected from git root if omitted.

Inputs: query (required), tags, limit, types, +2 more. Returns: result

memory_tasks_toolA

List in-progress task memories (tagged with task:*).

Args: limit: Maximum items to return (default 10) project: Optional project root path. Auto-detected from git root if omitted.

Inputs: limit, project. Returns: result

memory_update_toolA

Update a memory item. Reason is optional but strongly recommended.

Args: id: The memory item ID reason: Why this update was made (strongly recommended for audit trail; defaults to 'maintenance') title: New title statement: New statement details: New details tags: New tags status: New status (active, potentially_stale, invalidated, resolved, superseded) confidence: New confidence (0-1) importance: New importance (0-1) evidence: New evidence list metadata: New metadata project: Optional project root path. Auto-detected from git root if omitted.

Inputs: id (required), tags, actor, title, +12 more. Returns: result

memory_verify_toolB

Record that a memory was verified: sets verified_at and verified_commit.

Verification, not provenance, is what earns confidence 1.0.

Args: id: The memory item ID to mark verified method: How it was verified (stored in history) commit: Git commit verified at (defaults to HEAD) confidence: Confidence to set (default 1.0) verified_by_id: Optional memory ID holding the verification artifact project: Optional project root path. Auto-detected from git root if omitted.

Inputs: id (required), actor, commit, method, +6 more. Returns: result

observation_createC

Create an observation memory. Never auto-promote to invariant/decision.

Inputs: tags (required), title (required), statement (required), observation (required), +4 more. Returns: result

open_question_createC

Create an open question memory. impact: low/medium/high/critical.

Inputs: tags (required), title (required), impact (required), blocking (required), +5 more. Returns: result

register_file_read_toolA

Register facts learned from reading a file. Auto-hashes content, updates existing or creates new.

Call this after reading a file to store what you learned. Prevents re-reading the same file in future sessions.

Args: path: File path (e.g. 'src/auth.py') statement: What you learned (e.g. 'getUser() returns User | null, takes user_id: int') subject: What the fact is about (e.g. 'getUser()') kind: What kind of code fact (api/function/module/type/config/schema) tags: Tags for categorization start_line: Optional line range start (auto-detected if omitted) end_line: Optional line range end (auto-detected if omitted) title: Optional title (defaults to 'File: {filename}') details: Optional additional details symbol: Optional symbol the fact is about (e.g. 'UserService.authenticate'); makes evidence survive line moves project: Optional project root path. Auto-detected from git root if omitted.

Inputs: kind (required), path (required), tags (required), subject (required), +7 more. Returns: result

register_file_write_toolA

Register a file write/modification. Auto-hashes content, updates existing or creates new.

Call this after editing or writing a file to document what changed and why. The commit-gate hook will block all other tools until you register the write.

Args: path: File path (e.g. 'src/auth.py') statement: What changed (e.g. 'Added input validation to getUser()') reason: Why the change was made (e.g. 'Fix: getUser() crashed on null input') tags: Tags for categorization start_line: Optional line range start end_line: Optional line range end title: Optional title (defaults to 'File: {filename}') details: Optional additional details symbol: Optional symbol the change touches project: Optional project root path. Auto-detected from git root if omitted.

Inputs: path (required), tags (required), reason (required), statement (required), +6 more. Returns: result

rejected_idea_createB

Create a rejected idea memory. Prevents re-proposing dead ends.

Inputs: tags (required), title (required), proposal (required), statement (required), +4 more. Returns: result

resolve_conflict_toolC

Mark a conflict as resolved.

Args: conflict_id: The conflict ID resolution: Description of how the conflict was resolved (e.g. 'Kept existing: X') project: Optional project root path. Auto-detected from git root if omitted.

Inputs: resolution (required), conflict_id (required), actor, project, +3 more. Returns: result

totem_init_toolA

Initialize totem for a project. Creates .totem/ directory and DB if missing.

Args: project: Optional project root path. Auto-detected from git root if omitted.

Inputs: project. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    C2.4/5.0

    Scored across 37 tools

    Disambiguation2/5

    There is heavy overlap between the generic memory_create_tool (with a 'type' parameter covering 14 types) and 14 dedicated typed creates (decision_create, invariant_create, bug_create, etc.), plus flag_ambiguity is explicitly a 'convenience wrapper' for ambiguity_create. Several list tools (memory_list_tool, memory_recent_tool, memory_tasks_tool, memory_commands_tool, memory_search_tool) blur into filtered views of the same data, and memory_relate_tool vs memory_relations_tool are easy to confuse.

    Naming Consistency2/5

    Conventions are mixed: some tools use noun_verb_tool (memory_get_tool), some verb_noun_tool (register_file_read_tool, resolve_conflict_tool), and the typed creates use noun_verb with no suffix at all (decision_create, bug_create). The '_tool' suffix is applied inconsistently (flag_ambiguity has none, ambiguity_create has none), making the set unpredictable.

    Tool Count2/5

    37 tools is well above the healthy 3-15 range and past the 25+ threshold, largely because 14 near-duplicate typed create tools sit alongside a generic memory_create_tool. Many of these could be collapsed into the typed create or a single parameterized operation, making the surface feel bloated.

    Completeness4/5

    Coverage is broad: create/get/update/delete, search, filtered lists, verify, revalidate, relations, history, export/import, gc, conflict resolution, file registration, and init are all present. Minor gaps remain (no dedicated conflict-listing or bulk operations), but core lifecycle and CRUD are well covered.

    Maintenance

    ActivitySlowing
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Gives AI coding agents persistent, evolving knowledge about a codebase, enabling them to store and retrieve observations about architecture, conventions, gotchas, and recent work context.
      10
      20 npm
      3
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Provides persistent, searchable memory and knowledge capture for AI-assisted development, enabling agents to retain decisions, bugs, and patterns across sessions and projects.
      53 PyPI
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables MCP agents to maintain durable, evidence-aware project knowledge, retrieve precise excerpts on demand, and track decisions, conflicts, and revisions across sessions.
      1
      Apache 2.0
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI coding agents to persist and retrieve durable project knowledge across coding sessions, capturing decisions, conventions, lessons and reusable skills through ordinary chat requests. It supports searching, editing and reviewing saved items, and promoting local notes into Git-shareable versioned knowledge alongside repository changes.
      205 npm
      1
      MIT