Canonical guide for AI coding agents (Claude Code, GitHub Copilot, Codex, Cursor, Aider, etc.) working in this repository.
CLAUDE.mdand.github/copilot-instructions.mdpoint here — keep this file as the single source of truth.
- Restbro is a free, open-source desktop API testing tool — a privacy-respecting alternative to Postman/Insomnia.
- Public site: https://restbro.com. Releases: GitHub Releases.
- Stack: Electron 26 + TypeScript 5 + Webpack 5 + vanilla TS renderer (with isolated React/MUI islands for a few features such as JSON Compare). Monaco editor, CodeMirror 6, jsondiffpatch.
- Process model: classic Electron three-tier —
main(Node.js, trusted) ↔preload(contextBridge) ↔renderer(sandboxed browser). See docs/architecture.md. - Persistence: single JSON file at
app.getPath('userData')/database.jsonmanaged byStoreManager(debounced writes,flush()on quit). No SQLite, no localStorage.
npm install # one-time
npm run dev # watch main + dev server for renderer
npm start # launch packaged Electron against ./dist
npm run build # build main + preload + renderer (production)
npm run lint # eslint src --ext .ts
npm run lint -- --fix # autofix
npm run format # prettier --write src
npm test # vitest (watch)
npm test -- run # vitest single run (what CI uses)
npm run test:coverage # coverage report → ./coverage
npm run clean # rm -rf dist
npm run rebuild # clean + buildPackaging / release scripts (dist:*, release:*, ship:*) require signing/notarization secrets and must not be invoked by agents.
src/
├── main/ # Node.js process — trusted
│ ├── index.ts # boot: store → AI → IPC → window; flush() on quit
│ └── modules/ # one concern per file (≤ 300 lines each)
│ ├── ipc-manager.ts # registers all whitelisted IPC handlers
│ ├── store-manager.ts # database.json, debounced writes
│ ├── window-manager.ts # BrowserWindow + security flags
│ ├── request-builder.ts # assemble req, resolve {{vars}}, headers
│ ├── request-manager.ts # request lifecycle + cancellation
│ ├── request-error-formatter.ts
│ ├── variables.ts # request > env > folder > global precedence
│ ├── oauth.ts # auth code + PKCE, client creds, device code
│ ├── ai-engine.ts # local LLM streaming
│ ├── ai-system-prompt.ts
│ ├── curl-executor.ts
│ ├── loadtest-engine.ts # token-bucket RPM + percentiles
│ ├── loadtest-export.ts # CSV/PDF
│ ├── jks-parser.ts # SSL cert parsing
│ ├── notepad-ipc.ts
│ ├── update-manager.ts # electron-updater
│ ├── mock-server/ # mock server subsystem
│ └── importers/ # Postman / Insomnia / API Courier
├── preload/index.ts # contextBridge → window.restbro.* (no logic)
├── shared/ # imported by both main and renderer
│ ├── types.ts # domain types (Collection, ApiRequest, ApiResponse, …)
│ ├── ipc.ts # IPC_CHANNELS — single source of truth
│ ├── system-variables.ts # {{timestamp}}, etc.
│ ├── code-generators.ts
│ └── request-builder-shared.ts
├── renderer/ # sandboxed UI (vanilla TS managers + DOM events)
│ ├── index.ts, event-listeners.ts
│ ├── components/<feature>/ # one folder per feature
│ ├── tabs/, utils/, types/, styles/
└── features/json-compare/ # standalone React + Web Worker island
Tests live in __tests__/ folders next to the code (src/main/modules/__tests__, src/shared/__tests__, src/renderer/components/__tests__, …). Electron is mocked via src/__mocks__/electron.ts.
- Electron security flags stay on:
nodeIntegration:false,contextIsolation:true,sandbox:true(seesrc/main/modules/window-manager.ts). Never weaken them. - Renderer is sandboxed. No
require, noipcRenderer, nofs, nofetch-to-disk. Use onlywindow.restbro.*exposed by the preload bridge. - All persistence goes through
StoreManagerin main →database.json. Never uselocalStorage,sessionStorage, or write files from the renderer. - IPC is whitelisted and explicit. Add channels to
src/shared/ipc.ts; no dynamic channel names, no generic "invoke anything" pass-through. - All file/network/native operations live in main and are exposed via IPC.
- Never log or render secrets — Authorization headers, OAuth tokens, client secrets, JKS passwords, API keys. Redact before logging and before showing in UI/error messages.
- No telemetry, no analytics, no runtime CDN-loaded code. Restbro is privacy-first.
- Main-process modules: ≤ 300 lines.
- Renderer components/managers: 150–300 lines (soft target).
- When a file grows, split into helpers/sub-modules — do not create god files.
- Prefer pure functions for anything testable (variable resolution, formatters, parsers).
- Update / add types in src/shared/types.ts so main and renderer agree.
- Add IPC channel constants in src/shared/ipc.ts (
IPC_CHANNELS.*). - Implement the handler in src/main/modules/ipc-manager.ts (delegating to a focused module).
- Expose a typed API in src/preload/index.ts under
window.restbro.<group>.*. Update preload typings if shared shapes change. - Consume from the renderer via
window.restbro.*— neveripcRendererdirectly. - Persist via store IPC (
store:get/store:set) — the renderer never writes files. - Add unit tests for any pure logic (variable resolution, formatting, parsing) under the nearest
__tests__/.
database.jsonwith debounced writes; alwaysflush()on shutdown.- Migrations are additive: merge loaded data into
defaultState; never break older shapes. - Save response metadata (status, time, size) in history; avoid persisting huge bodies.
- Don't delete or overwrite collections/requests without explicit user confirmation.
- Requests run in main via Node
http/https(not rendererfetch). - Variable precedence: request > environment > folder chain > global (
modules/variables.ts). - Never override user-supplied headers. Auto-set
Content-Type/Content-Lengthonly when missing. - Cancellation must work by request id.
- Errors return structured objects shaped for the UI — see
RequestErrorFormatter.
- Supported grants: Authorization Code (with PKCE), Client Credentials, Device Code.
- Validate
state. Always cleanly tear down authBrowserWindows. - Refresh tokens only when expired; persist updated config back to the request/collection.
- Local LLM expected at
http://localhost:9999(Qwen 2.5 7B reference). Never call third-party AI services from the app. - Streaming via IPC: main emits chunks, renderer subscribes.
- Enforce
AI_MAX_CONTEXT_CHARS; fail gracefully with a useful UI error.
- Multiple instances, route matching: exact / prefix / wildcard (
*,**) / regex. - Lifecycle (
start/stop) is owned by main; renderer only commands.
- Token-bucket RPM scheduling. Report p50/p95/p99 and status distribution.
- Cancellation must terminate in-flight workers cleanly.
- Vanilla TS "manager" pattern with custom DOM events for cross-component updates. Don't introduce a global state framework.
- React / MUI is allowed only as isolated islands wrapped by a vanilla manager (e.g.,
features/json-compare). - Preserve existing keyboard shortcuts (Send/Cancel, tab nav, Notepad shortcuts).
- Themes are a finite set (Blue/Green/Purple/Orange/Red/Magenta) — extend, don't replace.
- TypeScript-first. Avoid
anyexcept at strict boundaries (parsing untrusted input, IPC edges). - Three separate
tsconfig.jsons —src/main,src/preload,src/renderer. Don't import across processes; share viasrc/shared/. - Lint with ESLint (
@typescript-eslint) + Prettier. Runnpm run lint -- --fixbefore committing. - Prefer small pure helpers over inheritance hierarchies.
- Framework: vitest with
jsdomenvironment. - Add tests for pure logic whenever feasible (variable resolution, importers, formatters, code generators, mock-server route matcher).
- Electron is mocked at
src/__mocks__/electron.ts. Don't import Electron directly in tests. - CI (
.github/workflows/ci.yml) runsnpm ci → lint → build → test -- runon macOS / Node 20.
- Avoid heavy dependencies unless they replace significant complexity and are clearly justified.
- No new analytics, telemetry, error-reporting SaaS, or runtime CDN scripts.
- New native modules require explicit discussion (they break universal Mac builds).
See CONTRIBUTING.md. Quick reminders for agents:
- Branch prefixes:
feature/,fix/,docs/,refactor/,ci/. - One feature/fix per PR; fill out the PR template (What / Why / Impact).
- PRs are squash-merged. Keep commit messages descriptive.
- Do not push to
main, force-push, or run release/publish scripts. - Do not commit anything under
dist/,release/,coverage/, ornode_modules/.
Before declaring any task complete, run all three locally and fix every failure:
npm run lint # 0 errors (warnings OK)
npm run build # must compile cleanly
npm test -- run # all unit tests passIf any of these fail, the task is not done.
- Disable Electron sandbox / contextIsolation / nodeIntegration.
- Use
localStorage/sessionStoragefor persistence. - Call
ipcRendererdirectly from the renderer. - Add a generic "invoke any channel" IPC handler.
- Log Authorization headers, tokens, passwords, or full secret payloads.
- Add telemetry, analytics, crash-reporting SaaS, or remote code loading.
- Run
npm run release*,npm run ship:*,npm run dist*, ornpm run publish:*. - Commit generated artifacts (
dist/,release/,coverage/). - Edit code-signing entitlements or
electron-builderpublish config without being asked. - Rewrite Postman/Insomnia importer formats — extend, don't replace; users depend on backward compatibility.