rules/jotai-state.md
Use Jotai for client-only state, not as a second cache for IPC data.
When state belongs to an entity, key it by that entity id instead of using a singleton selected-entity value.
Good examples:
chatMessagesByIdAtom: Map<number, Message[]>;
isStreamingByIdAtom: Map<number, boolean>;
previewRunStateByAppIdAtom: Map<number, PreviewRunState>;
Avoid unkeyed global booleans for entity-specific async work. A value like
loading: boolean is only safe when exactly one operation can own it. Prefer
an app/chat/job keyed map and derive the currently visible value from the
selected id.
Expose derived atoms or domain hooks for "current selected" reads:
currentPreviewErrorAtom = atom((get) => {
const appId = get(selectedAppIdAtom);
return appId == null ? undefined : get(previewErrorByAppIdAtom).get(appId);
});
Components should usually read currentPreviewErrorAtom rather than repeat
selectedAppIdAtom plus raw map lookup logic.
Map and Set values before modifying them so Jotai sees a new
reference.When deleting an entity, prune any keyed Jotai state for that entity. Chat
state already uses helper atoms such as removeChatIdFromAllTrackingAtom; app
scoped runtime state should follow the same pattern.