agentleFS
komlukkomluk/scaffolding/skills/state-management/SKILL.md

state-management

Skill16 starsChanged 5 days agoMITView on GitHub

Client state management standards: local-vs-global decisions, store structure, selectors, and re-render performance. TRIGGER when: creating a store, managing global state, or deciding local vs global state. SKIP: component/hook structure (use react-patterns); visual styling (use mui-styling). (Examples use Zustand.)

27 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use css-architecture, i18n and 6 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • Piyush8296Skill

    css-architecture

    CSS architecture, Tailwind patterns, responsive design, design tokens, and styling best practices. Use when implementing designs, setting up styling infrastructure, or debugging layout issues.

    Also in 3 projects that use this

  • lbednerSkill

    i18n

    Use when a code or template change introduces a new translation message key, in either the framework CLI (aegis/i18n/locales/) or a generated project's CLI (the app/i18n/locales/ template tree). Covers adding the real English string, stubbing the same key into every other locale for parity, and the separate translation PR that later replaces placeholders with reviewed native text.

    Also in 4 projects that use this

  • mijunriSkill

    database

    数据库脚本与操作规范。脚本放在 db_scripts 目录,遵循查询优化、事务、安全等实践。

    Also in 3 projects that use this

  • genomewalkerSkill

    resume

    Resume a thread by loading its ~800-token context capsule

    Also in 3 projects that use this

  • NVIDIASkill

    testing

    Run Python and Rust tests for physicsnemo-curator using uv + pytest with coverage reporting via pytest-cov, and cargo-nextest for Rust tests. Includes benchmark workflows with pytest-benchmark and criterion.

    Also in 6 projects that use this

  • 0xSeroSkill

    security

    Also in 4 projects that use this

The file

We split this skill into the rules it gives an agent

7 rules. 0 are common, 3 are distinctive, and 4 are very specific to this project.

  • 0

    Common

    Most of the 21 edited versions we read keep these.

  • 3

    Distinctive

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Use shallow equality for object selections

    line 107
  2. Very specific:

    Use subscribeWithSelector for side effects

    line 110
  3. Very specific:

    Create new objects in selectors without shallow

    line 114
  4. Distinctive:

    Put derived/computed state in store

    line 115
  5. Distinctive:

    Call actions during render phase

    line 116
  6. Distinctive:

    Create deeply nested store structure

    line 117
  7. Very specific:

    Every store defines type XxxState and type XxxActions, then exports the combined type:

    line 164

“Common” is measured: kept by at least 6 in 10 of the 21 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

State Management Skill

Client state management standards and best practices. The universal guidance (local-vs-global decisions, store structure, selectors, performance) applies to any store library; the concrete code examples use Zustand.

When to Apply

  • Creating new state stores
  • Sharing state between components
  • State architecture decisions
  • Performance optimization for state

State Category Guidelines

CategorySolutionUse When
Local UIuseStateSingle component, simple state
Shared UIZustand storeMultiple components need same data
Server dataReact Query / SWRAPI data with caching needs
Form stateuseState / form libraryForm inputs, validation
URL stateuseSearchParamsFilter/sort params, shareable URLs

Zustand Store Standards

Store Structure

ElementRequirement
InterfaceDefine typed state + actions interface
StateGroup related state together
ActionsDefine all mutations as functions
Naminguse[Domain]Store convention

Store Design Principles

PrincipleDescription
Single responsibilityOne store per domain (projects, UI, settings)
Flat structureAvoid deeply nested state
Immutable updatesAlways return new objects
Colocated actionsKeep actions inside store definition

Selector Best Practices

Selection Rules

RuleReason
Select minimal dataReduces re-renders
Use shallow for objectsPrevents unnecessary updates
Memoize derived dataUse useMemo for computed values
Avoid selecting entire storeCauses re-render on any change

Selector Patterns

PatternUse Case
Single value(state) => state.count
Multiple values(state) => ({ a: state.a, b: state.b }), shallow
Derived valueuseMemo outside store

Middleware Usage

MiddlewarePurposeWhen to Use
persistLocalStorage persistenceUser preferences, settings
devtoolsRedux DevTools integrationDevelopment debugging
immerImmutable updatesComplex nested state
subscribeWithSelectorGranular subscriptionsPerformance optimization

Store Organization

File Structure

