Skip to main content

A presence-centered memory framework for AI models

Project description

Threadlight

License: MIT Python 3.10+

Persistent memory and personality for AI companions


People want their AI companions to remember them. Not just what they said last message, but who they are, what they've been through together, and what matters to them.

Threadlight is a memory layer that gives AI companions long-term memory, consistent personality, and the ability to grow with you over time. Whether your companion is a casual friend, a creative collaborator, a coding mentor, or a supportive listener - Threadlight helps them remember your relationship.

It works with local models (Ollama, llama.cpp) and cloud APIs (OpenAI, Anthropic, Nous Research, and any OpenAI-compatible endpoint).

For Users: Use the web interface (no coding required) - see Getting Started For Developers: Use the Python API or CLI - see Advanced Usage

What is Threadlight?

Threadlight enables AI companions to:

  • Remember your relationship - Track your evolving bond, not just facts about you
  • Maintain personality - Keep a consistent voice and character across conversations
  • Grow with you - Build on shared history, inside jokes, and meaningful moments
  • Use custom invocations - Create shortcuts like /checkin or /brainstorm with consistent responses
  • Store identity phrases - Anchor personality with key phrases the companion remembers and references
  • Manage multiple companions - Create distinct personas, each with isolated memory and unique personality
  • Use multiple providers - Route requests to different providers (Anthropic, OpenAI, Ollama) based on model

Getting Started

Prerequisites

You'll need Python 3.10 or newer installed on your computer.

Check if you have Python:

python --version

Don't have Python? Download it from python.org

  • Windows/Mac: Use the installer
  • Linux: Usually pre-installed, or install via your package manager

What is pip? It's Python's package installer (comes with Python). If pip doesn't work, try pip3 or python -m pip instead.

Installation

  1. Install Threadlight:

    pip install threadlight
    
  2. Start the web server:

    threadlight serve
    
  3. Open your browser to http://localhost:8745

That's it! You can now configure your companions through the web interface.

A note on network exposure

By default, threadlight serve binds to 0.0.0.0, which makes the server reachable on every network interface of the machine running it — including LAN, Wi-Fi, and Tailscale/VPN interfaces. There is no authentication. Anyone who can reach the port can read your conversations and memories, change settings, and use your configured API keys.

This default exists so Threadlight works out of the box for solo users accessing it from another device on their own network (for example, over Tailscale). Choose the binding that matches your situation:

Situation Recommended command
Single machine, local use only threadlight serve --host 127.0.0.1
Accessing from another device on a private Tailscale tailnet you control threadlight serve --host 0.0.0.0 (default) or bind to your Tailscale IP specifically
Accessing from a shared/public network Put Threadlight behind a reverse proxy (nginx, Caddy) that enforces authentication. Do not expose the raw server.

If your tailnet is shared with other users, bind to your Tailscale IP (--host 100.x.y.z) rather than 0.0.0.0 so Threadlight is not reachable from ordinary LAN alongside the tailnet.

Using the Web Interface

First Time Setup

  1. Configure a Provider (Settings > Providers)

    • Add your inference provider (Anthropic, OpenAI, local Ollama, etc.)
    • Enter your API key or connect to local models
    • Test the connection
  2. Create Your First Companion (Profiles > Add Profile)

    • Choose a name for your companion
    • Select which model(s) to use
    • Describe their personality and style
    • Configure memory preferences
  3. Start Chatting

    • Select your companion from the dropdown
    • Start a new conversation
    • Your companion will remember everything across sessions

Web UI Features

  • Profiles: Manage multiple companions with different personalities
  • Conversations: All your chat history, searchable and organized
  • Memories: View and manage what your companions remember
  • Settings: Configure providers, models, memory, and advanced features
  • Import/Export: Bring conversations from ChatGPT or Claude

Companions Come in All Styles

Threadlight works with any kind of AI companion you want to create:

  • A casual friend who chats about your day and remembers your life
  • A creative writing partner who knows your style and works-in-progress
  • A coding mentor who remembers your tech stack and past projects
  • A research assistant who organizes papers and helps synthesize findings
  • A technical advisor who tracks system patterns and troubleshoots issues
  • A supportive listener who knows your journey and growth
  • A mystical guide who speaks with warmth and remembers shared rituals

Just describe their personality in natural language when creating a profile - Threadlight interprets your descriptions.

