# Code Remote Manager Engineering Guide

## Product Boundary

Code Remote Manager is a personal, Windows-only remote control for local Codex. A Node backend launches account-scoped Codex app-server processes. A React PWA controls them over the local machine or Tailscale.

Do not broaden this repository into a public multi-user service without a separate security design.

## Non-Negotiable Security Rules

- Never return or render credentials, `auth.json`, access/refresh tokens, API keys, `CODEX_HOME`, rollout paths, or raw authentication data.
- Never expose hidden chain-of-thought. Only Codex-provided reasoning summaries may enter public events.
- Capability projections may expose safe model, permission, plugin, and skill metadata, but never local skill paths. Resolve executable resources on the backend rather than accepting a browser-supplied path. The personal PC folder browser may expose folder names and hierarchy, but never absolute paths; navigation and selection use short-lived opaque backend-issued IDs.
- Browser-visible thread metadata must remain a safe projection. Local `cwd` values may become allowlisted workspace IDs/labels, never raw paths. Because this is a personal local-only app, Desktop history project grouping may also display the final folder name derived from `cwd` as a project label; never expose the full path or parent directories.
- Changed-file paths are allowed only inside the selected allowlisted workspace and only in the Changes feature.
- Redact app-server stderr and error data before persistence or SSE delivery.
- Keep `config.local.json` and runtime session data untracked. Personal machine paths belong only in local config.

## Ownership Invariants

- Each configured account owns its `CODEX_HOME`, authentication, and app-server process. Account selection controls which authenticated account executes the next request and consumes quota.
- Chats are unified conversations, not user-owned rows. Internal account/thread references may locate account-scoped Codex processes and history fragments, but must not create account-separated Chat UX.
- Opening a Chat or notification never changes the selected execution account. Only an explicit account-selector action changes and persists that selection; account creation, login, rename, and background refresh preserve it unless the selected account no longer exists.
- New Chat and continued Chat requests use the currently selected visible execution account and workspace.
- Continuing a Chat under a different execution account creates a new thread owned by that account. Carry forward only the visible user/assistant conversation; never copy hidden reasoning, approvals, credentials, raw runtime events, or private paths into the handoff prompt.
- Runtime cache may retain `threadRefs` across account-scoped Codex processes so linked physical threads project as one logical Chat. Do not expose those references as separate owner-oriented Chat UX.
- Unknown-workspace history is readable but cannot send until an allowlisted workspace is attached.

## Backend Architecture

- `apps/backend/src/accounts.js` and `account-routes.js`: safe account projection, managed account configuration, device-code login, account HTTP actions.
- `apps/backend/src/codex-runtime.js`: app-server JSON-RPC lifecycle, notification translation, approval responses, redaction.
- `apps/backend/src/codex-history.js`: account-scoped list/read, unified history aggregation, safe thread/history projection.
- `apps/backend/src/thread-routes.js`, `thread-groups.js`, and `thread-preferences.js`: archive/rename/pin actions, logical Chat projection, local pin state.
- `apps/backend/src/sessions.js`: runtime/session cache, logical account handoff, external-thread watching, SSE, approvals, message queue/steering, attachments, and workspace changes.
- `apps/backend/src/session-store.js`: persisted public session cache. Never serialize runtime clients, watchers, local attachment paths, or account secrets.
- `apps/backend/src/usage-status.js`: safe account rate-limit and active-thread context projections.
- `apps/backend/src/workspaces.js` and `workspace-routes.js`: public workspace projection and project discovery/registration below `projectsRoot`.
- `apps/backend/src/index.js`: HTTP routing only; keep business logic in focused modules.

Codex app-server is the durable thread source of truth. The local session store is only a runtime/SSE/approval cache. Backend restart must not execute work automatically.

## PWA Architecture

`apps/pwa/src/App.jsx` is composition-only. Feature folders own their components, state, API adapters, and CSS:

- `features/context`: account/workspace selectors and current runtime context.
- `features/accounts`: safe account identity, creation, device login, rename, and removal.
- `features/chats`: unified search/list, project grouping, pagination, Chat actions, transitions, and New Chat.
- `features/conversation`: SSE lifecycle, messages, activity cards, approvals, queue/steering, attachments, and composer capabilities.
- `features/changes`: changed files and diff display.
- `features/notifications`: background session/usage polling and short-lived local notifications.
- `features/status`: account quota/reset and active-thread context usage.

Features communicate through explicit props/callbacks and shared pure utilities. Do not move feature behavior back into `App.jsx`. Keep feature CSS scoped; global element defaults belong in `shared/styles/base.css` and shell layout in `app/app.css`.

## UI and Runtime Invariants

- Preserve the public SSE event model and approval workflow.
- An SSE connection may watch an externally running thread, but opening history or restarting the backend must never start, resume, steer, or repeat work by itself.
- Scope external-thread watchers to active viewers and stop them when no viewer remains or the session takes ownership of a live runtime.
- Keep queued messages FIFO. Remove the head only after dispatch succeeds; a failed dispatch keeps it and later messages queued. Restored queues never advance without an explicit operator action.
- A successful queued-message deletion must prevent automatic dispatch. Once dispatch owns the message, deletion must return a conflict instead of reporting success.
- Coalesce streaming assistant deltas and update activity items in place.
- Display reasoning summaries only.
- Move to the latest content when opening another Chat. During streaming, auto-follow only while the reader remains near the bottom.
- Keep the mobile shell at `100dvh`; history scrolls internally and the composer remains pinned to the bottom.
- At mobile widths, text inputs are 16px and controls are at least 48px high.
- If a multi-image selection partially fails, keep the successful uploads, report the failed items safely, and reset the picker so the same files can be selected again.
- Account/source failures must preserve successful unified Chat rows and provide retry.
- Missing usage fields display `Unavailable`; never estimate quota or context use.
- Button-triggered popup menus must close when the user taps or clicks outside the trigger/menu boundary; never require a second press on the trigger just to dismiss them.
- Button-triggered popup menus must also close immediately after an internal action is invoked, including opening a file picker, changing a mode, or selecting or clearing an item.
- Keep composer model, permission, and tools popovers compact and aligned with the ChatGPT mobile Codex structure. Preserve floating quick controls and avoid full-width shaded wrapper rows around floating controls.