src/stores/
├── index.ts           # Re-exports all stores
├── projectStore.ts    # Domain-specific store
├── uiStore.ts         # UI state (modals, panels)
└── settingsStore.ts   # User preferences

Store Separation Guidelines

Store TypeContains
Domain storeBusiness entities, selections
UI storeModal states, panel visibility, loading
Settings storeUser preferences, persisted config

Performance Guidelines

DO

  • Select only needed state slices
  • Use shallow equality for object selections
  • Define actions inside store (stable references)
  • Split large stores by domain
  • Use subscribeWithSelector for side effects

DON'T

  • Select entire store object
  • Create new objects in selectors without shallow
  • Put derived/computed state in store
  • Call actions during render phase
  • Create deeply nested store structure

Anti-Patterns

Anti-PatternProblemSolution
Giant storeHard to maintain, performance issuesSplit by domain
Computed in storeStale data, extra complexityUse useMemo
Prop drillingBypasses store benefitsUse store directly
Store in useStateLoses reactivityUse store hook
No TypeScriptRuntime errorsDefine interfaces

Decision Matrix

ScenarioRecommended Solution
Form input stateuseState
Modal open/closeuseState or UI store
Selected item (shared)Domain store
User preferencesPersisted store
API response dataStore + service function
Computed/derived datauseMemo from store values
Global loading stateUI store

Example: Zustand Store Patterns (illustrative)

Illustrative — these are one team's concrete Zustand conventions shown as an example. Substitute your store library's equivalents (Redux Toolkit, Jotai, Pinia, signals, etc.). The decision matrix and selector/performance guidance above are the reusable, library-agnostic part.

Store Files (<your-stores-module>/)

StorePersistPurpose
workspaceStore.tsYes (scaffolding-workspaces)Projects/workspaces, active selection
taskStore.tsNoTask CRUD, SSE updates, agent statuses
authStore.tsYes (auth-storage)GitHub OAuth state, user profile

Type Pattern: Separate State & Actions

Every store defines type XxxState and type XxxActions, then exports the combined type:

type WorkspaceState = {
  workspaces: Workspace[];
  activeWorkspace: Workspace | null;
};
type WorkspaceActions = {
  addWorkspace: (pathOrWorkspace: string | Workspace) => void;
  removeWorkspace: (path: string) => Promise<void>;
  setActiveWorkspace: (path: string) => void;
  loadFromApi: () => Promise<void>;
};
export type WorkspaceStore = WorkspaceState & WorkspaceActions;

Persist Middleware with partialize

Persisted stores use partialize to exclude actions and transient state from storage:

export const useWorkspaceStore = create<WorkspaceStore>()(
  persist(
    (set, get) => ({ /* state + actions */ }),
    {
      name: 'scaffolding-workspaces',
      partialize: (state) => ({
        workspaces: state.workspaces,
        activeWorkspace: state.activeWorkspace,
      }),
    }
  )
);

Hook Wrappers with useShallow (<your-hooks-module>/)

Stores are consumed through hook wrappers that use useShallow to prevent re-renders:

import { useWorkspaceStore } from '../stores/workspaceStore';
import { useShallow } from 'zustand/shallow';

export function useWorkspace() {
  return useWorkspaceStore(
    useShallow((state) => ({
      workspaces: state.workspaces,
      activeWorkspace: state.activeWorkspace,
      addWorkspace: state.addWorkspace,
      // ... selected fields only
    }))
  );
}

API Sync Pattern (loadFromApi)

Stores hydrate from localStorage first, then enrich from API:

  1. persist middleware loads cached state from localStorage on mount
  2. loadFromApi() fetches from backend, merges fields (id, github_url, role) into existing entries
  3. Failures are silently caught - localStorage data still works offline

SSE Update Pattern (taskStore)

Non-persisted stores receive real-time updates from Server-Sent Events:

  • addTask(task) - deduplicates before prepending to list
  • updateTask(task) - replaces full task object in list and currentTask
  • updateTaskPartial(id, updates) - merges partial fields from SSE completion events
  • updateAgentStatus(taskId, status) - tracks per-agent progress within a task

Error Handling in Stores

Stores use extractErrorMessage(err, fallbackMsg) utility and store errors in state:

catch (err) {
  const message = extractErrorMessage(err, 'Failed to fetch tasks');
  set({ error: message, isLoading: false });
}

For expected errors (e.g., 409 conflict on cancel), check AxiosError status before setting error state.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.