Skip to main content

A memory system for LLM multi-agent pipelines. Relationship-shaped memory topology across per-agent minds.

Project description

obsess

A memory system for LLM multi-agent pipelines. Plug-and-play LLM providers (llama.cpp, Ollama, Anthropic, OpenAI-compatible, Gemini), plug-and-play storage (in-memory, SQLite, or your own), and a memory model that treats agent relationships as first-class: siblings share differently than peers, a master and a prodigy share differently than parent and child, a team's failure is not any individual's failure.

Standard multi-agent memory puts everything in one store and lets every agent read from it. obsess doesn't. Memory is utility-gated (only content that matches an active obsession is encoded), compressed into impressions (regenerated through the current frame at retrieval), and distinguishes trauma (verbatim, self-surfacing, failure-linked) from regular recall. When multiple agents are in play, relationships shape what flows between them: obsessions inherit through parent/child edges, warnings propagate across peers, team failures live in pools.


Install

pip install obsess

# Or with LLM providers you use:
pip install "obsess[anthropic]"           # Claude
pip install "obsess[llamacpp]"            # Local GGUF
pip install "obsess[openai]"              # OpenAI + compatible (DeepSeek, Mistral, Groq, ...)
pip install "obsess[all-providers]"       # Everything

# With semantic embeddings (optional; HashEmbedder works with no deps):
pip install "obsess[embeddings]"

From source:

git clone https://github.com/djwarf/obsess
cd obsess
pip install -e ".[all]"

Quickstart

from obsess import Population
from obsess.types import SeedType

pop = Population.new()                    # in-memory; swap storage with SQLiteStorage(path)
agent = pop.spawn("assistant")

# What this agent cares about — the encoding gate
agent.seed_obsession(
    domain="code_quality",
    description="write clean readable tested code",
    seed_types=[SeedType.NEED_FOR_SUCCESS],
    commitment=0.8,
)

# Ingest — only gate-clearing content is encoded
agent.ingest("I just fixed a null check in the auth handler.")    # stored
agent.ingest("Taylor Swift released a new album today.")          # dropped

# Retrieve — synthesized through the current frame
result = agent.query("What do I know about the auth handler?")
print(result.answer)

See examples/ for multi-agent scenarios, pools, persistence, and real-LLM integration.


Why obsess

Standard RAG obsess
Everything embeds, sorts at retrieval Gate at encode: most content is not stored
Chunks are stored verbatim Impressions are compressed through the current frame
Retrieval is playback Retrieval is regeneration through the current frame
Failure is just more text Trauma is a separate encoding class — verbatim, self-surfacing, immune to narrative rewriting
Multi-agent = shared store, everyone reads Multi-agent = typed relationships, sharing rules per kind, non-transitive
Memory is static Relationship topology shapes what flows across agents

Provider selection

The semantic layer (scoring, impression formation, regeneration) lives in one place; swapping LLM backends is a drop-in change.

from obsess import Population, ProviderSemantics

# Local GGUF via llama.cpp (Qwen3, Gemma, Llama, Mistral, ...)
from obsess.providers import LlamaCppProvider
llm = ProviderSemantics(LlamaCppProvider("/path/to/model.gguf"))

# Anthropic (Claude)
from obsess.providers import AnthropicProvider
llm = ProviderSemantics(AnthropicProvider(model="claude-sonnet-4-6"))

# OpenAI — and DeepSeek, Mistral, Groq, Together, xAI, Fireworks via the same class
from obsess.providers import OpenAICompatibleProvider
llm = ProviderSemantics(OpenAICompatibleProvider(
    model="deepseek-chat",
    base_url="https://api.deepseek.com/v1",
    api_key="...",
    strict_schema=False,  # DeepSeek doesn't do strict JSON schema yet
))

# Google Gemini
from obsess.providers import GeminiProvider
llm = ProviderSemantics(GeminiProvider(model="gemini-2.5-flash"))

# Ollama
from obsess.providers import OllamaProvider
llm = ProviderSemantics(OllamaProvider(model="qwen3:4b"))

pop = Population.new()
agent = pop.spawn("assistant", llm=llm)

Writing a new provider is ~50 lines implementing the Provider protocol. See obsess/providers/.


Storage selection

from obsess import Population
from obsess.storage.sqlite import SQLiteStorage

# In-memory (default; transient)
pop = Population.new()

# SQLite (persistent across sessions)
pop = Population.new(storage=SQLiteStorage("obsess.db"))

# Rehydrate agents from a prior session
for agent_id in pop.agent_ids_on_record():
    pop.rehydrate_agent(agent_id)          # pass llm= if needed

