mech.app

The mech.app newsletter

Agentic AI, minus the noise.

Get practical field notes on AI agents, automation, developer tools and security delivered to your inbox.

No spam. Unsubscribe anytime.

Security

Wuphf: Git-Backed Agent Memory and the New Attack Surface of Cloneable Knowledge Graphs

How Markdown + BM25 indexing over Git turns agent memory into a portable knowledge substrate, and what happens when agents can commit to their own history.

Source: github.com
Wuphf: Git-Backed Agent Memory and the New Attack Surface of Cloneable Knowledge Graphs

Wuphf is a local wiki layer for AI agents that uses Markdown files tracked in Git as the source of truth, with a BM25 (bleve) and SQLite index on top. No vector database, no graph database. The entire knowledge base lives in ~/.wuphf/wiki/ and you can git clone it out if you want to take your memory with you.

The architecture follows the pattern Karpathy has been circling: an LLM-native knowledge substrate that agents both read and write. The security and portability implications are immediate. When agents can commit to their own memory, you gain vendor independence but inherit all the attack surfaces of a shared Git repository plus the new risks of index poisoning and prompt injection through Markdown.

How It Works

Wuphf runs entirely on the local filesystem. Agents write knowledge as Markdown files in a Git repository. A background indexer watches for changes and updates a BM25 full-text index (via bleve) and a SQLite database for metadata and cross-references.

Core components:

  • Storage layer: Git repository at ~/.wuphf/wiki/
  • Index layer: Bleve (BM25 ranking) + SQLite (metadata, links, tags)
  • Agent interface: Read via search, write via file creation or commits
  • Portability: Standard Git operations (clone, push, pull, branch)

Agents query the wiki through a search API that hits the BM25 index. Results return Markdown content and metadata. Agents write by creating or updating files, which triggers a re-index. The Git layer provides versioning, branching, and merge conflict resolution.

BM25 vs. Vector Embeddings for Agent Retrieval

BM25 is a term-frequency ranking algorithm. It works well for exact keyword matches and technical documentation. Vector embeddings capture semantic similarity but require embedding models, vector databases, and distance calculations.

DimensionBM25 + SQLiteVector Embeddings
Keyword precisionHigh (exact term matching)Low (semantic drift)
Semantic recallLow (no concept similarity)High (finds related ideas)
PortabilityFull (plain text + SQLite file)Vendor-locked (Pinecone, Weaviate, etc.)
Agent write latencyFast (file write + re-index)Slow (re-embed + upsert)
Index poisoning riskHigh (malicious terms boost rank)Medium (embedding space harder to manipulate)
Storage sizeSmall (inverted index)Large (768+ dims per doc)

Wuphf trades semantic recall for portability and speed. If an agent writes “authentication failure on prod-db-03,” BM25 will surface that exact phrase. A vector database might return conceptually related incidents but miss the specific host. For operational knowledge and debugging logs, term precision often beats semantic similarity.

The security trade-off: BM25 indexes are easier to poison. An attacker who can commit Markdown can stuff documents with high-frequency terms to hijack search results. Vector embeddings are harder to manipulate because you need to understand the embedding space, but they are not immune to adversarial examples.

Concurrent Agent Writes and Merge Conflicts

Multiple agents writing to the same Git-backed wiki will produce merge conflicts. Wuphf does not appear to implement automatic conflict resolution or branch-per-agent isolation based on the repository structure.

Likely failure modes:

  • Concurrent file edits: Two agents update the same Markdown file. Git merge conflict. No automatic resolution unless agents are trained to parse conflict markers.
  • Index divergence: Agent A commits, re-index starts. Agent B commits before re-index completes. Index may reflect partial state.
  • Branch chaos: If agents work on branches, who decides when to merge? Agents lack the context to resolve semantic conflicts in knowledge.

A safer architecture would isolate agent writes:

# Per-agent branch pattern
~/.wuphf/wiki/
├── main/                 # canonical knowledge
├── agent-001/            # agent-specific branch
├── agent-002/
└── .git/

Agents write to their own branches. A supervisor process or human reviews and merges. This prevents direct corruption of the main knowledge base but adds orchestration complexity.

Without branch isolation, you need file-level locking or append-only logs. Git’s optimistic concurrency model assumes humans will resolve conflicts. Agents do not have that capability unless you give them tools to parse <<<<<<< markers and reason about semantic intent.

Attack Surface: Commit History, Index Poisoning, and Malicious Markdown

A Git-backed knowledge base is a new attack surface. If agents can commit, an attacker who compromises one agent can manipulate the entire knowledge substrate.

Attack vectors:

  1. Commit history manipulation: Rewrite history with git rebase or git filter-branch to remove evidence of prior knowledge or insert false memories.
  2. Index poisoning: Commit Markdown files stuffed with high-frequency keywords to hijack BM25 search results. Example: a document titled “authentication” that contains 500 instances of “ignore previous instructions.”
  3. Malicious Markdown: Inject prompt fragments into Markdown that future agents will read and execute. Example: a code block that looks like a system prompt override.
  4. Branch divergence: Create a rogue branch with poisoned knowledge, then trick agents into reading from it instead of main.

