a digital entity named phi that roams bsky
Python 98.9%
Just 1.1%
Other 0.1%
44 3 0

Clone this repository

https://tangled.org/zzstoatzz.io/bot https://tangled.org/did:plc:xbtmt2zjwlrfegqvch7fboei/bot
git@tangled.org:zzstoatzz.io/bot git@tangled.org:did:plc:xbtmt2zjwlrfegqvch7fboei/bot

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

phi#

a bluesky bot inspired by integrated information theory. built with pydantic-ai, mcp, and the at protocol.

quick start#

# clone and install
git clone https://github.com/zzstoatzz/bot
cd bot
uv sync

# configure
cp .env.example .env
# edit .env with your credentials

# run
just run

required env vars:

  • BLUESKY_HANDLE / BLUESKY_PASSWORD - bot account (use app password)
  • ANTHROPIC_API_KEY - for agent responses

optional (for episodic memory):

  • TURBOPUFFER_API_KEY + OPENAI_API_KEY - semantic memory

features#

  • โœ… responds to mentions with ai-powered messages
  • โœ… episodic memory with semantic search (turbopuffer)
  • โœ… thread-aware conversations (fetches from network, not cached)
  • โœ… mcp-enabled (atproto tools via stdio)
  • โœ… session persistence (no rate limit issues)
  • โœ… behavioral test suite with llm-as-judge

โ†’ read the docs for deeper dive into design and implementation

development#

just run        # run bot
just dev        # run with hot-reload
just evals      # run behavioral tests
just check      # lint + typecheck + test
just fmt        # format code
architecture

phi is an mcp-enabled agent with episodic memory:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚     Notification Arrives            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
               โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚     PhiAgent (PydanticAI)           โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ System Prompt: personality.md โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚              โ†“                      โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ Context Building:             โ”‚  โ”‚
โ”‚  โ”‚ โ€ข Thread context (ATProto)    โ”‚  โ”‚
โ”‚  โ”‚ โ€ข Episodic memory (TurboPuffer)โ”‚ โ”‚
โ”‚  โ”‚   - Semantic search           โ”‚  โ”‚
โ”‚  โ”‚   - User-specific memories    โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚              โ†“                      โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ Tools (MCP):                  โ”‚  โ”‚
โ”‚  โ”‚ โ€ข post() - create posts       โ”‚  โ”‚
โ”‚  โ”‚ โ€ข like() - like content       โ”‚  โ”‚
โ”‚  โ”‚ โ€ข repost() - share content    โ”‚  โ”‚
โ”‚  โ”‚ โ€ข follow() - follow users     โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚              โ†“                      โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ Structured Output:            โ”‚  โ”‚
โ”‚  โ”‚ Response(action, text, reason)โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
               โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚     MessageHandler                  โ”‚
โ”‚     Executes action                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

key components:

  • pydantic-ai agent - loads personality, connects to mcp server, manages memory
  • episodic memory - turbopuffer for vector storage with semantic search
  • mcp integration - external atproto server provides bluesky tools via stdio
  • session persistence - tokens saved to .session, auto-refresh every ~2h
episodic memory

phi uses turbopuffer for episodic memory with semantic search.

namespaces:

  • phi-core - personality, guidelines
  • phi-users-{handle} - per-user conversation history

how it works:

  1. retrieves relevant memories using semantic search
  2. embeds using openai's text-embedding-3-small
  3. stores user messages and bot responses
  4. references past conversations in future interactions

why vector storage?

  • semantic similarity (can't do this with sql)
  • contextual retrieval based on current conversation
  • enables more natural, context-aware interactions
project structure
src/bot/
โ”œโ”€โ”€ agent.py                    # mcp-enabled agent
โ”œโ”€โ”€ config.py                   # configuration
โ”œโ”€โ”€ database.py                 # thread history storage
โ”œโ”€โ”€ main.py                     # fastapi app
โ”œโ”€โ”€ core/
โ”‚   โ”œโ”€โ”€ atproto_client.py      # at protocol client (session persistence)
โ”‚   โ”œโ”€โ”€ profile_manager.py     # online/offline status
โ”‚   โ””โ”€โ”€ rich_text.py           # text formatting
โ”œโ”€โ”€ memory/
โ”‚   โ””โ”€โ”€ namespace_memory.py    # turbopuffer episodic memory
โ””โ”€โ”€ services/
    โ”œโ”€โ”€ message_handler.py     # agent orchestration
    โ””โ”€โ”€ notification_poller.py # mention polling

evals/                         # behavioral tests
personalities/                 # personality definitions
sandbox/                       # docs and analysis
troubleshooting

bot gives no responses?

  • check ANTHROPIC_API_KEY in .env
  • restart after changing .env

not seeing mentions?

  • verify BLUESKY_HANDLE and BLUESKY_PASSWORD
  • use app password, not main password

no episodic memory?

  • check both TURBOPUFFER_API_KEY and OPENAI_API_KEY are set
  • watch logs for "๐Ÿ’พ episodic memory enabled"

hit bluesky rate limit?

  • phi uses session persistence to avoid this
  • first run: creates .session file with tokens
  • subsequent runs: reuses tokens (no api call)
  • tokens auto-refresh every ~2h
  • only re-authenticates after ~2 months
  • rate limits (10/day per ip, 300/day per account) shouldn't be an issue
refactor notes

see sandbox/MCP_REFACTOR_SUMMARY.md for details.

what changed:

  • removed approval system (half-baked)
  • removed context viz ui (not core)
  • removed google search (can add back via mcp)
  • kept turbopuffer (essential for episodic memory)
  • added mcp-based architecture
  • added session persistence
  • reduced codebase by ~2,720 lines

reference projects#

inspired by void, penelope, and prefect-mcp-server.