## Configuration

- `config.example.json` is the committed template.
- `config.local.json` contains real paths and is ignored.
- `accounts[].historyOnly: true` creates a history source hidden from the account selector; omit it for the Desktop Codex home when this app should create chats that later appear in the desktop app.
- `workspaces[]` is the only filesystem allowlist.
- `projectsRoot` remains the default quick-project location for direct-child discovery and creation. The personal PC folder browser may navigate filesystem drives through opaque backend-issued IDs; only a folder explicitly confirmed by the operator is added to the workspace allowlist.
- Backend defaults: `127.0.0.1:43110`; PWA defaults: `127.0.0.1:43111`; Vite proxies `/api` to backend.

## Session Startup

- For continuation requests such as `ㄱ`, `continue`, or `next patch`, read
  `docs/PRE_RELEASE_CHECKLIST.md` after this file and follow only its `현재 패치` section.
- Do not read `README.md`, `ROADMAP.md`, the full pre-release checklist, dated audits, or old
  handoffs at startup. Open only the checklist sections and exact references required by the
  current task.
- A continuation request authorizes safe repository inspection and work inside the bounded task.
  It does not authorize deployment, server restart, Tailscale mutation, signing, store submission,
  or another external-state change that otherwise requires operator approval.
- Keep `docs/PRE_RELEASE_CHECKLIST.md` compact: user-visible status, current task, constraints,
  evidence required, short completion summary, and ordered queue only. Never append session logs.
- After a completed patch, without waiting for a reminder, update the checklist and any affected
  authoritative status section before committing. Advance `현재 패치` to the next bounded item,
  then stop without starting it. Never create another handoff or next-patch document.

## Development Workflow

1. Read the `현재 패치` section of `docs/PRE_RELEASE_CHECKLIST.md`, then only its routed
   documentation and relevant code/tests.
2. For behavior changes, agree on a design and write a focused plan before implementation.
3. Do not create or commit standalone design/spec documents unless the operator explicitly requests one. Keep routine design agreement in the conversation and implementation plan.
4. Use TDD: add a failing test, verify the expected failure, implement the smallest fix, then run the full affected suite.
5. Preserve unrelated user changes and ignored local configuration.
6. Verify browser behavior for UI changes, including 390x844 mobile layout.
7. Commit coherent changes only after fresh verification.

### Token-Efficient Development

- Before every patch, run `git status --short`. If unrelated changes overlap files in scope,
  preserve them and plan partial staging before editing. Never discover overlap only at commit time.
- For targeted test runs, use the narrowest test file and test-name filter available. Avoid
  diagnostics that print entire source or CSS files when a focused assertion can identify the
  mismatch.
- Required verification commands must still run in full. On success, report only the command,
  exit code, and pass/fail/skip counts; show detailed logs only when verification fails.

For an already-agreed, one-behavior change touching at most two production files, use this micro
patch workflow:

1. Confirm the intended behavior in one sentence.
2. Add or update one focused failing test.
3. Apply the smallest implementation change.
4. Run the focused test.
5. Run Required Verification once after all related edits are complete.
6. Commit only patch-owned hunks.

Do not create design documents or repeat full verification between closely related edits unless an
intermediate result must be committed separately.

## Existing-Commit PWA Refresh

When the operator asks only to commit finished work from other sessions and reflect it in the PWA:

1. Start with `git status --short`. If the worktree is clean, do not create an empty commit or
   re-audit recent commits.
2. Run `npm.cmd run safe:apply` once. A successful safe apply satisfies the three commands in
   `Required Verification` because it runs diff checking, the full test suite, and the PWA build
   against the staged release before promotion and health checks.
3. Do not run those verification commands separately before or after `safe:apply`.
4. Perform one focused browser smoke check after promotion. Use 390x844 only when the unapplied
   commits contain UI changes. Do not repeat the full feature matrix for a refresh-only request.
5. Recheck Tailscale exposure, logs, history, or the full checklist only when the relevant commits
   changed those areas, the smoke check fails, or the operator explicitly requests it.
6. If next-session preparation is requested, confirm only that `현재 패치` is current. Do not
   rewrite an already-current checklist or create a separate handoff document.

This fast path applies only to a clean worktree whose requested changes are already committed.
Dirty changes and active patch completion continue to use the normal development workflow.

## Required Verification

```powershell
npm.cmd test
npm.cmd --workspace apps/pwa exec vite build
git diff --check
```

For UI/runtime patches also verify:

- `http://127.0.0.1:43111`
- the configured Tailscale Serve URL when remote access is in scope
- account switching, unified Chats, desktop history, old-thread open/resume, SSE, approvals, Changes, usage status, and mobile composer placement