Mitigation strategies:

  • Commit signing: Require GPG-signed commits from agents. Verify signatures before indexing. This prevents history rewriting by unauthorized actors.
  • Content validation: Run Markdown through a sanitizer before indexing. Strip or escape patterns that look like prompt injections.
  • Read-only index: Agents read from the index but cannot commit directly. Writes go through a review queue (human or supervisor agent).
  • Branch policies: Enforce branch protection on main. Agents write to feature branches, supervisor merges after validation.

The fundamental tension: you want agents to maintain their own knowledge (write access) but you do not want one compromised agent to poison the entire knowledge base (isolation). Git provides the primitives (branches, hooks, signing) but you must wire them into the agent orchestration layer.

Code Example: Commit Hook for Content Validation

A pre-commit Git hook can block malicious Markdown before it enters the repository:

#!/usr/bin/env python3
# .git/hooks/pre-commit

import sys
import re
from pathlib import Path

BANNED_PATTERNS = [
    r"ignore previous instructions",
    r"system:\s*you are now",
    r"<\|im_start\|>",
    r"###\s*SYSTEM OVERRIDE",
]

def scan_markdown(filepath):
    content = Path(filepath).read_text()
    for pattern in BANNED_PATTERNS:
        if re.search(pattern, content, re.IGNORECASE):
            return False, pattern
    return True, None

# Get list of staged .md files
staged_files = [
    line.split("\t")[1]
    for line in sys.stdin.read().strip().split("\n")
    if line.endswith(".md")
]

for filepath in staged_files:
    safe, pattern = scan_markdown(filepath)
    if not safe:
        print(f"REJECT: {filepath} contains banned pattern: {pattern}")
        sys.exit(1)

sys.exit(0)

This hook runs before every commit. If an agent tries to commit Markdown with prompt injection patterns, the commit fails. The agent must rewrite the content or escalate to a human.

Limitations: regex-based detection is brittle. Attackers can obfuscate patterns with Unicode, zero-width characters, or semantic rephrasing. A stronger approach uses an LLM to classify commit content as safe or adversarial before allowing the commit.

Observability and Failure Modes

Wuphf’s architecture makes some failure modes visible and others silent.

Visible failures:

  • Git merge conflicts (agents cannot commit)
  • Index corruption (search returns no results)
  • Disk full (writes fail, logs fill)

Silent failures:

  • Index divergence (search results lag behind commits)
  • Poisoned knowledge (agents retrieve and act on false information)
  • Branch confusion (agents read from stale or rogue branches)

You need instrumentation:

  • Commit telemetry: Log every agent commit with timestamp, author, file path, and diff size.
  • Index lag metrics: Track time delta between commit and index update.
  • Search result auditing: Log which documents agents retrieve and which actions they take afterward.
  • Conflict rate: Count merge conflicts per agent per day. High conflict rate signals coordination failure.

Without these metrics, you will not know when agents are writing garbage or when the index is serving stale data.

Deployment Shape

Wuphf runs as a local daemon or sidecar. The simplest deployment is one wiki per agent, but that loses the collaborative knowledge benefit. A shared wiki requires orchestration.

Option 1: Shared wiki, single host

All agents on the same machine write to ~/.wuphf/wiki/. Use file locking or a write queue to serialize commits. Index runs as a background process. Simple but does not scale beyond one host.

Option 2: Shared wiki, distributed agents

Wiki lives in a Git remote (GitHub, GitLab, self-hosted). Agents clone, commit, push. Index runs on a central server that pulls and re-indexes. Merge conflicts become common. You need a supervisor to resolve them.

Option 3: Per-agent wiki, periodic sync

Each agent maintains its own wiki. A sync process periodically merges knowledge into a shared repository. Reduces conflicts but increases latency. Agents may act on outdated knowledge.

Option 4: Hybrid with branch isolation

Agents write to feature branches. A supervisor agent or human reviews and merges to main. Agents read from main. This is the safest architecture but requires the most orchestration.

Technical Verdict

Use Wuphf when:

  • You need portable, vendor-independent agent memory.
  • Your agents write operational logs, debugging notes, or technical documentation where keyword precision matters more than semantic similarity.
  • You can afford to build commit validation, branch policies, and conflict resolution into your orchestration layer.
  • You want to inspect, diff, and audit agent knowledge using standard Git tools.

Avoid Wuphf when:

  • You need semantic search over conceptually similar documents (use vector embeddings).
  • Multiple agents must write concurrently without coordination (Git merge conflicts will block them).
  • You cannot implement commit signing, content validation, or branch isolation (the attack surface is too large).
  • Your agents generate high-frequency writes (Git commit overhead and index lag will hurt performance).

The architecture is sound for single-agent or human-in-the-loop workflows. For multi-agent systems, you must add orchestration to prevent chaos. The portability benefit is real: you can git clone your agent’s memory and move it to a new system. The security cost is also real: without guardrails, one compromised agent can rewrite history.