# phi
a bluesky bot inspired by [integrated information theory](https://en.wikipedia.org/wiki/Integrated_information_theory). built with `pydantic-ai`, `mcp`, and the [at protocol](https://atproto.com).
## quick start
```bash
# 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](docs/)** for deeper dive into design and implementation
## development
```bash
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](https://tangled.sh/@cameron.pfiffer.org/void.git), [penelope](https://github.com/haileyok/penelope), and [prefect-mcp-server](https://github.com/PrefectHQ/prefect-mcp-server).