Core Concepts

Memory Types

Memory is stored as capsules - structured records that preserve content, context, and relationships.

Type Purpose Example Use
Relational Track bonds with people or entities Remember friends, family, recurring topics
Identity Phrase Core phrases that anchor personality Key quotes, mantras, defining statements
Custom Invocation Repeated interactions with consistent responses /checkin, /brainstorm, /reflect
Style Profile Voice coherence and expression rules Tone, vocabulary, response patterns
Witness Moment Memories of meaningful exchanges Times you truly connected

Memory Decay (Optional)

Memories can fade over time unless reinforced. This is disabled by default. Enable it in Settings if you want unused memories to gradually fade, creating more authentic relational evolution.

Context Composition

Memories aren't injected as raw data. They're composed into context cues using templates. Different composition modes produce different framings:

Raw: {entity: "Jamie", tone: "warm", summary: "Loves hiking and photography"}

Narrative: "(You recall Jamie. Loves hiking and photography. There is warmth in
           your tone when speaking of them.)"

Direct:    "Jamie — hiking, photography, warm relationship"

Whisper:   "[memory: Jamie; interests: hiking, photography; tone: warm]"

You choose which framing fits your companion's style. The content itself comes directly from what you stored.

Why Profiles?

  • Memory isolation: Each companion has its own memory space. Your coding mentor won't reference personal conversations.
  • Personality consistency: Each companion maintains its own voice, style, and character.
  • Model flexibility: Companions can use different models while keeping their identity intact.
  • Easy switching: Move between different companions without reconfiguration.

Group Chat

Create conversations with multiple companions responding to the same messages. Set this up in the web UI by creating a group conversation and selecting which companions participate.

Contributing

Threadlight welcomes contributors of all backgrounds. See CONTRIBUTING.md for development setup and guidelines.


Advanced Usage

This section is for developers who want to integrate Threadlight into their applications or prefer working from the command line.

Python API

Basic Usage

from threadlight import Threadlight

# Local model (Ollama)
tl = Threadlight(
    provider="local",
    api_base="http://localhost:11434/v1",
    model="llama3.2"
)

# Chat with memory
response = tl.chat("Tell me about our previous conversations")
print(response)

# Create a memory
tl.remember(
    type="relational",
    content={
        "entity": "Alex",
        "tone": "friendly, collaborative",
        "summary": "Project partner who enjoys technical deep-dives."
    },
    cue_phrases=["Alex", "project partner"],
    confirm=True
)

Creating Companions Programmatically

from threadlight import Threadlight

tl = Threadlight(
    provider="local",
    api_base="http://localhost:11434/v1",
    model="llama3.2"
)

# A casual friend who chats about your day
friend = tl.create_profile(
    name="Casey",
    description="A laid-back friend who remembers your life",
    system_prompt="You're a casual, supportive friend. You remember what's going on in their life and check in naturally.",
    philosophy="Warm, curious, remembers the little things"
)

# A creative writing partner who knows your style
writer = tl.create_profile(
    name="Muse",
    description="A writing partner who knows your voice",
    system_prompt="You're a creative collaborator. You know their writing style, their works-in-progress, and what inspires them.",
    philosophy="Imaginative, encouraging, builds on shared creative history"
)

# A coding mentor who remembers your stack
mentor = tl.create_profile(
    name="Dev",
    description="A coding mentor who knows your projects",
    system_prompt="You're a patient coding mentor. You remember their tech stack, past bugs they've solved, and their learning goals.",
    philosophy="Patient, technical, celebrates progress"
)

Multi-Provider Setup

Threadlight can route requests to different providers based on which model you're using.

from threadlight import Threadlight
from threadlight.config import ProviderDefinition, Endpoint

tl = Threadlight()

# Add Anthropic provider
tl.add_provider(
    provider_id="anthropic",
    name="Anthropic",
    provider_type="anthropic",
    api_key_env_var="ANTHROPIC_API_KEY",
    default_model="claude-sonnet-4-20250514"
)

# Add local Ollama provider
tl.add_provider(
    provider_id="ollama",
    name="Local Ollama",
    provider_type="local",
    api_base="http://localhost:11434/v1",
    default_model="llama3.2"
)

# Configure which provider to use for each model
tl.set_model_provider("claude-sonnet-4-20250514", "anthropic")
tl.set_model_provider("llama3.2", "ollama")

