3 Principles Fiber Teaches Us About AI Agent State Design
Why not just write “what is Fiber”
React Fiber had a piece hit 6012 heat score on Juejin last week. Deep-dive explainers on the same topic are all over the internet — acdlite/react-fiber-architecture, the original 2016 design doc, is still the best intro material, and yet another rewrite is just paraphrasing.
What’s actually worth writing, and nobody writes, is — what can Fiber’s three core mechanisms (double buffering, time slicing, lanes priority) teach us about AI Agent state design? Most people who write about Fiber don’t build agents; most people who build agents don’t study Fiber. The analogy layer between them is empty.
I’m not a deep React user (the TableOfContents.astro ponytail tested in blog202 is a component on this site — the blog runs on Astro, not React), so this piece isn’t “look at what I built with Fiber.” It’s “what I stole from Fiber’s design and applied to my AI Agent practice.” Each of the three principles corresponds to a concrete decision I’ve dogfooded, and blog194 project passport, blog195 loop debt, and blog202 ponytail hands-on all line up.
The value of cross-domain analogy is “design principles validated over 10 years on one side can be borrowed directly by a new field on the other.” React Fiber has been in production for 9 years since 2017; Facebook / Meta uses this architecture internally to hold up applications with 100k+ components. Its design constraints were forged under extreme conditions. AI Agents are only 2-3 years old — the detours we can skip, we should skip on purpose.
Principle 1: Double buffering (current vs work-in-progress) → separating “proposed” from “applied” agent state
How Fiber does it
React maintains two Fiber trees at the same time internally:
- current tree: the Fiber corresponding to what’s on screen right now
- work-in-progress tree (WIP): the Fiber React is “hypothesizing” in the background as the next state
The WIP tree is built independently in memory — invisible to the user, interruptible at any time, disposable and rebuildable. Only when the WIP tree is fully ready does React atomically swap the two trees in the commit phase (root.current = workInProgress).
This design has a very important property: no “half-finished UI” ever appears. The user always sees a consistent screen — either 100% old or 100% new, no transitional state in between.
What AI Agents should steal
Most early AI Agent state designs are “mutate reality directly” — LLM generates tool call → execute directly → write file / send message directly. This is the same mistake React made when it mutated the DOM directly early on: “UI / world is seen by the user in a half-finished state.”
Ponytail hands-on lesson (in blog202 I installed ponytail on the blog’s 196-line TableOfContents component) — one key detail I noticed: ponytail’s first rung to the AI is “run through the 7-step decision ladder before touching anything,” not “see the requirement and immediately change code.” That separates the “proposed state” (ladder reasoning) from the “applied state” (writing code), and it mirrors Fiber’s WIP / current separation exactly.
Concrete moves for AI Agent state design:
- Keep maker (proposer) and verifier (checker) context strictly separate — one of the three loop-engineering debts in blog195, the verification debt, comes down to this. The verifier prompt cannot see the maker’s reasoning process, otherwise it gets “hypnotized” by the maker — the same way React would leak state if the WIP wrote directly to current and saw its own prior output.
- File writes should stage before commit — Claude Code’s PreToolUse hook can intercept before the Write tool fires: write to a
.tmpdirectory first, run lint/test/typecheck, then atomically rename. This is the equivalent of Fiber’s commit phase. - Memory updates in two phases — you can push the memory management from blog194 project passport one step further: write a draft first, run a self-check (no conflict with existing AGENTS.md entries, correct time format, tags within the allowed set), and only commit to the main memory file after it passes. This step wasn’t in blog194 — it’s the enhancement I extracted from the Fiber double-buffering analogy.
Counterexample: writing claude API tool call results straight into a prod DB / sending an email / deleting a file with no buffer — that’s an agent without double buffering, where any transient error is irreversible damage.
Principle 2: Time slicing (yielding every 5ms) → checkpoint / resume for long agent tasks
How Fiber does it
The React Scheduler cuts rendering work into small chunks (fiber unit of work). Every ~5ms it checks: does the browser have anything more urgent (user click, animation frame)? Yes → yield, come back next tick. No → continue with the next fiber unit.
This yield isn’t “throw everything away” — it’s save progress, resume from the breakpoint next time. React’s MessageChannel under the hood is exactly this “run a slice, yield, run a slice” loop.
Key property: long tasks can’t drag down short interactions. A user click always takes priority, even if React is rendering a 5000-node tree.
What AI Agents should steal
The most common failure mode inside agent loops is “a task runs 30 minutes without checking any external signal”: the agent decides to refactor an entire codebase → sprints ahead → half an hour later the user tries to interrupt and finds Ctrl+C unresponsive (because the agent is waiting on an LLM streaming response).
The $4,200 LeanOps case (blog195): an autonomous refactor loop ran for two days over a weekend. The humans went home, the agent had no checkpoint, no equivalent of a 5ms yield mechanism, and just burned tokens straight through until Monday morning’s bill arrived and revealed the direction had been wrong the whole time.
Three specific things agents should steal from time slicing:
- The agent loop needs “flush to persistent state every N tool calls” — resumable from a breakpoint rather than restarting from scratch. Analogous to React’s fiber unit of work: every 5ms, note down progress.
- Checkpoint contents should be the “minimum resumable set” — current goal description, completed sub-goals, pending sub-goals, key intermediate artifact paths. Like the
alternatepointer +child/siblingstructure stored in a fiber node, use minimum info to reconstruct the full tree. - Long-running agents must expose a “cooperative interrupt interface” — not a kill signal, but “please stop after the next checkpoint.” Fiber’s
shouldYield()is exactly this — don’t hard-interrupt the current unit, ask “can you stop at the next safe point?”
Claude Code’s counterpart: the session-resume capability discussed in blog194 — you close the terminal yesterday, today claude --resume picks up from the previous message history + tool state. Behind this is every step flushing state to ~/.claude/projects/<hash>/. This design and Fiber’s time slicing checkpoint are two expressions of the same thing: any long task must be interruptible, saveable, resumable.
Counterexample: a while (True) { tool_call() } loop inside an agent with no checkpoint output and no shouldYield check — one power outage and all progress is gone. Or, more commonly: progress lives only in memory, and the agent process crashes and it vanishes.
Principle 3: Lanes priority (31-bit bitmask) → P0/P1 tiered scheduling for agent tasks
How Fiber does it
React’s Lanes system uses a 31-bit bitmask to represent updates at different priorities. Core lane definitions:
- SyncLane: highest priority, user discrete events (click, keypress) — must respond immediately
- InputContinuousLane: continuous input (scroll, mousemove) — high priority but batchable
- DefaultLane: regular state updates
- TransitionLane: updates marked by
useTransition, where users tolerate slower (page navigation etc.) - IdleLane: lowest priority, runs only when everything else is idle
Every time the scheduler decides “what to do next,” it reads the highest bit in the bitmask and processes that lane first. Work on low-priority lanes can be interrupted by higher-priority lanes (back to Principle 2’s interruptibility).
Key property: work with different stakes goes to different lane scheduling, avoiding “I clicked a button but the UI got stuck on background data loading.”
What AI Agents should steal
In most agent systems all tool calls are equal — Write to a config file and Bash an rm -rf go through the same execution stack, the same confirm, the same retry strategy, the same timeout. This is wrong.
Ponytail’s A/B/C three-tier code stratification (blog197 vibe coding maintenance) + the verifier tier division in loop debt (blog195) both point in this direction, but neither is as fine-grained as Lanes.
Three specific things agents should steal from lanes:
- Tool calls should be laned by blast radius — low risk (read file, grep) goes to IdleLane no-confirm; medium risk (write to project scratch dir) goes to DefaultLane with logging; high risk (git push, prod deploy, send email, rm) goes to SyncLane with forced human confirm. Just like Fiber, work on different lanes goes through different pipelines.
- User-facing operations (edit code, send message) priority > background batch work (memory tidying, log archiving) — like SyncLane over IdleLane. While the agent is waiting for the user to read its previous message, it can run memory cleanup on IdleLane in the background.
- Priority is not a numeric magnitude, it’s a classification — React uses a bitmask rather than a numeric priority because work in multiple lanes may need to be processed together (bitmask OR). Agents are similar: a task can simultaneously be “high blast radius” (needs confirm) + “user-facing” (needs fast response) — both attributes need marking, and the scheduling strategy has to read both. You don’t have to force bitmask bit operations — for agent scenarios tag combinations are enough (the counter-boundary section will expand on this).
Claude Code’s counterpart: PreToolUse hook plus a whitelist/blacklist for the Bash tool — whitelisted tools (git status, ls, grep) auto-allow, blacklisted (rm -rf, git push --force) forced intercept + confirm. This is a crude implementation of laning tools by blast radius. A true Lanes-level implementation would be statically classifiable at each tool call site + dynamically scheduled at runtime.
Counterexample: putting every tool call under a binary “always confirm” or “never confirm” — the former fatigues the user into pressing Yes on everything (echoing the Stack Overflow “decision fatigue” piece cited in blog195), the latter leaves high-risk actions with zero protection. Both extremes are the product of no lanes system.
What Fiber can’t teach: React is a finite tree, an agent is an infinite loop
I have to draw a counter-boundary here, otherwise the analogy becomes a template. Some Fiber design premises don’t hold in the agent domain:
- Every React commit is a convergence point (this render is complete, UI is stable, even if the next update overturns it), but an agent loop is open-ended — there’s no natural moment of “this task is done,” only “user said stop” or “budget exhausted.” So the “commit moment” of double buffering in agents is nowhere near as crisp as in React, and requires an additional convergence check (after this step, has the target state been reached?).
- React has 31 statically defined lanes (fixed at compile time), but the number of agent tools and risk levels is dynamic — user-defined MCP tools, runtime-loaded skills can introduce new classifications. So lanes in agents look more like a tag system than a fixed bitmask.
- React’s fiber nodes are immutable data structures + immutable pattern (each update creates a new alternate), but agent state (memory, context, file state) is mostly mutable — because persisting immutable state to disk is too expensive. This means when agents borrow from Fiber they can’t go 100% immutable, only immutable on critical paths.
Point 3 is the deepest difference in the R → A analogy — Fiber trades immutability for predictability, agents trade mutability for efficiency — two different engineering tradeoffs. That’s why the title says “3 principles” instead of “copy the Fiber architecture wholesale” — principles are transferable abstractions, architecture is domain-specific implementation.
Wrap-up: the meta-rule of cross-domain analogy
Three Fiber principles → AI Agent state design:
| Fiber mechanism | Agent counterpart | What I’ve dogfooded |
|---|---|---|
| Double buffering (current/WIP) | maker/verifier separation + stage/commit writes | blog195 verifier sub-agent isolated context / blog194 memory taxonomy foundation + the draft→commit enhancement this post proposes |
| Time slicing (5ms yield) | long-task checkpoint / resume + shouldYield cooperative interrupt | Claude Code --resume / blog195 avoiding the $4,200 runaway |
| Lanes (bitmask priority) | tool calls tiered by blast radius | Claude Code PreToolUse hook / blog197 A/B/C code stratification |
My biggest personal takeaway from writing this isn’t “agents should copy Fiber.” It’s “any mature system that’s run for 10 years — every emerging field will fall into the same traps it did.” React spent 4 years going from stack reconciler to Fiber, 2013 to 2017; the agent field can absolutely skip these traps at 1/10 the time cost.
If you’re building an agent system (LangChain / OpenAI Assistants / a loop you wired up yourself), next time you decide where to store state, how to schedule tools, whether a task is interruptible, ask yourself: how would Fiber do this? Can I steal it here?
The 6012-heat-score Fiber piece on Juejin is worth reading — but after reading, going out and thinking through analogies, going out and stealing principles is 10x more valuable than memorizing the data structure definitions one more time.
Further reading:
- acdlite/react-fiber-architecture - Fiber’s original design doc (written by Andrew Clark in 2016, still the best intro material in 2026)
- React Lanes deep dive - 2026 breakdown of the lanes system’s 31-bit bitmask
- blog194 - AGENTS.md + CLAUDE.md + memory project passport - the practical side of memory draft→commit from Principle 1
- blog195 - Loop Engineering three-debts playbook - detailed reasoning for verifier context separation from Principle 2 + PreToolUse hook from Principle 3
- blog202 - Ponytail 73k stars in three weeks + hands-on - the hands-on record of ponytail’s 7-step ladder from Principle 1