All docs must canonical, no past commentary, only live state.
Purpose: keep lightweight, durable project memory so agents avoid repeating mistakes and follow user/project preferences over time.
Store memory in the project root under ./memory/:
memory/decisions.md— active canonical rules only (high-signal, current behavior)memory/mistakes.md— mistakes, fixes, and prevention rulesmemory/todo.md— open loops and follow-up tasksmemory/context.md— optional short-lived working context (can be compacted)memory/archive/— detailed historical decision logs moved out of canonical memory during compaction
Agents should write memory entries when ANY of the following happens:
- User states a stable preference or rule ("do it this way").
- Agent makes a non-trivial mistake and corrects it.
- A decision is made that affects future implementation.
- A follow-up task is identified but not completed immediately.
Write target:
- Put durable behavior/rules in
memory/decisions.md. - Put implementation-step history and low-signal details in
memory/archive/*. - Keep
memory/mistakes.mdandmemory/todo.mdappend-only.
Do NOT write:
- trivial chatter
- transient debug noise
- secrets/tokens/passwords
- private data not required for project execution
Before starting a task, agents must read:
memory/decisions.md- recent entries in
memory/mistakes.md - open items in
memory/todo.md memory/archive/*only when current files do not provide enough context
Then apply those constraints during planning and implementation.
Use this compact format:
## YYYY-MM-DD HH:mm
Context: <task or feature>
Type: decision | preference
Rule: <one-line future behavior>
Why: <short reason this rule exists>For entries in memory/mistakes.md, include:
Root cause:Fix applied:Prevention rule:
- Keep
memory/decisions.mdcompact and high-signal (target: <= 150 lines). - Compaction should move detailed historical entries to
memory/archive/and keepmemory/decisions.mdas canonical rules. - During compaction, preserve meaning and keep at least the latest 30 days of detail in
memory/archive/. - When compacting
memory/decisions.md, append one compaction entry noting where full history was archived.
CodexMonitor is a Tauri app that orchestrates Codex agents across local workspaces.
- Frontend: React + Vite
- Backend (app): Tauri Rust process
- Backend (daemon):
src-tauri/src/bin/codex_monitor_daemon.rs - Shared backend domain logic:
src-tauri/src/shared/*
The backend separates shared domain logic from environment wiring.
- Shared domain/core logic:
src-tauri/src/shared/* - App wiring and platform concerns: feature folders + adapters
- Daemon wiring and transport concerns:
src-tauri/src/bin/codex_monitor_daemon.rs
src-tauri/src/codex/mod.rssrc-tauri/src/codex/args.rssrc-tauri/src/codex/home.rssrc-tauri/src/codex/config.rs
src-tauri/src/files/mod.rssrc-tauri/src/files/io.rssrc-tauri/src/files/ops.rssrc-tauri/src/files/policy.rs
src-tauri/src/dictation/mod.rssrc-tauri/src/dictation/real.rssrc-tauri/src/dictation/stub.rs
src-tauri/src/workspaces/*
src-tauri/src/shared/*
Root-level single-file features remain at src-tauri/src/*.rs (for example: menu.rs, prompts.rs, terminal.rs, remote_backend.rs).
Shared logic that must work in both the app and the daemon lives under src-tauri/src/shared/.
src-tauri/src/shared/codex_core.rs- Threads, approvals, login/cancel, account, skills, config model
src-tauri/src/shared/workspaces_core.rs- Workspace/worktree operations, persistence, sorting, git command helpers
src-tauri/src/shared/settings_core.rs- App settings load/update, Codex config path
src-tauri/src/shared/files_core.rs- File read/write logic
src-tauri/src/shared/git_core.rs- Git command helpers and remote/branch logic
src-tauri/src/shared/worktree_core.rs- Worktree naming/path helpers and clone destination helpers
src-tauri/src/shared/account.rs- Account helper utilities and tests
Use this mental model when changing backend code:
- Put shared logic in a shared core module.
- Keep app and daemon code as thin adapters.
- Pass environment-specific behavior via closures or small adapter helpers.
The app and daemon do not re-implement domain logic.
The daemon defines wrapper modules named codex and files inside src-tauri/src/bin/codex_monitor_daemon.rs.
These wrappers re-export the daemon’s local modules:
- Codex:
codex_args,codex_home,codex_config - Files:
file_io,file_ops,file_policy
Shared cores use crate::codex::* and crate::files::* paths. The daemon wrappers satisfy those paths without importing app-only modules.
- Composition root:
src/App.tsx - Feature slices:
src/features/ - Tauri IPC wrapper:
src/services/tauri.ts - Tauri event hub:
src/services/events.ts - Shared UI types:
src/types.ts - Thread item normalization:
src/utils/threadItems.ts - Styles:
src/styles/
- Tauri command registry:
src-tauri/src/lib.rs - Codex adapters:
src-tauri/src/codex/* - Files adapters:
src-tauri/src/files/* - Dictation adapters:
src-tauri/src/dictation/* - Workspaces adapters:
src-tauri/src/workspaces/* - Shared core layer:
src-tauri/src/shared/* - Git feature:
src-tauri/src/git/mod.rs
- Daemon entrypoint:
src-tauri/src/bin/codex_monitor_daemon.rs - Daemon imports shared cores via
#[path = "../shared/mod.rs"] mod shared;
- Composition root: keep orchestration in
src/App.tsx. - Components: presentational only. Props in, UI out. No Tauri IPC.
- Hooks: own state, side effects, and event wiring.
- Utils: pure helpers only in
src/utils/. - Services: all Tauri IPC goes through
src/services/. - Types: shared UI types live in
src/types.ts. - Styles: one CSS file per UI area under
src/styles/.
Keep src/App.tsx lean:
- Keep it to wiring: hook composition, layout, and assembly.
- Move stateful logic/effects into hooks under
src/features/app/hooks/. - Keep Tauri IPC, menu listeners, and subscriptions out of
src/App.tsx.
Use the design-system layer for shared UI shells and tokenized styling.
- Primitive component locations:
src/features/design-system/components/modal/ModalShell.tsxsrc/features/design-system/components/toast/ToastPrimitives.tsxsrc/features/design-system/components/panel/PanelPrimitives.tsxsrc/features/design-system/components/popover/PopoverPrimitives.tsx- Toast sub-primitives:
ToastHeader,ToastActions,ToastError(inToastPrimitives.tsx) - Panel sub-primitives:
PanelMeta,PanelSearchField(inPanelPrimitives.tsx) - Popover sub-primitives:
PopoverMenuItem(inPopoverPrimitives.tsx)
- Diff theming and style bridge:
src/features/design-system/diff/diffViewerTheme.ts
- DS token/style locations:
src/styles/ds-tokens.csssrc/styles/ds-modal.csssrc/styles/ds-toast.csssrc/styles/ds-panel.csssrc/styles/ds-popover.csssrc/styles/ds-diff.css
Naming conventions:
- DS CSS classes use
.ds-*prefixes. - DS CSS variables use
--ds-*prefixes. - DS React primitives use
PascalCasecomponent names (ModalShell,ToastCard,ToastHeader,ToastActions,ToastError,PanelFrame,PanelHeader,PanelMeta,PanelSearchField,PopoverSurface,PopoverMenuItem). - Feature CSS should keep feature-prefixed classes (
.worktree-*,.update-*) for content/layout specifics.
Do:
- Use DS primitives first for shared shells (modal wrappers, toast cards/viewports, panel shells/headers, popover/dropdown surfaces).
- Pull shared visual tokens from
--ds-*variables. - Keep feature styles focused on feature-specific layout/content, not duplicated shell chrome.
- Centralize shared animation/chrome in DS stylesheets when used by multiple feature families.
Don't:
- Recreate fixed modal backdrops/cards in feature CSS when
ModalShellis used. - Duplicate toast card chrome (background/border/shadow/padding/enter animation) per toast family.
- Duplicate panel shell layout/header alignment in feature styles when
PanelFrame/PanelHeaderalready provide it. - Recreate popover/dropdown shell chrome in feature CSS when
PopoverSurface/PopoverMenuItemalready provide it. - Add new non-DS color constants for shared shells; add/extend DS tokens instead.
Migration guidance for new/updated components:
- Start by wrapping UI in the closest DS primitive.
- Migrate shared shell styles into DS CSS (
ds-*.css) and delete redundant feature-level shell selectors. - Keep only feature-local classes for spacing/content/interaction details.
- For legacy selectors that are still referenced, keep minimal compatibility aliases temporarily.
- Remove compatibility aliases once callsites reach zero, then rerun lint/typecheck/tests.
Anti-duplication guidance:
- Before adding shell styles, search for existing DS token/primitive coverage.
- If two or more feature files need the same shell rule, move it to DS CSS immediately.
- Prefer extending DS primitives/tokens over introducing another feature-specific wrapper class.
- During refactors, remove unused legacy selectors once callsites are migrated.
Enforcement workflow:
- Lint guardrails for DS-targeted files live in
.eslintrc.cjs. - Popover guardrails are enforced for migrated popover files (
MainHeader,Sidebar,SidebarHeader,SidebarCornerActions,OpenAppMenu,LaunchScript*,ComposerInput,FilePreviewPopover,WorkspaceHome) to requirePopoverSurface/PopoverMenuItem. - Codemod scripts live in
scripts/codemods/:modal-shell-codemod.mjspanel-shell-codemod.mjstoast-shell-codemod.mjs
- Run
npm run codemod:ds:drybefore UI shell migration PRs. - Keep
npm run lint:ds/npm run lintgreen for modal/toast/panel/popover/diff files.
- Shared logic goes in
src-tauri/src/shared/first. - App and daemon are thin adapters around shared cores.
- Avoid duplicating git/worktree/codex/settings/files logic in adapters.
- Prefer explicit, readable adapter helpers over clever abstractions.
- Do not folderize single-file features unless you are splitting them.
The daemon runs backend logic outside the Tauri app.
Update the daemon when one of these is true:
- A Tauri command is used in remote mode.
- The daemon exposes the same behavior over its JSON-RPC transport.
- Shared core behavior changes and the daemon wiring must pass new inputs.
- Shared behavior or domain logic:
- Add or update code in
src-tauri/src/shared/*.rs.
- Add or update code in
- App-only behavior:
- Update the app adapters or Tauri commands.
- Daemon-only transport/wiring behavior:
- Update
src-tauri/src/bin/codex_monitor_daemon.rs.
- Update
- Implement the core logic in a shared module.
- Wire it in the app.
- Add a Tauri command in
src-tauri/src/lib.rs. - Call the shared core from the appropriate adapter.
- Mirror it in
src/services/tauri.ts.
- Add a Tauri command in
- Wire it in the daemon.
- Add a daemon method that calls the same shared core.
- Add the JSON-RPC handler branch in
codex_monitor_daemon.rs.
- Shared git unit wrapper:
workspaces_core::run_git_command_unit(...)
- App spawn adapter:
spawn_with_app(...)insrc-tauri/src/workspaces/commands.rs
- Daemon spawn adapter:
spawn_with_client(...)insrc-tauri/src/bin/codex_monitor_daemon.rs
- Daemon wrapper modules:
mod codex { ... }andmod files { ... }incodex_monitor_daemon.rs
If you find yourself copying logic between app and daemon, extract it into src-tauri/src/shared/.
- Backend spawns
codex app-serverusing thecodexbinary. - Initialize with
initializeand theninitialized. - Do not send requests before initialization.
- JSON-RPC notifications stream over stdout.
- Threads are listed via
thread/listand resumed viathread/resume. - Archiving uses
thread/archive.
The app uses a shared event hub so each native event has one listen and many subscribers.
- Backend emits:
src-tauri/src/lib.rsemits events to the main window. - Frontend hub:
src/services/events.tsdefinescreateEventHuband module-level hubs. - React subscription: use
useTauriEvent(subscribeX, handler).
- Emit the event in
src-tauri/src/lib.rs. - Add a hub and
subscribeXhelper insrc/services/events.ts. - Subscribe via
useTauriEventin a hook or component. - Update
src/services/events.test.tsif you add new subscription helpers.
- Workspaces live in
workspaces.jsonunder the app data directory. - Settings live in
settings.jsonunder the app data directory. - On launch, the app connects each workspace once and loads its thread list.
- UI layout or styling:
src/features/*/components/*andsrc/styles/*
- App-server events:
src/features/app/hooks/useAppServerEvents.ts
- Tauri IPC shape:
src/services/tauri.tsandsrc-tauri/src/lib.rs
- Shared backend behavior:
src-tauri/src/shared/*
- Workspaces/worktrees:
- Shared core:
src-tauri/src/shared/workspaces_core.rs - App adapters:
src-tauri/src/workspaces/* - Daemon wiring:
src-tauri/src/bin/codex_monitor_daemon.rs
- Shared core:
- Settings and Codex config:
- Shared core:
src-tauri/src/shared/settings_core.rs - App adapters:
src-tauri/src/codex/config.rs,src-tauri/src/settings/mod.rs - Daemon wiring:
src-tauri/src/bin/codex_monitor_daemon.rs
- Shared core:
- Files:
- Shared core:
src-tauri/src/shared/files_core.rs - App adapters:
src-tauri/src/files/*
- Shared core:
- Codex threads/approvals/login:
- Shared core:
src-tauri/src/shared/codex_core.rs - App adapters:
src-tauri/src/codex/* - Daemon wiring:
src-tauri/src/bin/codex_monitor_daemon.rs
- Shared core:
useThreads is a composition layer that wires focused hooks and shared utilities.
- Orchestration:
src/features/threads/hooks/useThreads.ts - Actions:
src/features/threads/hooks/useThreadActions.ts - Approvals:
src/features/threads/hooks/useThreadApprovals.ts - Event handlers:
src/features/threads/hooks/useThreadEventHandlers.ts - Messaging:
src/features/threads/hooks/useThreadMessaging.ts - Storage:
src/features/threads/hooks/useThreadStorage.ts - Status helpers:
src/features/threads/hooks/useThreadStatus.ts - Selectors:
src/features/threads/hooks/useThreadSelectors.ts - Rate limits:
src/features/threads/hooks/useThreadRateLimits.ts - Collab links:
src/features/threads/hooks/useThreadLinking.ts
npm install
npm run tauri devnpm run tauri buildnpm run typechecknpm run testnpm run test:watchAt the end of a task:
- Run
npm run lint. - Run
npm run testwhen you touched threads, settings, updater, shared utils, or backend cores. - Run
npm run typecheck. - If you changed Rust backend code, run
cargo checkinsrc-tauri.
- The window uses
titleBarStyle: "Overlay"and macOS private APIs for transparency. - Avoid breaking JSON-RPC format; the app-server is strict.
- App settings and Codex feature toggles are best-effort synced to
CODEX_HOME/config.toml. - UI preferences live in
localStorage. - GitHub issues require
ghto be installed and authenticated. - Custom prompts are loaded from
$CODEX_HOME/prompts(or~/.codex/prompts).
- Use
pushErrorToastfromsrc/services/toasts.tsfor user-facing errors. - Toast wiring:
- Hook:
src/features/notifications/hooks/useErrorToasts.ts - UI:
src/features/notifications/components/ErrorToasts.tsx - Styles:
src/styles/error-toasts.css
- Hook: