Agent skill

Effect Atom Optimistic Updates

by UsefulSoftwareCo in UsefulSoftwareCo/executor

Pattern for implementing optimistic UI updates with effect-atom in this codebase.

MITAuto-check passedFrontend & Design

Install Effect Atom Optimistic Updates

skills CLI
$ npx skills add UsefulSoftwareCo/executor --skill effect-atom-optimistic-updates -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install UsefulSoftwareCo/executor effect-atom-optimistic-updates --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/UsefulSoftwareCo/executor.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.skills/effect-atom-optimistic-updates .claude/skills/effect-atom-optimistic-updates && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
effect-atom-optimistic-updates
GitHub stars
4.1k
Token cost
~2.5k tokens
SKILL.md length
811 words
Files
1
Skills in repo
21
Repo updated
First seen
Licence
MIT

At a glance

Pattern for implementing optimistic UI updates with effect-atom in this codebase.

  • Works in 4 steps: User clicks "set action = block" →… → User clicks "set action = approve" →… → A's response returns first →… → …
  • Adding optimistic behavior to a query atom + its mutations (action toggles
  • SKILL.md covers When to use, Why not roll your own, Pattern and Consuming in components, plus 7 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

Effect Atom Optimistic Updates is an agent skill from UsefulSoftwareCo/executor. Pattern for implementing optimistic UI updates with effect-atom in this codebase. Use when adding optimistic behavior to a query atom + its mutations (action toggles, list adds/removes, inline edits). DO NOT roll your own pending-state with React state, Maps, or custom merge helpers — Atom.optimistic + Atom.optimisticFn already handle racing, refresh, and waiting correctly.

Its SKILL.md is about 2.5k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Frontend & Design, covering State management. The repository describes itself as: The missing integration layer for AI agents. Let them call any OpenAPI / MCP / GraphQL / custom js functions in secure environment. The licence is MIT.

When your agent uses it

  • Adding optimistic behavior to a query atom + its mutations (action toggles
  • List adds/removes

Example prompts

  • “/effect-atom-optimistic-updates”

Workflow steps

4 steps, taken from the first numbered list in SKILL.md.

  1. User clicks "set action = block" → mutation A fires, pending entry written
  2. User clicks "set action = approve" → mutation B fires, pending entry overwritten with B
  3. A's response returns first → finally-block clears the pending entry → UI flickers back to the server's "block" value
  4. B's response returns → UI shows "approve"

What it can do on your machine

Read from SKILL.md and the folder at commit 27dccb8. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are typescript).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Effect Atom Optimistic Updates loads about 2.5k tokens when it runs. Until then it costs about 103 tokens; SKILL.md has 811 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~103
When it runs · the whole SKILL.md, loaded when a task matches
~2.5k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from UsefulSoftwareCo/executor at commit 27dccb8, republished under its MIT licence (© UsefulSoftwareCo). 811 words, ~2,540 tokens.

Download SKILL.mdSave it as .claude/skills/effect-atom-optimistic-updates/SKILL.md (or your agent's skills folder).
name
effect-atom-optimistic-updates
description
Pattern for implementing optimistic UI updates with effect-atom in this codebase. Use when adding optimistic behavior to a query atom + its mutations (action toggles, list adds/removes, inline edits). DO NOT roll your own pending-state with React state, Maps, or custom merge helpers — `Atom.optimistic` + `Atom.optimisticFn` already handle racing, refresh, and waiting correctly.

effect-atom Optimistic Updates

The @effect-atom/atom-react library ships first-class optimistic support via Atom.optimistic and Atom.optimisticFn. Use them directly. Do not write a custom "pending entries" layer (Maps, useState, useRef) on top of useAtomValue — it will not handle racing updates correctly, and the existing helpers in packages/react/src/api/optimistic.tsx are legacy patterns kept only for sources/connections.

When to use

  • A list query atom (Atom.optimistic wraps the query)
  • Plus one or more mutation atoms that change rows in that list (create / update / delete)
  • And you want the UI to reflect the change immediately on click, before the server roundtrip

If you only need the UI to be "eventually consistent" (i.e. you're fine waiting ~200ms for the server response and the existing reactivity refetch), skip optimistic — just use the mutation directly with reactivityKeys.

Why not roll your own

The naive approach — track pending: Array<{id, value}> in a separate atom and merge it with the server result — has a subtle race that bites on rapid edits:

  1. User clicks "set action = block" → mutation A fires, pending entry written
  2. User clicks "set action = approve" → mutation B fires, pending entry overwritten with B
  3. A's response returns first → finally-block clears the pending entry → UI flickers back to the server's "block" value
  4. B's response returns → UI shows "approve"

Step 3 is the bug. Fixing it correctly requires per-call entry ids and "last entry per row id wins" merging — at which point you've reimplemented a worse version of Atom.optimistic's transition tracking.

Atom.optimistic solves this because the runtime reads the current optimistic state (including any in-flight transitions) and passes it to your reducer as current, so B stacks on top of A correctly. When all transitions settle, it calls refresh(self) to pull the server's authoritative state.

Pattern

Define optimistic atoms next to the underlying query and mutations in the atoms.tsx (or equivalent) module. Each scope-keyed list gets a family that wraps the query with Atom.optimistic, and each mutation gets a family that pipes the optimistic atom through Atom.optimisticFn with a reducer.

typescript
import { Atom, Result } from "@effect-atom/atom-react";
import type { ScopeId, PolicyId, ToolPolicyAction } from "@executor/sdk";

import { ExecutorApiClient } from "./client";

// 1. The plain query atom — same as before.
export const policiesAtom = (scopeId: ScopeId) =>
  ExecutorApiClient.query("policies", "list", {
    path: { scopeId },
    timeToLive: "30 seconds",
    reactivityKeys: [ReactivityKey.policies],
  });

// 2. Plain mutations — same as before. These are the underlying `fn` for
//    the optimistic wrappers below.
export const createPolicy = ExecutorApiClient.mutation("policies", "create");
export const updatePolicy = ExecutorApiClient.mutation("policies", "update");
export const removePolicy = ExecutorApiClient.mutation("policies", "remove");

// 3. Optimistic read atom. `Atom.family` memoizes per-scope so every consumer
//    references the same optimistic atom instance and shares transition state.
export const policiesOptimisticAtom = Atom.family((scopeId: ScopeId) =>
  Atom.optimistic(policiesAtom(scopeId)),
);

// 4. Optimistic mutation. The reducer takes the same arg as the underlying
//    mutation and returns the next list state. `Result.map` keeps the
//    Result wrapper intact.
export const updatePolicyOptimistic = Atom.family((scopeId: ScopeId) =>
  policiesOptimisticAtom(scopeId).pipe(
    Atom.optimisticFn({
      reducer: (
        current,
        arg: {
          path: { scopeId: ScopeId; policyId: PolicyId };
          payload: { action?: ToolPolicyAction };
          reactivityKeys?: ReadonlyArray<unknown>;
        },
      ) =>
        Result.map(current, (rows) =>
          rows.map((r) =>
            r.id === arg.path.policyId && arg.payload.action !== undefined
              ? { ...r, action: arg.payload.action }
              : r,
          ),
        ),
      fn: updatePolicy,
    }),
  ),
);

Consuming in components

Read from the optimistic atom; write through the optimistic mutation. The existing reactivityKeys plumbing still applies — pass them in the call.

typescript
import { useAtomValue, useAtomSet } from "@effect-atom/atom-react";

import { policiesOptimisticAtom, updatePolicyOptimistic } from "../api/atoms";
import { policyWriteKeys } from "../api/reactivity-keys";

export function PoliciesPage() {
  const scopeId = useScope();

  // Read: this Result reflects in-flight optimistic state on top of server data.
  const policies = useAtomValue(policiesOptimisticAtom(scopeId));

  // Write: same call signature as the underlying mutation.
  const doUpdate = useAtomSet(updatePolicyOptimistic(scopeId), { mode: "promise" });

  const handleUpdate = async (id: string, action: ToolPolicyAction) => {
    await doUpdate({
      path: { scopeId, policyId: PolicyId.make(id) },
      payload: { action },
      reactivityKeys: policyWriteKeys,
    });
  };

  // ...
}

Reducer rules

  1. current is the FULL Result, not the unwrapped value. Use Result.map to update inside the success case — the wrapper preserves Initial/Failure states correctly.
  2. The reducer is called for every transition, including ones that stack on top of in-flight ones. Read current and produce next — don't track "the previous optimistic value" yourself.
  3. The reducer signature must match the mutation's arg shape. Effect-atom passes the raw mutation arg (e.g. { path, payload, reactivityKeys }) to both the reducer and the underlying fn. Don't try to build a "nicer" arg shape unless you also wrap the underlying mutation.
  4. Be pure. No side effects, no calls to Date.now() for stable values, no random ids unless you need a placeholder row id (see "Adds" below).
Show full SKILL.md (332 more words)Show less

Adds (server mints the id)

For create flows the server assigns the canonical id. The reducer inserts a placeholder with a temp id — the post-commit refresh replaces it with the canonical row.

typescript
export const createPolicyOptimistic = Atom.family((scopeId: ScopeId) =>
  policiesOptimisticAtom(scopeId).pipe(
    Atom.optimisticFn({
      reducer: (
        current,
        arg: {
          path: { scopeId: ScopeId };
          payload: { pattern: string; action: ToolPolicyAction };
          reactivityKeys?: ReadonlyArray<unknown>;
        },
      ) =>
        Result.map(current, (rows) => [
          {
            id: PolicyId.make(`pending-${Math.random().toString(36).slice(2)}`),
            scopeId,
            pattern: arg.payload.pattern,
            action: arg.payload.action,
            position: -Number.MAX_SAFE_INTEGER, // sort to top
            createdAt: Date.now(),
            updatedAt: Date.now(),
          },
          ...rows,
        ]),
      fn: createPolicy,
    }),
  ),
);

The placeholder doesn't need to roundtrip through the id field unless your list rendering keys on it (it usually does — <Row key={p.id}>). A unique prefix like pending- is fine.

Removes

typescript
export const removePolicyOptimistic = Atom.family((scopeId: ScopeId) =>
  policiesOptimisticAtom(scopeId).pipe(
    Atom.optimisticFn({
      reducer: (
        current,
        arg: {
          path: { scopeId: ScopeId; policyId: PolicyId };
          reactivityKeys?: ReadonlyArray<unknown>;
        },
      ) => Result.map(current, (rows) => rows.filter((r) => r.id !== arg.path.policyId)),
      fn: removePolicy,
    }),
  ),
);

How racing is handled (mental model)

You don't have to think about this — it works — but understanding helps:

  • Atom.optimistic(self) wraps the underlying atom and tracks a transitions set
  • Each Atom.optimisticFn call creates one shared transition state per (scope, mutation)
  • A call: runtime reads the current optimistic state (including in-flight transitions), invokes reducer(current, arg) → value, sets transition to Success(value, waiting=true), calls the underlying mutation fn with arg
  • The next call to the same optimisticFn sees the prior call's optimistic value as current — so it stacks on top
  • When fn settles, both calls' subscribers fire, the transition flips to non-waiting, and refresh(self) pulls the server state
  • The server's authoritative response replaces the optimistic state via the underlying atom's normal subscribe path

Net result: rapid edits look smooth, the last edit wins both visually and on the server, no flickers, no manual cleanup.

Things to avoid

  • ❌ useState/useRef to hold pending values
  • ❌ Map / Set of in-flight ids
  • ❌ Custom mergePending helpers
  • ❌ try/finally blocks that "clear the placeholder" — optimistic clears for you
  • ❌ Reading policiesAtom directly in the component while writing through updatePolicyOptimistic — they have different transition state, you'll see jumps

Reference implementation

packages/react/src/api/atoms.tsx (search for policiesOptimisticAtom) and packages/react/src/pages/policies.tsx show the full pattern: optimistic read, optimistic create/update/remove, no custom state.

When you must NOT use this

  • The mutation has cross-cutting effects on data that isn't in the same list (e.g. a single mutation invalidates tools AND policies). Reactivity keys still handle that — optimistic only paints the list-local change.
  • You need to show transient UI state that isn't a row property (toasts, dirty indicators per field, pending counts). Those belong in component state, not in the atom layer.

© UsefulSoftwareCo, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .skills/effect-atom-optimistic-updates of UsefulSoftwareCo/executor.

Open the folder on GitHubat commit 27dccb8

Compare with similar skills

Effect Atom Optimistic Updates next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Effect Atom Optimistic Updates compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Effect Atom Optimistic Updates this skillUsefulSoftwareCo/executor4.1k—~2.5kAutomated safety check: PassMIT
Svelte Core Best Practicesrilldata/rill2.9k4 repos~1.8kAutomated safety check: PassApache-2.0
Dify Component Writing Guidelanggenius/dify158k—~626Automated safety check: PassCustom licence
GPUI Kit Desktop App GuideAprilNEA/OpenLogi23k—~5.5kAutomated safety check: PassApache-2.0
React State Managementinvolvex/youtube-music-cli45612 repos~3kAutomated safety check: PassMIT
Pierre Theming Librarypierrecomputer/pierre6.2k—~661Automated safety check: PassApache-2.0

Similar skills

  • Rules for writing idiomatic Svelte 5 code: when to reach for runes like state, derived and effect, and how to handle props, attachments and bindings.

    2.9k GitHub starsUsed in 4 repos~1.8k tokens
    Frontend & DesignAuto-check passed
  • Use when implementing or refactoring React/TypeScript components and the task requires decisions about component ownership, feature boundaries, state, data…

    158k GitHub stars~626 tokensUpdated today
    Frontend & DesignAuto-check passed
  • Guides building Rust desktop apps with the gpui-kit crate, covering component selection, state ownership, theming and overlays, plus normative GPUI coding rules.

    23k GitHub stars~5.5k tokensUpdated 4 days ago
    Frontend & DesignAuto-check passed
  • React State Management

    involvex/youtube-music-cli

    Master modern React state management with Redux Toolkit, Zustand, Jotai, and React Query.

    456 GitHub starsUsed in 12 repos~3k tokens
    Frontend & DesignAuto-check passed
  • Pierre Theming Library

    pierrecomputer/pierre

    Explains how to use the @pierre/theming package to list, resolve, select, switch and persist themes, with controller, color and React references.

    6.2k GitHub stars~661 tokensUpdated yesterday
    Frontend & DesignAuto-check passed
  • Frontend Patterns

    kurealnum/dotfiles

    Frontend development patterns for React, Next.js, state management, performance optimization, and UI best practices.

    290 GitHub starsUsed in 19 repos~3.7k tokens
    Frontend & DesignAuto-check passed

More from UsefulSoftwareCo/executor

All 21 skills in this repo
  • Effect Client Wrapper

    UsefulSoftwareCo/executor

    Pattern for wrapping third-party SDK clients (Stripe, Resend, AWS, etc.) with Effect.

    4.1k GitHub starsUsed in 1 repo~1.4k tokens
    Auto-check passed
  • CLI Release

    UsefulSoftwareCo/executor

    Runbook for releasing the executor CLI package (stable and beta).

    4.1k GitHub stars~2k tokensUpdated today
    Auto-check passed
  • Effect HTTP Testing

    UsefulSoftwareCo/executor

    Testing Effect HttpApi services end-to-end. An agent skill from UsefulSoftwareCo/executor.

    4.1k GitHub stars~1.6k tokensUpdated today
    Auto-check passed
  • Emulate

    UsefulSoftwareCo/executor

    Use the @executor-js/emulate service emulators (GitHub, Google, Stripe, Resend, WorkOS, …) to test integrations for real — full OpenAPI specs, working OAuth flows, mintable credentials, and a…

    4.1k GitHub stars~2.2k tokensUpdated today
    Auto-check: notes
  • Prod Telemetry

    UsefulSoftwareCo/executor

    Query Executor's production telemetry — Axiom traces (executor-cloud dataset), prod Postgres via PlanetScale, PostHog product analytics — through the Executor MCP.

    4.1k GitHub stars~1.9k tokensUpdated today
    Auto-check passed
  • Self Contained Modals

    UsefulSoftwareCo/executor

    Build modals/dialogs self-contained: form and in-flight state lives inside, closing unmounts it.

    4.1k GitHub stars~878 tokensUpdated today
    Auto-check passed

Questions about Effect Atom Optimistic Updates

What does Effect Atom Optimistic Updates do?

Pattern for implementing optimistic UI updates with effect-atom in this codebase. Effect Atom Optimistic Updates is an agent skill from UsefulSoftwareCo/executor. Pattern for implementing optimistic UI updates with effect-atom in this codebase.

When should I use Effect Atom Optimistic Updates?

Effect Atom Optimistic Updates fits situations like: adding optimistic behavior to a query atom + its mutations (action toggles; list adds/removes.

How do I install Effect Atom Optimistic Updates in Claude Code?

Run `npx skills add UsefulSoftwareCo/executor --skill effect-atom-optimistic-updates -a claude-code`. Or copy the skill folder (.skills/effect-atom-optimistic-updates in UsefulSoftwareCo/executor) into .claude/skills/effect-atom-optimistic-updates in your project. Claude Code loads it when a task matches its description.

How do I install Effect Atom Optimistic Updates in Codex?

Run `npx skills add UsefulSoftwareCo/executor --skill effect-atom-optimistic-updates -a codex`. Or copy the skill folder (.skills/effect-atom-optimistic-updates in UsefulSoftwareCo/executor) into .agents/skills/effect-atom-optimistic-updates in your project. Codex loads it when a task matches its description.

Can I use Effect Atom Optimistic Updates in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add UsefulSoftwareCo/executor --skill effect-atom-optimistic-updates -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/effect-atom-optimistic-updates, .gemini/skills/effect-atom-optimistic-updates, .github/skills/effect-atom-optimistic-updates and .opencode/skills/effect-atom-optimistic-updates in your project.

What does Effect Atom Optimistic Updates need to run?

SKILL.md names no scripts, command-line tools or credentials: Effect Atom Optimistic Updates is instructions for the agent only.

Does Effect Atom Optimistic Updates access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Effect Atom Optimistic Updates safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Effect Atom Optimistic Updates use?

Effect Atom Optimistic Updates is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Effect Atom Optimistic Updates use?

About 2.5k tokens (SKILL.md is roughly 10k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Effect Atom Optimistic Updates?

Skills that share tags, products or a category with Effect Atom Optimistic Updates: Svelte Core Best Practices (rilldata/rill, 2.9k stars), Dify Component Writing Guide (langgenius/dify, 158k stars), GPUI Kit Desktop App Guide (AprilNEA/OpenLogi, 23k stars) and React State Management (involvex/youtube-music-cli, 456 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Effect Atom Optimistic Updates?

UsefulSoftwareCo (a GitHub organization) maintains it in UsefulSoftwareCo/executor, which has 4,085 GitHub stars. The repository holds 21 skills in this directory. The repository was last updated on October 7, 2026.

Source: UsefulSoftwareCo/executor on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.