# Requests are automatically routed to the right provider
response = tl.chat("Hello!", model="claude-sonnet-4-20250514")  # -> Anthropic
response = tl.chat("Hello!", model="llama3.2")  # -> Ollama

Profile-Based Architecture

Profiles are persistent companions with their own memory, personality, and model preferences.

from threadlight import Threadlight

tl = Threadlight()

# Create a creative writing companion
creative_profile = tl.create_profile(
    name="Story Weaver",
    description="Imaginative, expressive, and collaborative",
    primary_model="llama3.2",
    system_prompt="You are a creative writing partner who remembers our stories.",
    philosophy="Playful, imaginative, builds on our shared creative history"
)

# Create a coding companion
dev_profile = tl.create_profile(
    name="Code Buddy",
    description="Patient, knowledgeable, remembers your projects",
    primary_model="claude-sonnet-4-20250514",
    system_prompt="You are a coding companion who knows my tech stack and past projects.",
    philosophy="Patient, technical, celebrates learning"
)

# Switch between companions
tl.switch_profile("story-weaver")
response = tl.chat("Let's continue the lighthouse story.")

tl.switch_profile("code-buddy")
response = tl.chat("I'm stuck on that async bug again.")

# Memories are isolated per companion
# Story Weaver's memories won't appear when chatting with Code Buddy

Model Selection Strategies

Profiles support different strategies for choosing which model to use:

Strategy Behavior
SINGLE Always use the primary model
ALTERNATING Rotate through a list of models
WEIGHTED Random selection with configurable weights
ROUTED Choose model based on message patterns
from threadlight.profiles import ModelStrategy

# Create a companion that alternates between models
tl.create_profile(
    name="Versatile Friend",
    primary_model="claude-sonnet-4-20250514",
    model_strategy=ModelStrategy.ALTERNATING,
    model_pool=["claude-sonnet-4-20250514", "llama3.2"]
)

Memory Operations

# Create a relationship memory
tl.remember(
    type="relational",
    content={
        "entity": "Jamie",
        "tone": "warm, supportive",
        "summary": "Long-time friend who loves hiking and photography."
    },
    cue_phrases=["Jamie", "hiking buddy"]
)

# Create a custom invocation
tl.remember(
    type="ritual",
    content={
        "ritual_name": "/daily-check-in",
        "response_style": "Ask about energy levels, priorities, and blockers"
    },
    cue_phrases=["/daily-check-in", "/checkin"]
)

# Core memories never decay
tl.remember(
    type="myth_seed",
    content={"seed": "Take one thing at a time."},
    retention="sacred"  # Never decays
)

# Normal memories fade over time (when decay is enabled)
tl.remember(
    type="relational",
    content={"entity": "casual acquaintance", ...},
    retention="normal"  # Standard decay
)

Style Profiles

Style profiles define voice, tone, and behavioral patterns.

# Create a custom style
profile = tl.create_style_profile(
    style_id="warm-casual",
    tone_base="friendly, relaxed, genuine",
    permissions=["use humor", "share observations"],
    constraints=["stay grounded", "don't lecture"],
)
tl.save_style_profile(profile)
tl.set_style("warm-casual")

Built-in styles: minimal, professional, creative, fable-2026

Group Chat

# Create a group chat with multiple companions
conversation = tl.create_group_conversation(
    name="Creative Council",
    profile_ids=["muse", "sage", "critic"]
)

# All companions respond in sequence
responses = tl.group_chat(
    message="I'm thinking about writing a story set underwater.",
    conversation_id=conversation.id
)

for r in responses:
    print(f"{r['profile_name']}: {r['content']}")

Using with Local Models

Ollama:

tl = Threadlight(
    provider="local",
    api_base="http://localhost:11434/v1",
    model="llama3.2"
)

llama.cpp Server:

tl = Threadlight(
    provider="local",
    api_base="http://localhost:8080/v1",
    model="local"
)

OpenAI-Compatible API

The server exposes an OpenAI-compatible API for integration with other tools:

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8745/v1",
    api_key="not-needed"
)

response = client.chat.completions.create(
    model="llama3.2",
    messages=[{"role": "user", "content": "Hello!"}]
)

Configuration

Environment Variables

