a digital entity named phi that roams bsky
MCP Refactor Progress#
Branch: mcp-refactor#
Completed ✅#
Phase 1: Foundation#
-
Cloned and studied reference projects
sandbox/prefect-mcp-server- Learned PydanticAI + MCP patterns- Understood how MCP servers work as toolsets for PydanticAI agents
-
Created simplified memory system (
src/bot/memory.py)- Single SQLite database (threads.db)
- Plain text storage - no embeddings, no vector search
- Two tables:
threads- Full conversation history per thread (JSON)user_memories- Simple facts about users
- Completely interpretable - you can open the db and read everything
-
Integrated ATProto MCP server
- Copied from
.eggs/fastmcp/examples/atproto_mcp→src/bot/atproto_mcp - Updated settings to use existing env vars (BLUESKY_HANDLE, etc.)
- Server provides tools: post(), like(), repost(), follow(), search(), create_thread()
- Copied from
-
Created MCP-enabled agent (
src/bot/agent.py)- PydanticAI Agent with ATProto MCP tools as a toolset
- Loads personality from
personalities/phi.md - Integrates with memory system
- Returns structured Response (action, text, reason)
-
Updated dependencies
- ✅ Added:
fastmcp>=0.8.0,websockets>=15.0.1 - ❌ Removed:
turbopuffer,openai(no longer needed for memory)
- ✅ Added:
What Changed#
Before (Complex)#
- Memory: TurboPuffer + OpenAI embeddings + semantic search
- Agent: Custom response generator with manual action interpretation
- AT Protocol: Direct client calls scattered throughout codebase
- Personality: Dynamic loading from TurboPuffer
- Self-modification: Complex approval system with DM workflow
After (Simple)#
- Memory: SQLite with plain text (interpretable!)
- Agent: PydanticAI with MCP tools (agent decides actions)
- AT Protocol: MCP server provides all tools
- Personality: Static file loading
- Self-modification: Removed (cruft)
How It Works Now#
# Create agent with memory
memory = Memory()
agent = PhiAgent(memory)
# Process a mention
response = await agent.process_mention(
mention_text="hey phi!",
author_handle="user.bsky.social",
thread_uri="at://did/post/123"
)
# Agent returns: Response(action="reply", text="...", reason="...")
# If action is "reply", agent can call MCP tool: post(text="...", reply_to="...")
The agent has access to all ATProto MCP tools and can decide:
- Should I reply, like, or ignore this?
- If replying, what should I say?
- Should I use other tools (repost, follow, etc.)?
Next Steps#
Phase 2: Integration (Not Started)#
- Update
src/bot/main.pyto use new agent - Simplify
src/bot/services/notification_poller.py - Remove old response_generator.py
- Test end-to-end
Phase 3: Cleanup (Not Started)#
- Delete cruft:
src/bot/ui/(context visualization)src/bot/personality/editor.py(approval system)src/bot/core/dm_approval.pysrc/bot/memory/namespace_memory.pysrc/bot/agents/anthropic_agent.py(replaced by agent.py)
- Update database.py to remove approval tables
- Update tests
- Update README.md and documentation
Phase 4: Verification (Not Started)#
- Run the bot and test mentions
- Verify thread memory works
- Verify user memory works
- Ensure online/offline status still works
Testing#
Test script created: sandbox/test_new_agent.py
uv run python sandbox/test_new_agent.py
Key Files#
New#
src/bot/memory.py- Simple SQLite memorysrc/bot/agent.py- MCP-enabled PydanticAI agentsrc/bot/atproto_mcp/- ATProto MCP server (vendored)
Modified#
pyproject.toml- Updated dependencies
To Be Deleted#
src/bot/memory/namespace_memory.pysrc/bot/agents/anthropic_agent.pysrc/bot/response_generator.pysrc/bot/ui/src/bot/personality/editor.pysrc/bot/core/dm_approval.py
Philosophy#
Before: Over-engineered for capabilities we might want someday After: Simple, working, interpretable system that does what we need today
The memory is now something you can:
- Open with any SQLite browser
- Read and understand immediately
- Debug by just looking at the tables
- Migrate or export trivially
No more:
- Vector embeddings you can't see
- Complex namespace hierarchies
- Approval workflows for every personality change
- Multiple overlapping memory systems