Custom backends (Postgres, Redis, DynamoDB, ...) implement the Storage protocol. See obsess/storage/.


Multi-agent: relationships and pools

from obsess import Population, ObsessionSpec, RelationshipKind
from obsess.types import SeedType

pop = Population.new()

# A shared obsession both agents can activate against
code_quality = pop.shared_obsessions.define(
    domain="code_quality",
    description="write clean readable tested code",
)

master = pop.creator.propose("master", [ObsessionSpec(
    shared_definition_id=code_quality.id,
    seed_types=[SeedType.DELIBERATE_STUDY],
    commitment=0.9,
)]).agent

prodigy = pop.spawn("prodigy")

# Prodigy inherits the master's obsession with bootstrapped commitment
pop.form_relationship(RelationshipKind.MASTER_PRODIGY, "master", "prodigy")
assert prodigy.obsessions.get(code_quality.id) is not None

# When master records a failure, prodigy sees it via trauma propagation
master.record_failure(
    context="missed a null check in review",
    failure="production bug shipped",
    attempted_solutions=["manual review"],
    cost="hotfix + postmortem",
    unsolvable_at_time=True,
    linked_obsession_id=code_quality.id,
)

# Prodigy encounters similar context — master's warning fires, rendered through
# prodigy's current frame
r = prodigy.ingest("About to review a PR for null safety.")
for surfaced in r.trauma_warnings:
    print(f"[{surfaced.access.value}] {surfaced.rendered_text}")

Four relationship kinds:

  • TEAM — pool formation, warning-share both directions.
  • PEER — visibility-granting, no-share by default.
  • PARENT_CHILD — directional, non-decaying, obsessions inherit attenuated.
  • MASTER_PRODIGY — directional, decaying, prodigy bootstraps to master's level.

See DESIGN-MULTI.md for the full relationship model.


Integrating with agent frameworks

obsess is framework-neutral — it provides memory state; your framework provides the reasoning loop. See docs/INTEGRATIONS.md for patterns with LangChain, the Claude Agent SDK, and raw tool-loop agents.

The core pattern is a sandwich around each LLM call:

# Before the LLM call
ingest_result = agent.ingest(observation)
warnings = [st.rendered_text for st in ingest_result.trauma_warnings]

# Augment the prompt
prompt = (
    f"{user_message}\n\n"
    f"Memory warnings: {warnings}" if warnings else user_message
)

# Your framework's call
response = my_framework.chat(prompt)

# After — flag failures explicitly if you detect one
if detected_failure:
    agent.record_failure(context=..., failure=..., ...)

Documentation

  • DESIGN.md — per-agent memory architecture (utility gate, impressions, trauma, obsessions).
  • DESIGN-MULTI.md — multi-agent model: ownership modes, relationship kinds, pools, propagation, render layer.
  • DESIGN-META.md — meta-layer: Creator, Evolution selection, Bonding.
  • docs/INTEGRATIONS.md — plugging obsess into common agent frameworks.
  • examples/ — runnable scenarios.

Status

Alpha. The architecture is complete and tested (61 tests). The API may evolve with real-world use. Feedback welcome.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

obsess-0.1.0.tar.gz (56.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

obsess-0.1.0-py3-none-any.whl (51.5 kB view details)

Uploaded Python 3

File details

Details for the file obsess-0.1.0.tar.gz.

File metadata

  • Download URL: obsess-0.1.0.tar.gz
  • Upload date:
  • Size: 56.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for obsess-0.1.0.tar.gz
Algorithm Hash digest
SHA256 6eee34006244a9f62f114d10194f5238c198fc81c043efa2fcd3031b6fbef29f
MD5 16e57ba1fb77d7ff509e83591527512c
BLAKE2b-256 005ef5d5b6b8d34248a60c3a0cc512de1e52c67d96280ff8e44b9f59ec7ff84a

See more details on using hashes here.

Provenance

The following attestation bundles were made for obsess-0.1.0.tar.gz:

Publisher: publish.yml on Djwarf/obsess

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file obsess-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: obsess-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 51.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for obsess-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 97a161af721d99317079612b0ab3f04b423974e7d7072dde17ac18f29a37fee5
MD5 e3b93687a19794581a445d441c6a35bb
BLAKE2b-256 e629d4853066cf75da49431a2d1cc4358e78446fda5652edf2cb5e890223232b

See more details on using hashes here.

Provenance

The following attestation bundles were made for obsess-0.1.0-py3-none-any.whl:

Publisher: publish.yml on Djwarf/obsess

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page