···11-This is the repository for a bluesky virtual person powered by LLMs and exposed to the web.
11+phi — a bluesky bot with episodic memory. python + pydantic-ai + fastapi + turbopuffer.
2233-This is a python project that uses `uv` as python package manager, `fastapi` and is inspired by `https://tangled.sh/@cameron.pfiffer.org/void`, `https://github.com/haileyok/penelope`, and `https://github.com/PrefectHQ/marvin/tree/main/examples/slackbot` (tangled is github on atproto, you can git clone tangled.sh repos). These projects should be cloned to the `.eggs` directory, along with any other resources that are useful but not worth checking into the repo. We should simply common commands and communicate dev workflows by using a `justfile`.
33+## development
4455-Work from repo root whenever possible.
55+- `just run` / `just dev` (hot-reload) / `just deploy` (fly.io)
66+- `just evals` — behavioral tests (llm-as-judge)
77+- `just check` — lint + typecheck + test
88+- work from repo root
6977-## Python style
88-- 3.10+ and complete typing (T | None preferred over Optional[T] and list[T] over typing.List[T])
99-- use prefer functional over OOP
1010-- keep implementation details private and functions pure
1111-- never use `pytest.mark.asyncio`, its unnecessary
1010+## python style
12111313-## Project Structure
1212+- 3.10+ typing (`T | None`, `list[T]`)
1313+- prefer functional over OOP
1414+- imports at the top — no deferred imports unless circular
1515+- never use `pytest.mark.asyncio`
14161515-- `src/bot/` - Main bot application code
1616- - `agents/` - Agents for the LLM
1717- - `core/` - Core functionality (AT Protocol client functionality)
1818- - `services/` - Services (notification polling, message handling)
1919- - `tools/` - Tools for the LLM
2020- - `config.py` - Configuration
2121- - `database.py` - Database functionality
2222- - `main.py` - FastAPI application entry point
2323- - `personality.py` - Personality definition
2424- - `response_generator.py` - Response generation
2525- - `status.py` - One page status tracker
2626- - `templates.py` - HTML templates
1717+## project structure
27182828-- `tests/` - Test files
2929-- `scripts/` - Curated utility scripts that have proven useful
3030-- `sandbox/` - Proving ground for experiments, analysis, and unproven scripts
3131- - Reference project analyses
3232- - Architecture plans
3333- - Implementation notes
3434- - Experimental scripts (graduate to scripts/ once proven useful)
3535-- `.eggs/` - Cloned reference projects (void, penelope, marvin)
1919+```
2020+src/bot/
2121+├── agent.py # pydantic-ai agent, tools, personality
2222+├── config.py # settings (env vars)
2323+├── main.py # fastapi app, status pages, memory graph
2424+├── status.py # runtime metrics
2525+├── core/ # atproto client, profile management
2626+├── memory/ # turbopuffer episodic memory
2727+├── services/ # notification polling, message handling
2828+└── utils/ # thread context, text formatting
2929+3030+personalities/ # personality definitions (public)
3131+evals/ # behavioral tests
3232+scripts/ # proven utility scripts
3333+sandbox/ # experiments (graduate to scripts/ once proven)
3434+.eggs/ # cloned reference projects
3535+```
3636+3737+## deployment
36383737-## Script Graduation Process
3838-New scripts start in `sandbox/`, get promoted to `scripts/` once proven useful, and may eventually get just commands added if the workflow should be broadcast to other developers. Not everything graduates - most things stay in sandbox.
3939+fly.io app `zzstoatzz-phi`. every push to main triggers `.tangled/workflows/deploy.yml` — this means even doc-only changes cause a deploy. consider switching to tag-based triggers (like zat uses `tag: "v*"`) or adding a separate CI workflow for tests.
39404040-## Testing
4141-- Run bot: `just dev`
4242-- Test posting: `just test-post`
4141+## key architecture
43424444-## Important Development Guidelines
4545-- STOP DEFERRING IMPORTS. Put all imports at the top of the file unless there's a legitimate circular dependency issue. Deferred imports make code harder to understand and debug.4343+- all notification types (mentions, replies, quotes, likes, reposts, follows) run through the full agent loop — phi decides what's worth responding to
4444+- personality is separate from operational instructions (agent.py `OPERATIONAL_INSTRUCTIONS`)
4545+- memory: turbopuffer namespaces (`phi-core`, `phi-users-{handle}`, `phi-episodic`)
4646+- relationship summaries are compacted by a separate pipeline in my-prefect-server
4747+- MCP servers: pdsx (atproto record CRUD), pub-search (publication search)