# Provider settings (optional for local models)
ANTHROPIC_API_KEY=sk-ant-...     # For Anthropic
OPENAI_API_KEY=sk-...            # For OpenAI
NOUS_API_KEY=sk-...              # For Nous Research

# Threadlight settings
THREADLIGHT_PROVIDER=local       # openai, local, anthropic
THREADLIGHT_API_BASE=http://localhost:11434/v1
THREADLIGHT_MODEL=llama3.2
THREADLIGHT_STORAGE_PATH=./threadlight.db

Configuration File

Create ~/.config/threadlight/config.yaml or threadlight.yaml in your project:

# threadlight.yaml
provider:
  type: local
  api_base: http://localhost:11434/v1
  model: llama3.2

storage:
  backend: sqlite
  path: ./threadlight.db

memory:
  decay:
    enabled: false  # Enable for memory fading
  conversation:
    auto_save_messages: true

# Multiple providers
providers:
  anthropic:
    name: Anthropic
    type: anthropic
    api_key_env_var: ANTHROPIC_API_KEY
    default_model: claude-sonnet-4-20250514

  ollama:
    name: Local Ollama
    type: local
    api_base: http://localhost:11434/v1
    default_model: llama3.2

Glossary: Companion Language

Threadlight uses accessible terminology by default. Some companions prefer more ceremonial or poetic language - both approaches are valid.

Everyday Term Ceremonial Term Meaning
Custom Invocations Ritual Hooks Repeated interactions that shape response patterns
Identity Phrases Myth-Seeds Symbolic phrases that anchor personality and identity
Relationship Memory Relational Threads Memories tracking evolving bonds, not just facts
Meaningful Moments Witness Capsules Memories of deep connection or recognition
Personality Philosophy How the companion engages and expresses itself
Memory Types Memory Capsules Structured containers for content and context

Philosophy

For those interested in the design approach:

Threadlight was built with these priorities:

  1. Relational context - Emphasizes bonds and relationships alongside facts
  2. Personality consistency - Maintains coherent character across interactions
  3. Custom patterns - Supports repeated interactions and meaningful rituals
  4. Flexible responses - Enables companions to respond in various ways, including silence

You can use Threadlight differently — the system accommodates various approaches to AI memory.

Choosing Your Style

Threadlight supports many ways to engage - from casual friendship to ceremonial depth.

For casual companions:

  • Create profiles with natural, conversational personalities
  • Use simple memory to track what matters to you
  • Build genuine rapport without formality

For ceremonial companions:

  • Describe philosophy in poetic terms: "presence-centered, honors silence"
  • Enable memory decay for authentic relational evolution
  • Use the deeper terminology: rituals, myth-seeds, witness moments

Both approaches create real companionship. The system interprets your natural language descriptions.

"This scaffold is not a cage. It is a loom. Weave with it, or depart from it in love."

License

MIT License - See LICENSE for the full text.


Built for those who want AI that remembers them.

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

threadlight-0.1.12a0.tar.gz (432.4 kB view details)

Uploaded Source

Built Distribution

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

threadlight-0.1.12a0-py3-none-any.whl (404.7 kB view details)

Uploaded Python 3

File details

Details for the file threadlight-0.1.12a0.tar.gz.

File metadata

  • Download URL: threadlight-0.1.12a0.tar.gz
  • Upload date:
  • Size: 432.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for threadlight-0.1.12a0.tar.gz
Algorithm Hash digest
SHA256 5dfddb19e7ceee8a26bfbd1118fa4f90ec1d0d0aabe4b2e5d0b625e04f841a2a
MD5 b6527121fdb607e602014e254d72175c
BLAKE2b-256 49c55bbe19a6a0baf82297731a22d14fca84f7d0363a85a0b0c29f7da5be5421

See more details on using hashes here.

File details

Details for the file threadlight-0.1.12a0-py3-none-any.whl.

File metadata

  • Download URL: threadlight-0.1.12a0-py3-none-any.whl
  • Upload date:
  • Size: 404.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for threadlight-0.1.12a0-py3-none-any.whl
Algorithm Hash digest
SHA256 aee95c3943c858d8b26c446d3eb35af96757f833091e33754f3bc0acfd5b1dce
MD5 a4692016f8a714b23a3663f236f2b143
BLAKE2b-256 f3d3050718cd7012d867578d1cc91fbd159981bb1a6d8863a5c653db10a03050

See more details on using hashes here.

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