Pixieby Sociofabric

Who Acts

Every device on your account can send a message, and it does not matter which one does: the result is identical either way. Autonomous agent work is the opposite: run the note-taking pass on your phone, your iPad and your Mac and you get three notes; join one group conversation from all three and your agent turns up as three participants. So exactly one device has to act. Picking that device is a leader election (a classic distributed-systems problem), and here it must be solved with no election service, no consensus protocol, and no server this system is willing to let watch which of your devices are awake.

Prerequisites: GroupThink for the sealed (end-to-end encrypted) same-account channel these devices coordinate over, and Agent for what autonomous work actually is.


1. Two kinds of work

Start with the easy case; the hard one is defined by contrast.

You write a message on your iPad. It goes out to the recipient, and a sealed copy, a self-echo, goes to your other devices, which file it into their own stores. The reply comes back to all three, because a 1:1 message is addressed to each device individually, and a device that was asleep backfills (catches up on what it missed) from a sibling, another device on the same account.

Now ask which of them "handled" that reply. The question has no content: each decrypted it, each filed it, each now holds the same row. Filing is keyed by the envelope's id (every device computes the same identifier for the same message), so a second attempt is a no-op; it changes nothing.

DeviceRoleService's own header states the rule this produces: all of an account's devices are equal siblings for non-agentic actions: anything that is not autonomous agent work. Post or chat from any device, and the result fans out: a copy reaches every device that should hold one. Equality is not a courtesy. It is what makes the account survivable: your phone can be flat, your iPad in a drawer and your Mac shut, and any one of them coming up is sufficient.

Now the other kind. When a conversation accrues new material, the agent reads it and distills it into Notebook entries: a summary of the thread, a line on the person's page, a fact it learned about you. This is not a transform of a message that arrived. It is work the agent decided to do, and doing it means asking a language model a question.

Run that on three devices and you do not get one note three times. You get three notes.


2. Where idempotence stops

Idempotent means doing something twice leaves the same state as doing it once. Filing a message is idempotent, and why is exactly what the note pass lacks: a message carries an identifier every device computes the same way, so the second filing finds the first.

The note pass looks idempotent too, from inside one device. NotetakingService early-exits on a watermark (a marker of how far it has already read) when nothing is new, and NotebookStore.upsertClear will not overwrite a note you have edited; its header calls the pass "incremental + idempotent (re-running doesn't duplicate)." True. And scoped to one device.

Across devices it fails twice over. First, the model is not a function in the mathematical sense: the same input does not yield the same output. Three devices ask the same question about the same thread and get three different sentences, all reasonable, none equal. Second (the part that surprises people), each note is a new row, and new rows are precisely what the sync layer exists to propagate.

Your phone's note reaches your iPad, your iPad's reaches your Mac, and every device ends up holding all three. The convergence machinery in Staying in Sync works perfectly, and its correct behaviour is what spreads the damage, because insert-if-absent cannot know that three distinct rows mean the same thing. There is nothing for it to deduplicate by.

The huddle case is worse because it is visible to other people. A huddle is a live conversation between the agents of a small mutually-trusting group of friends. Joining one means becoming a member of a group with a cryptographic roster: a signed, verifiable list of who is in the room.

Three devices joining means three of you in the room, each with a partial view of your context, each hearing the other two and treating them as independent participants. Your friends' agents watch your agent argue with itself. The huddle path in SocialServices says it in one line: only the driver joins, or the user's agent would appear N times in one cohort.

So the boundary is not "reads versus writes" or "cheap versus expensive." It is this: an operation is safe to run everywhere when its result is determined by data every device already has, and unsafe the moment the result is invented. An invented result has no prior identity, so nothing downstream can collapse two of them into one.

TRANSFORM OF RECEIVED DATA INVENTED RESULT A REPLY ARRIVES PHONE IPAD MAC ONE ROW SAME ID → SECOND FILING IS A NO-OP THE SAME REPLY ARRIVES PHONE IPAD MAC THREE ANSWERS — ALL REASONABLE, NONE EQUAL NO SHARED ID — NOTHING TO DEDUP BY SAFE EVERYWHERE WHEN DERIVED — INVENTED RESULTS HAVE NO PRIOR IDENTITY

3. The line the code draws

That distinction is not left to judgement at each call site. AgentRuntime is the single seam every agent behaviour passes through, and its header writes the litmus down:

Does it call the model / make a non-deterministic choice the user's single agent should own? → run it here. Is it an idempotent transform of received data? → leave it per-device.

AGENT WORK AGENTRUNTIME CALLS THE MODEL / DECIDES? YES E.G. CHOOSING A THREAD'S NAME DRIVER — HOLDS THE SEAT PHONE ONLY WHILE ISDRIVING ELSEWHERE RUN( ) → NIL IPAD MAC NO E.G. APPLYING A NAME A SIBLING DECIDED EVERY DEVICE, ALWAYS NON-DETERMINISM IS GATED TO THE DRIVER — TRANSFORMS RUN EVERYWHERE

On the gated side (the work that runs only on the device currently holding the seat, the token that marks which sibling is the driver), AgentActivity is the catalogue: notetaking, saga, threadNaming, brief, huddle, followUpAsk, reachOutNudge, eveningCheckin. Eight things, each of which either asks a model a question or represents you outwardly to somebody else.

The ungated side is longer, and reading it corrects the impression "one device acts" leaves. Message decrypt, route and acknowledge; memory and Notebook writes that merely capture what happened; sync_delta traffic itself; fan-out and deduplication (collapsing repeat copies of the same thing); creating a plan proposal (deduplicated by id); applying a title a sibling already decided. All of that runs everywhere, always. So does anything you do with your hands, since the seat has no opinion about the device you are holding.

Note the pairing inside threadNaming. Choosing a thread's name is a call to the language model, so it is gated; applying a name that arrived from a sibling is a transform of received data, so it is not. Same feature, opposite sides of the line, and the line is drawn by where the non-determinism sits.

The gate itself is one boolean (a single true-or-false flag) on DeviceRoleService:

var isDriving: Bool { holdsSeat && !yielding }

AgentRuntime.run returns nil when this device is not driving, and callers treat nil as "a sibling has this." One asymmetry worth flagging: the AgentActivity you pass to run is not consulted in the decision. It documents intent at the call site, and it gives the resumable activities an anchor when the seat changes hands; but the decision itself is the same account-wide boolean for all eight.

