Problem
The Factory sidebar allows orchestration runs to be dismissed from the list, but dismissals are stored in React state (useState) and lost on page refresh. The entire list reappears after any reload.
Proposed solution
Persist user settings to a server-side JSON file via new REST API endpoints. The Express server gains a SettingsStore service that reads/writes settings.json to a configurable directory (FACTORY_SETTINGS_PATH env var, defaulting to ~/.config/codeassembly/factory/). New GET/PATCH /api/settings endpoints expose settings to the client. The useDismissedRuns hook switches from in-memory useState to server-synced state with optimistic updates.
Key design decisions
- Server-persisted to disk (not browser localStorage) because the app runs locally
- Configurable path:
FACTORY_SETTINGS_PATH env var > ~/.config/codeassembly/factory/settings.json default (follows existing AI_PROJECTS_PATH pattern)
- Status-aware dismissals: Each dismissed run records the status at dismissal time. If a run's status changes (e.g., re-executed), it reappears automatically
- Extensible settings model:
UserSettings interface supports future UI preferences as new top-level keys
- Atomic writes: Write to temp file + rename to prevent corruption on crash
- Graceful degradation: Missing/corrupted settings file falls back to defaults; client falls back to session-only behavior if server is unreachable
Data model
{
"dismissedRuns": {
"my-project/TICKET-1/run-001": { "status": "completed" },
"my-project/TICKET-2/run-002": { "status": "failed" }
}
}
Acceptance criteria
Problem
The Factory sidebar allows orchestration runs to be dismissed from the list, but dismissals are stored in React state (
useState) and lost on page refresh. The entire list reappears after any reload.Proposed solution
Persist user settings to a server-side JSON file via new REST API endpoints. The Express server gains a
SettingsStoreservice that reads/writessettings.jsonto a configurable directory (FACTORY_SETTINGS_PATHenv var, defaulting to~/.config/codeassembly/factory/). NewGET/PATCH /api/settingsendpoints expose settings to the client. TheuseDismissedRunshook switches from in-memoryuseStateto server-synced state with optimistic updates.Key design decisions
FACTORY_SETTINGS_PATHenv var >~/.config/codeassembly/factory/settings.jsondefault (follows existingAI_PROJECTS_PATHpattern)UserSettingsinterface supports future UI preferences as new top-level keysData model
{ "dismissedRuns": { "my-project/TICKET-1/run-001": { "status": "completed" }, "my-project/TICKET-2/run-002": { "status": "failed" } } }Acceptance criteria
settings.jsonon diskFACTORY_SETTINGS_PATHenv varpnpm run checkpasses