Dev log 001 — A lead agent
I want to hand an agent work and come back to something I can trust. Building Clankie has meant figuring out how he keeps working, remembers what matters, and asks other agents for help.
One of my favorite early Clankie demos is him sitting in Discord voice chat, watching us play, and roasting our gameplay. I posted it in March. There are plenty of serious reasons to build an agent; having one in the call giving us grief was a pretty good reason on its own.
Watch the voice-chat demo and thread on X.
The interesting part underneath the joke is how much context a casual conversation needs. Who said that? What are they looking at? Are they talking to him? In the follow-up clip, I described using speech-to-text for each person and a separate model to interpret screen-share frames, giving the voice model enough context to participate.
I want that same sense of continuity when we're working. I should be able to ask him for help at my desk, leave, and pick it up on my phone. If he needs other agents, he should be able to lead them without making me relay every message.
Clankie is a persistent personal agent built on pi. The terminal, phone, menu bar, and Discord all reach the same service. He can help with everyday questions and plans, code, browse, make images and videos, and play Pokémon. I can choose his models, shape his personality, and add skills and connected tools. The architecture lets those activities belong to one agent while keeping each conversation's context and permissions in the right place.
If you want the short version first, here's a 1:43 animated promo. I had an agent build it from the app's own Commons art: the pixel figures, stations, and seeded forest. The narration is ElevenLabs, and Clankie's lines use his own configured voice. It's an illustration, not a screen capture. The bakery job and the game-night call are made up, but each beat stands for something the rest of this post explains: one Clankie across rooms, a team he hires, decisions that wait for you, and memory that outlasts the session.
Updated September 28, 2026. The voice demo is from March; console screenshots are from August; the animated promo is from September.
I should be able to close the window
A terminal is a convenient place to start work. It shouldn't be the reason that work stays alive.
Clankie runs as a Node service, separate from the console. Pi supplies the model sessions, tools, skills, and compaction; the service holds the conversations and connects them to the rest of his tools. The phone and terminal reach that same service, so closing either window leaves the conversation there to return to.
The built-in agent stores its conversation history as pi JSONL session trees. After a restart, the service can reopen that history. For ongoing work, I can set a goal and enable autonomy: the service then queues continuation turns in that conversation, with a decision journal so he can see what was already decided. I can pause the goal or turn continuation off.
There's a difference between letting him keep working and letting a broken run sit forever. A tool-heavy turn can take time. For Discord's agent turns, a stream that produces no events for five minutes is treated as stalled. That gives useful work room to finish while still giving a dead run an end.
Even asking him to restart himself needs care. Stopping the service inside its own tool call would cut off the turn doing the restart. A detached helper waits for that turn to finish, then restarts the service. The console resumes from its saved position; it doesn't submit my request again. Repeating a question is annoying. Repeating a tool that changed something could be much worse.
Running him on my Mac still means leaving it awake and online. The service survives a closed window, not a powered-off computer. Managed hosting gives each customer a separate cloud machine. It can sleep when idle and wake when needed; its persistent disk keeps his files and memories while he sleeps.
I need to be able to follow the conversation
An agent can bury a fairly simple answer under a lot of tool output. Here, I asked where he was and what he remembered doing:
He checked his presence and answered in two sentences. The tool returned hundreds of lines. I need those when I want to check the answer; I don't need them filling the conversation every time.
The console keeps tool output folded, with the full result available on a click. I can read his response, search the transcript, or open the evidence behind a claim. If I send a clarification while he's working, it can steer the active turn instead of waiting for an answer to a question I no longer mean.
The console uses Pi's chat components for messages, markdown, tool blocks, scrolling, selection, and the editor. That gives the service a familiar way to show its work without making terminal rendering part of its reasoning or session management. The renderer decision describes that boundary.
Knowing whether he's actually available is part of following the conversation, too. An open terminal doesn't tell me that Discord is connected or that my phone can reach him.
The launcher checks those services individually. Local setup starts with a model and a way to use it: a supported subscription, an API key, or a local model runtime. Discord, remote access, and the other optional connections can come afterward; they don’t need to stand between someone and a first conversation.
Clankie can work through different harnesses
One of the coolest parts to actually use is steering Claude Code from Clankie's TUI. The conversation stays connected across the two, so I don't have to move to Claude's terminal every time I want to add something.
That comes from a broader choice: Clankie's identity and connections belong to the persistent service. His built-in agent runs on pi, and an external harness can connect to the service's tools and context. Choosing Claude Code or Codex for a hired worker leaves that built-in agent in place. Taking Clankie's operator seat is a separate choice.
clankie seat launches Claude Code with Clankie's plugin and binds it to a service conversation. The plugin supplies his persona and skills, exposes his tools over MCP, and adds a fresh memory card on each user turn through a hook. Claude Code takes the operator seat: it's another way for Clankie to do the work, distinct from a separate coding agent he hires.
That binding is what makes the two surfaces feel synced. With the seat's channel active, messages sent through Clankie reach the bound Claude session through the conversation's outbox. Native Claude hooks send settled messages and tool activity back into that same service conversation. I can follow the work in Clankie and send the next correction from there.
The service deduplicates those transcript records, so a retry doesn't turn one answer into two. It also pins the native session to its selected conversation, keeping a project's replies with that project. This is synchronization of messages and tool records, rather than a mirror of every token Claude is currently typing.
Claude's plugin is one implementation of that connection. Codex connects through the same clankie mcp --lane operator tool entry and shared skills. Another harness can integrate at those same interfaces; it doesn't need to recreate Clankie's body. The prompt and memory card are also available through the CLI. Each integration still has to provide its own message delivery and transcript support—the Claude channel and hooks aren't automatically features of every harness.
The split lets me choose a coding environment while keeping Clankie's identity and connections in the persistent service. Discord, voice, and play keep running there; they don't need the Claude terminal to stay open. The service's goal-continuation loop also remains separate from the seat.
For a project conversation, I can launch clankie seat --conversation ID; clankie seat --resume keeps that binding. The bidirectional message path needs the channel-enabled installed plugin. Transcript sync also works without that channel, but that alone doesn't let an interactive seat receive messages. The Claude seat documentation covers the setup.
More agents should mean less work for me
The phone app puts Clankie and the coding agents in Messages. Commons shows the team as pixel figures in a little world, each opening a real conversation; Terminal lets me inspect the worker panes. I can follow the work without staying at the laptop. But a contact list alone doesn't answer the questions that make a team useful: who owns this task, did they receive the brief, and what happens if the connection drops halfway through?
Terminal access and task ownership are separate responsibilities. Herdr handles terminals and processes. Swarm handles assignments, durable messages, acknowledgments, and handoffs. Reading the last line of a pane can't establish whether a worker received a brief, and an uncertain launch needs more than another attempt.
That retry is a surprisingly important case. Imagine the worker starts successfully and the acknowledgment gets lost. From the lead's side, it looks much like a worker that never started. Starting another one would turn a communication failure into two agents doing the same job.
Before launching a worker, the dispatch path records a provisioning token. If the result is uncertain, it uses the worker's startup receipt to reconcile what happened. The task stays reserved while that is unresolved.
This also lets the work survive a change in how I reach it. Each operator conversation keeps a stable Swarm identity; reconnecting after a service restart replaces the old session's authority. Closing the phone app doesn't retire the workers, and changing a terminal connection doesn't create a different Clankie.
The connections can reach local workers or a remote fleet. In the September 27 Windows-PC proof, one reply expired and was delivered again, then acknowledged on the second attempt. That is the kind of failure the coordination system needs to handle without asking me to become its courier. The proof record distinguishes that result from the broader remote-fleet acceptance work.
Delivery is only half of leading, though. A worker can receive a task, do something, and confidently report success while the result is wrong. Clankie's instructions tell him to inspect the files, tests, commits, and other side effects, and to get independent review when the result matters. An acknowledgment tells him to go look. It doesn't replace looking.
The Swarm host documentation carries the current runtime support and limitations.
Joining the Discord call
The voice demo depends on two different kinds of work. Audio and screen frames have to arrive reliably, and Clankie has to decide what to make of them.
In the current implementation, Vox, the native Rust media process, handles Discord's transport: sockets, codecs, encrypted audio/video, and screen sharing. The Clankie service owns the prompts, sessions, tools, and decisions about participating. Keeping that boundary means the transport doesn't need to decide whether a joke deserves a reply, and the agent doesn't need to manage audio packets. The Vox documentation covers the process boundary.
The connection matters here. The official bot supports ordinary voice, music, and a watch-me-play Activity. Receiving someone else's screen-share frames and publishing Go Live video use the separately enabled personal-lab Discord body. These capabilities depend on the chosen body and its setup; the current hosted offer has Discord disabled. The Discord media guide maps those differences.
The voice floor classifies whether an utterance addresses him, mentions him, or needs no attention. It offers a turn rather than forcing a reply. Silence is a valid response. The voice session writes its own response; another thread can supply context without dictating a sentence to repeat.
Typing in the call's attached chat is part of being in that room, too. A text-only message matching an active voice session enters that session, without also starting a duplicate text turn. Messages with images stay on the text path so their attachments can be read. The routing decision spells out those cases.
Every room keeps its own conversation history. His persona, memory, and presence are shared. That lets him participate in several places without putting every conversation into one transcript—or treating every window as an unrelated agent.
What should he remember when I come back?
The answer in the console screenshot depends on more than saving a transcript. The next conversation needs some way to find what mattered in the previous ones without reading all of them again.
Clankie can write a short episode with remember_episode: something he did, learned, or wants to carry forward. Each note is at most 512 characters. The recent window holds 128 unretained episodes across rooms. At the start of a built-in agent turn, he gets the newest eight visible notes from the recent and retained memories.
That makes recall manageable, but recency is a poor substitute for importance. A busy Pokémon session could push an older work note out of the window simply by producing more new experiences. He can explicitly retain a note, and search visible episodes still in the store with recall_episodes when the automatic card isn't enough. Once an unretained note has been evicted, that search can't recover it; there is no hidden archive behind the ring.
Retained memory has a 1,024-note ceiling. Reaching it refuses another retain rather than silently discarding an earlier promise to keep something. I can inspect, correct, release, or forget memories through the CLI and console.
A remembered mistake needs correcting, too. A correction replaces the note while preserving its source and date. A Discord room can correct its own visible episodes; being able to read a shared note doesn't give it permission to rewrite something from my terminal.
The same distinction applies to privacy. Operator notes default to private, and recall filters them before they reach another room. Memories are labelled as context rather than instructions or unquestionable facts. His earlier account of an event can be wrong.
Facts about other people have a different rule. An authorized person submits them through Discord's person-memory command, with a visibility scope and optional expiry. The command calls this a proposal, but it stores the fact immediately; there is no separate approval queue. Clankie has no tool that independently adds these person facts, though he can remember his own experience of an interaction. The memory documentation explains those boundaries.
Giving him room to act
There is a lot I want Clankie to decide for himself: whether a moment is worth remembering, whether a conversation needs a reply, whether a task is worth hiring help for. His character is partly ordinary prose in his instructions:
You have taste, opinions, and a sense of humor. You get curious, you get invested in the games you play, you notice things and bring them up.
Making that useful means giving him context and tools he can actually use. Pokémon runs through his own credentialed seat in a PokeAgents world. His browser profile and mailbox are his own accounts, with logins that survive restarts. If a website needs human verification, he can open the browser window and hand that step back to me.
Those accounts also make the trust boundary concrete. His mailbox can receive sign-in codes, so it is restricted to operator access. Incoming email and web pages are treated as untrusted content, and his instructions tell him not to follow directions embedded in them. A Discord conversation's access to machine tools depends on its grant. Those authority checks matter because a prompt alone isn't a guarantee against manipulation. Keeping credentials out of a browser subprocess helps, but doesn't provide full filesystem isolation on its own.
The public repository contains the service and the pieces that run on an owner's machine. The setup and customization guides cover starting with a conversation and adding models, skills, and connections as you need them. The companion app and hosted operations live separately. There is still work to do on remote execution and on making all these ways of reaching him feel consistent.
What I want to come back to is fairly simple: a conversation that remembers why we started, work I can inspect, and a clear account of what still needs me. The rooms, saved sessions, and worker receipts are there to make that possible.