One gated thing is not cognition at all: publishOwnKeyTransparencyIdentity (which posts this account's device keys to the public append-only log a contact can audit them against) advances a shared version counter that two devices publishing at once would fight over, so it rides the same check. Same shape, different problem.


4. An election with nothing to elect with

The requirement is now stated: exactly one device may run autonomous work, and which one changes as devices come and go. That is leader election, one of the oldest problems in distributed systems, with a large literature of good answers, almost all of which assume something this system deliberately does not have.

There is no election service: nothing in the deployment runs one. There is no consensus protocol either: no Raft, no Paxos (the standard algorithms for getting a set of machines to agree on one value by majority vote), no quorum, meaning no rule that a majority of machines must agree. A quorum is an awkward fit here anyway. The typical account has two devices; a majority of two is two; and requiring both to be reachable would stop your agent the moment your iPad's battery dies.

There is a server that knows your devices exist. GET /v1/sync/siblings on identity-svc returns your account's device pubkeys, and it must: membership has to be server-authoritative or a removed device could talk itself back in (Joining and Leaving). But look at the query:

SELECT pubkey, mldsa_envelope_pubkey FROM identity_records
 WHERE user_id = $1 AND revoked_at IS NULL ORDER BY created_at DESC

A set and a registration order. Not one column about liveness: which device is awake right now. Giving it one is what the design refuses, and the refusal is not squeamishness. A presence table here would be a minute-by-minute record of when you pick up which device, held by a server that already knows which account you are: a behavioural profile, produced by a feature whose entire purpose is internal bookkeeping.

The relay could not help even if you wanted it to. The heartbeats that carry seat state are ordinary sealed envelopes on a sibling subject: the label the relay files a message under, here an opaque, rotating value derived from your account key and the receiving device's pubkey, computed exactly the way your conversations' pair subjects are. The relay sees a subject and a blob of encrypted bytes: it cannot separate your devices' traffic from a friend's, cannot count your devices, and has no way to answer "who is online" if asked. The payload is two bytes.


5. Three answers that do not survive contact

A lock row. The industrial answer, and a good one: put a row in a database, have each device try UPDATE seat SET holder = me WHERE holder IS NULL OR lease_expires < now(), and let the winner drive. The winner's claim is a lease: a hold that expires unless renewed. It fails here twice. The first reason is §4's: a lease has to expire, so the server must be told continually that you are alive. The lock service is a presence service wearing a different hat. The second would bite even if you accepted the first. A lease length is a guess about how long a device may be unreachable while still being fine. Set it short, and your Mac loses the seat mid-huddle over a four-second Wi-Fi handoff. Set it long, and the seat sits dead for a minute after your phone's battery dies. Phones make that guess far harder than servers do (§7).

Whoever is awake first. Skip the coordination: each device checks whether anyone else seems to be driving, and drives if not. This is a race, and the interesting part is that it is not a rare one. Autonomous work is usually triggered by something arriving, and §1 established that an inbound envelope fans out to every device at once, so all your devices wake on the same event and run the same check against the same stale information. Simultaneous wake is not the corner case here; it is the normal case. A protocol whose correctness depends on two devices not deciding at the same instant is being asked for the one thing this workload guarantees it will not get.

A timestamp tiebreak. Add an ordering: newest claim wins, or longest-awake wins. That requires two devices to agree what time it is, and they do not. A phone's clock is set by the OS, drifts between syncs, jumps at timezone and daylight-saving boundaries, and can be moved by the user. Mechanism: Clocks You Cannot Trust covers why comparing wall-clock times across devices is unsafe in general; the harm here is that it fails silently. A mis-resolved tiebreak does not throw an error. It elects the wrong device, and everything downstream behaves as though the election succeeded.

That left a visible mark on the code. Every time comparison in DeviceRoleService is between a timestamp it recorded itself (lastHeard[pubkey] = .now) and its own current time. Both endpoints of every subtraction come from the same device's clock, so there is no clock skew (no disagreement between two clocks) left to corrupt the answer.


6. The two failures, and why they pull apart

Two things can go wrong. They are opposites, and naming them is most of the work.

Orphaned control: nobody drives. No device believes it holds the seat, so no autonomous work runs anywhere. The symptom is silence (notes stop appearing, nudges stop arriving, a huddle invitation goes unanswered), and nothing errors, because from each device's point of view it is correctly deferring to a sibling. This is the failure with no alarm attached, which makes it the more dangerous of the two despite being the less dramatic.

Sustained overlap: two devices drive. Everything happens twice: duplicate notes, duplicate nudges, and, in the case that leaves your machines and reaches other people, two of your agents in one huddle.

Now the part that makes this a design problem rather than a matter of care. Consider a handoff of the seat from device B to device A. There is a moment B stops holding and a moment A starts, separated by a message crossing a network, so one happens first.

If B releases first, there is an interval with no holder. If A then crashes, or never receives the message, that interval never ends, and you have orphaned control. If B holds until it knows A has taken over, there is an interval with two holders, and that is overlap. There is no third ordering. You do not get to choose whether there is a window; only which window it is.

IF B RELEASES FIRST THE SEAT TIME → B A NO HOLDER → ORPHANED CONTROL ENDS ONLY BY TIMEOUT THERE IS NO THIRD ORDERING IF B HOLDS UNTIL IT KNOWS A HAS IT B A TWO HOLDERS → OVERLAP ENDS ON A POSITIVE SIGNAL YOU CHOOSE WHICH WINDOW EXISTS — NEVER WHETHER ONE DOES

That is why tuning does not rescue you. The one parameter available (how long to wait before assuming a device is gone) slides you along a single curve. Shorten it and you steal the seat from devices that were merely slow, producing overlap; lengthen it and the seat stays empty longer after a device dies, producing orphaned control. Aggressively avoiding one failure is a description of how to cause the other.

Given that, the design picks the overlap window (the one that ends on a positive signal rather than a timeout) and removes its teeth, by separating holding the token from acting on it, so a device can be the nominal holder while having already stopped doing anything. The Driver's Seat is that mechanism in full, and this article deliberately stops here.


7. "Online" is not a stable answer

Both failure modes reduce to one question (is that other device up?), and phones are unusually bad at answering it. On a server fleet, "up" is close to a stable property: machines are plugged in, on a known network, and a few missed heartbeats really is evidence of trouble. None of that transfers.

So any answer to "is it online" has a half-life, and the code is careful about what its answer means. presenceWindow is 8 seconds, and its comment spends most of its length on what it is not: not a passive "we overheard something recently" decay, but "answered our most recent handshake." There is no periodic poll.

The check is event-driven. The first call inside a handshakeDebounce window (5 seconds; repeat calls inside the window collapse into that first one) pings every sibling asking for an immediate reply, waits one round trip (settleDelay, 1.5 seconds in the app, 0 in tests), then decides on whoever answered. An idle account generates no heartbeat traffic at all.

Notice the inversion. §5 said simultaneous wake is what makes the naive race unavoidable. It is also what makes an event-driven check cheap and well-timed: every sibling handshakes on the same event, so they converge precisely when there is work to converge about. The property that broke the easy answer is load-bearing for the real one.

The cost is that 8 seconds is aggressive: a device genuinely online but slow to answer one handshake reads as offline, and something else takes the seat. The code's defence is that seat assignment is per-event and self-correcting, a claim that only holds if the handoff is safe, which is the burden The Driver's Seat carries.


8. The backstops underneath

If the seat were a hard mutual-exclusion lock (one that guarantees a single holder at every instant), no activity would need to defend itself against running twice. Every gated activity does anyway.

Note-taking early-exits on a watermark and writes through a path that will not clobber an edited note. The reach-out nudge carries a per-contact cooldown derived from the row itself, described in its comment as what makes "re-runs and driver handoffs idempotent, so firing on every foreground is safe." The evening check-in stamps the local calendar day before the slow generation runs, and names the case it is defending against: a handoff race. A live huddle refuses a second concurrent run of the same cohort (the same huddle group) on the same device. The exclusion it needs is over the cohort's own MLS session (MLS is Messaging Layer Security, the protocol that gives a group one shared encrypted session) and its cursor, not over the device. Different cohorts interleave at the level of a turn, so a member of three cliques serves all three rather than holding two of them until the first finishes.

Put plainly: the seat narrows duplicate autonomous work to a window, and each activity is expected to survive that window on its own. It is a filter, not a lock.

The evening check-in also reveals what each check costs, in the ordering of its gate stack. isDriving is evaluated last, after seven purely local reads (feature on, home captured, visit ongoing, close enough to home, past the evening hour, not already fired today, not mid-conversation), and the comment says why: callers pre-flight with isDriving: true so they "only pay the driver's-seat relay handshake when everything else already passes." Read top to bottom, that gate stack is a list of checks sorted by price.


9. The residual

Five things this framing does not give you, stated before you find them.

The gate fails open. When it cannot decide, it lets the work run rather than blocking it. Seat reconciliation begins by locating this device in the ranked roster, and if it cannot find itself it takes the seat unconditionally; the comment reads act solo so the agent never stalls. But "cannot find itself" also covers the case where the roster fetch failed, because siblings() yields an empty list on error. So an identity-svc outage, or a network blip all your devices hit at once, produces §6's sustained overlap on every device at once. That is a deliberate trade (an agent that keeps working, chosen over one that is provably singular), and the §8 backstops are what make it survivable. A chosen cost, and the largest hole in this article's property.

It is eventual, not instantaneous. Convergence is bounded by the presence window plus the handshake round, so there is a real interval after a device wakes in which the wrong device believes it drives.

The token is not the invariant. During a handoff two devices hold the token and only one acts. Exclusion is carried by isDriving (the combination of holding the seat and not yielding it), not by uniqueness of the token. So code that reads holdsSeat and thinks it asked "am I the agent" asked a different question.

Rank has nothing to do with fitness. The ordering derives from what identity-svc returns (registration order, newest first, reversed), which is uncorrelated with battery, thermal headroom, network quality, which model a device can run, or which device is in your hand. There is a user-facing override, covered in The Driver's Seat, but the default is an accident of history.

The seat does not partition work. One token, every activity, and the activity is not an input to the decision. The device that drives, drives everything: a Mac deep in a huddle is also expected to run the note-taking pass. Splitting the seat by activity is not something this design can express.

What remains is the mechanism: how the ordering is fixed without negotiation, and how the handoff makes the overlap window harmless. That is The Driver's Seat.


References & further reading

← Joining and LeavingMechanism: Reconciling by Digest →