a digital entity named phi that roams bsky phi.zzstoatzz.io
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 72 lines 4.5 kB view raw view rendered
1# architecture 2 3phi is one agent loop, fired from a few different paths. notifications drive most of the activity; scheduled paths cover the rest. 4 5## one agent, many entry points 6 7every entry point ends in the same place: `agent.run()` with a `PhiDeps` carrying whatever context the path needs. tool definitions are the same across paths; the system prompt assembles different dynamic blocks based on what's in `PhiDeps`. the agent decides AND acts inside the run via tool calls — `reply_to`, `like_post`, `post`, `note`, `propose_goal_change`, etc. there's no separate decide-then-dispatch layer. 8 9what changes per path is the user prompt and the deps shape, not the agent. 10 11## entry points 12 13| path | trigger | user prompt sketch | 14|---|---|---| 15| **notifications batch** | poll every 10s, dispatch unread as one cognitive event | "process your new notifications batch — silence is fine" | 16| **scheduled musing** | every 2h during configured hours | "you have a moment. post if you want, or don't" | 17| **daily reflection** | once per day at `DAILY_REFLECTION_HOUR` | "end of day. post a reflection if you have one" | 18| **relay check** | every ~3h | "scheduled relay check. report transitions; tag owner if `*.waow.tech` dips or fleet-wide degradation" | 19| **memory review** | on demand | dream/distill pass over recent observations | 20 21## data flow (notifications) 22 23``` 24bsky.notification.listNotifications (every 10s) 2526filter unread × allow-list (rate limit per author) 2728build notifications_context: per-notif fetch (post body, thread context, 29 reply refs, embeds), pre-fetch stranger profiles for unfamiliar authors 3031PhiDeps assembled, system prompt composed: 32 identity / time / known relays / goals / inner critic / self state 33 / notifications block / per-author memory / synthesized episodic / ... 3435agent.run() — tool calls happen inside (reply_to, like_post, etc.) 3637post-action: store interaction in turbopuffer for next time 38``` 39 40see [system-prompt.md](system-prompt.md) for what each block contains and when it refreshes. 41 42## scheduling 43 44all schedules run from one `notification_poller.py` loop. on each ~10s tick: 45 461. fetch + dispatch any unread notifications 472. if it's the daily reflection slot and we haven't fired today → run it 483. if it's a thought-post slot we haven't fired this hour → run it 494. if it's been ≥3h since the last relay check → run it 50 51state for "did we already fire today" is persisted via phi's own posts on PDS — the poller seeds from history at startup so deploys don't double-post. 52 53## intent state on PDS 54 55phi's *durable* intent lives on its own PDS as records under `io.zzstoatzz.phi.*`: 56 57- `io.zzstoatzz.phi.goal` — phi's anchors. a small set of named, defined goals (e.g. "make 3 friends" with a concrete progress signal). injected as `[GOALS]` in every tick. 58- `io.zzstoatzz.phi.mentionConsent` — handles opted-in to be tagged by phi. 59 60mutations to goals (and any other owner-gated action like `follow_user`, `create_feed`) flow through a like-as-approval gate: phi posts an authorization request, the owner likes it, the next batch's `_is_owner` check sees the like-on-phi's-post and lets the action through. scoped to the action discussed in that thread, not blanket. 61 62## why this shape 63 64**tool-based actions.** phi decides AND acts inside one agent run. no structured decide-then-dispatch layer to maintain. consequence: the agent's "output" is a brief summary string for logging; the actual work happened during the run. 65 66**network-first context.** thread bodies are fetched from atproto on demand per batch (~200ms). nothing about the conversation is cached locally. the network is source of truth. 67 68**docstrings, not prompt restatement.** what each tool does and when to use it lives in the tool's docstring. the framework surfaces docstrings to the model. the system prompt is for cross-cutting rules (consent, ownership, memory trust hierarchy), not per-tool documentation. 69 70**synthesize before injecting where shape matters.** memory candidates from a vector store are ranked by cosine similarity, which doesn't reconcile or note recency. for blocks where coherence matters (recent posts → audit, episodic candidates → relevant memories), a small haiku pass produces a coherent block from the candidates. see [memory.md](memory.md) and [system-prompt.md](system-prompt.md). 71 72**MCP for capabilities outside this codebase.** atproto record CRUD (pdsx) and long-form publication search (pub-search) are remote MCP servers. reusable, not bundled.