Pesk is an Electron and TypeScript application for working with Codex through a dedicated chat workspace, remote-machine investigation, configurable Windows workflows, and remote Codex session access.
![]() |
![]() |
![]() |
![]() |
- Animated desktop companion with customizable visual themes
- Integrated Codex workspace for interactive development assistance
- Remote-machine investigation through one or more embedded terminals, with human approval
- Extensible configuration and external content support after installation
- Productivity automation through configurable Windows application presets
- Native Windows integration through the system tray, keyboard shortcuts, and login startup
The architecture separates renderer windows from main-process services: a secure IPC bridge carries UI actions and state, while focused services own Codex communication, remote-machine terminal access, browser connectivity, and persisted user data.
flowchart LR
Desktop((Desktop))
Browser((Browser))
subgraph Windows[Desktop windows]
Pet[[Pet]]
Chat[[Codex chat]]
Menu[[Pesk menu]]
end
subgraph Electron[Electron main process]
direction TB
Bridge{{Secure IPC bridge}}
Services{{Application services}}
Codex([Codex client])
Web([Chat web server])
Bridge <--> Services
Services <--> Codex
Services <--> Web
end
Storage[(User data)]
AppServer[/Codex app-server/]
Push[/Browser push service/]
Desktop --> Pet
Desktop --> Chat
Desktop --> Menu
Pet <-->|IPC| Bridge
Chat <-->|IPC| Bridge
Menu <-->|IPC| Bridge
Codex <-->|JSON-RPC over WebSocket| AppServer
Browser <-->|Chat WebSocket| Web
Web -->|Push notification| Push
Push -->|Browser delivery| Browser
Services --> Storage
classDef user fill:#ede9fe,stroke:#7c3aed,color:#2e1065
classDef window fill:#dbeafe,stroke:#2563eb,color:#172554
classDef process fill:#ffedd5,stroke:#ea580c,color:#431407
classDef service fill:#dcfce7,stroke:#16a34a,color:#14532d
classDef external fill:#f3f4f6,stroke:#6b7280,color:#111827
classDef storage fill:#fef3c7,stroke:#d97706,color:#451a03
class Desktop,Browser user
class Pet,Chat,Menu window
class Bridge,Services process
class Codex,Web service
class AppServer,Push external
class Storage storage
sequenceDiagram
actor User
participant Pesk as Pesk main process
participant Codex
participant HostA as Remote host A
participant HostB as Remote host B
User->>Pesk: Diagnose why one production host missed a release while peer hosts completed deployment successfully
Pesk->>Codex: Forward investigation request
loop Repeat until the issue is understood
Codex->>Pesk: Request next diagnostic step
Pesk->>User: Ask for human command approval
alt Approved
User->>Pesk: Approve command
Pesk->>HostA: Execute approved command
Pesk->>HostB: Execute approved command
HostA-->>Pesk: Return state and command output
HostB-->>Pesk: Return state and command output
Pesk->>Codex: Provide terminal output
else Rejected
User-->>Pesk: Reject command
Pesk-->>Codex: Tool request rejected
end
end
Codex->>Pesk: Explain result
Pesk-->>User: Display result
| Diagram component | Ownership and responsibility |
|---|---|
| Desktop windows | Electron-owned pet, Codex chat, and Pesk menu surfaces for desktop interaction. |
| Secure IPC bridge | The preload boundary that safely carries window requests and main-process state updates. |
| Application services | Main-process coordination for configuration, settings, animations, presets, window lifecycle, and cross-component behavior. |
| Codex client | Main-process connection and state owner for JSON-RPC requests, threads, turns, streaming, approvals, and user-input requests. |
| Remote Terminal | Per-thread bridge to one or more remote machines, with session-aware terminal access and approval-gated Codex tools. |
| Chat web server | Main-process LAN server for pairing, authenticated browser chat, state broadcasts, and push notification requests. |
| User data | Local persisted configuration, settings, device credentials, VAPID keys, subscriptions, and external content. |
| Codex app-server | External service that receives and streams Codex JSON-RPC traffic. |
| Browser push service | External browser-vendor delivery service used for Web Push notifications. |
- Windows for the packaged application and monitor-placement presets
- Node.js and npm for development and packaging
npm install
npm startUseful commands:
npm run build # Compile main and renderer TypeScript
npm test # Build and run Jest tests
npm run dist # Build the Windows NSIS installerCompiled runtime files are written to build/. The installer is written to dist/Pesk-Setup-<version>.exe.
To open detached DevTools for the pet, chat, and menu windows:
DESKTOP_PET_DEVTOOLS=1 npm startPesk uses JSON configuration for application behavior and keeps user preferences in a separate settings file.
- During development, the repository root
config.jsonprovides the default configuration. - Installed builds use
%APPDATA%\pesk\config.jsonas the user override. The file is created or edited manually; it is intentionally not included in the installer. - User preferences such as the selected animation, visibility, pause state, and lock state are stored in
%APPDATA%\pesk\settings.json.
When both configuration files exist, values in the user configuration override the bundled or development defaults. Restart Pesk after changing configuration.
Example application configuration:
{
"fps": 24,
"petSize": 180,
"animationsDir": "animations",
"codexAppServerProfiles": [{ "id": "default", "name": "Default", "url": "ws://127.0.0.1:4500" }],
"activeCodexAppServerProfileId": "default",
"features": {
"remoteTerminal": {
"enabled": true,
"url": "http://127.0.0.1:5000/provider/ssh"
}
},
"codexStatusSound": "audio.mp3",
"webAccessEnabled": false,
"webPort": 4587,
"webTlsKey": "",
"webTlsCert": ""
}Configuration fields:
fpsandpetSizecontrol default animation playback and rendering.animationsDirselects the external animation directory. Relative paths are resolved beside the active configuration file.codexAppServerProfilesdefines named app-server profiles.activeCodexAppServerProfileIdselects the startup profile. Both can also be managed from the Pesk Menu.features.remoteTerminal.enabledenables remote-machine investigation through an embedded terminal and approval-gated Codex terminal tools.features.remoteTerminal.urlpoints to an rterm provider page such ashttp://127.0.0.1:5000/provider/ssh. rterm owns provider, target, user, terminal-session creation, credentials, and provider operations.codexStatusSoundspecifies an optional sound file. Relative paths are resolved beside the active configuration file.webAccessEnabledenables the browser-based chat endpoint. It is disabled by default.webPortspecifies the HTTP/WebSocket listening port. The default is4587.webTlsKeyandwebTlsCertoptionally enable HTTPS/WSS for the web chat. Relative paths resolve beside the active configuration file; configure both together.presetsdefines named Windows commands or URLs available from the Pesk menu. Each action may specify acommand,args, and an optional one-basedmonitor.animationsprovides per-animation overrides such asfps. Animation folders contain numbered PNG frames, for example:
<active-config-directory>\animations\dance\001.png
Remote-terminal access from web chat is brokered by Pesk. Web clients do not connect to the rterm service directly; authenticated paired clients receive only a short-lived, device-scoped capability.
When remote-terminal support is enabled, Codex can use these approval-gated tools:
remote_terminal.sessions— list available terminal sessions.remote_terminal.read— read recent terminal output.remote_terminal.execute— run an approved command.remote_terminal.upload— upload a workspace file after approval.remote_terminal.download— download a remote file after approval.
Start an authenticated app-server separately:
codex app-server --listen ws://127.0.0.1:4500Configure one or more profiles in config.json or from the Pesk Menu:
{
"codexAppServerProfiles": [
{ "id": "local", "name": "Local", "url": "ws://127.0.0.1:4500" },
{ "id": "remote", "name": "Remote", "url": "wss://codex.example.test/ws" }
],
"activeCodexAppServerProfileId": "local"
}URLs must use ws:// or wss://. The active profile can be switched from the Pesk Menu without
restarting; Pesk reloads threads and projects from the selected server.
To confirm that a local server is listening before opening Pesk, request its readiness endpoint:
curl http://127.0.0.1:4500/readyzKeep the app-server on loopback (127.0.0.1) unless you have separately secured
the transport and understand the exposure. The WebSocket listener is documented
by Codex as experimental.
All shortcut definitions are centralized in src/renderer/shared/shortcuts.ts.
Global shortcuts are fixed application behavior; they are not configuration
options.
| Shortcut | Action |
|---|---|
Ctrl+Down |
Open the Pesk menu |
Ctrl+Up |
Focus the pet, chat input, or pending question |
Ctrl+Shift+L |
Lock or unlock chat auto-hide on blur |
Escape |
Hide chat and unfocus the pet |
| Shortcut | Action |
|---|---|
Ctrl+Left / Ctrl+Right |
Switch between Codex sessions |
Ctrl+C / Cmd+C |
Copy the selected message |
Alt+Home / Alt+End |
Scroll to the top or bottom |
Alt+Up / Alt+Down |
Select the previous or next message |
Alt+Shift+Up / Alt+Shift+Down |
Select the previous or next user message |
Shift+Up / Shift+Down |
Scroll history by one step |
Alt+Right |
Copy the selected message into the composer |
Shift+Enter |
Expand or collapse the selected message |
| Shortcut | Context | Action |
|---|---|---|
Enter |
Desktop composer | Submit the prompt |
Enter |
Web composer | Insert a newline |
Ctrl+Enter |
Composer | Insert a newline |
Alt+Enter |
Composer | Steer the active Codex turn, or submit when idle |
Ctrl+C |
Working composer | Interrupt the active Codex turn |
Up / Down |
Composer | Recall the previous or next submitted prompt at a line boundary |
| Shortcut | Context | Action |
|---|---|---|
Up / Down |
Suggestions | Select the previous or next suggestion |
Enter |
Suggestions | Accept the selected suggestion |
Escape |
Suggestions/review | Dismiss suggestions or cancel the review form |
Up / Down |
Question options | Select the previous or next radio option |
Tab |
Question options | Move from an option to its note field |
Tab |
Question note | Return to the selected option |
Enter |
Question/review fields | Submit the current form |
| Shortcut | Context | Action |
|---|---|---|
Tab / Shift+Tab |
Pesk menu | Move to the next or previous section |
Up / Down |
Pesk menu | Move between actions |
Left / Right |
Pesk menu device row | Move between row actions |
Escape |
Pesk menu | Close the menu |
Enter |
Pairing field | Generate a pairing QR code |
Enter / Space |
Web connection status | Reload and reconnect |
In the menu’s Presets section, typing unmodified printable characters filters
presets and Backspace removes the last filter character.
Presets define named actions available from the Pesk menu. An action runs a Windows command with optional arguments. URL arguments can be used with browser commands, and monitor specifies a one-based monitor number.
{
"presets": [
{
"name": "Open documentation",
"actions": [
{
"command": "msedge",
"args": ["--new-window", "https://example.com/docs"]
}
]
},
{
"name": "Open dashboard on monitor 2",
"actions": [
{
"command": "brave",
"args": ["--new-window", "http://localhost:3000"],
"monitor": 2
}
]
}
]
}Packaged builds enable Windows login startup after the installed application is launched once.
Expose only the Codex chat to a browser on the same trusted LAN.
- Set
webAccessEnabledtotrue. - Restart Pesk.
- Open the Pesk Menu and choose
Pair a device. - Enter a unique device name and press Enter.
- Scan the displayed QR code with the other device’s camera.
The QR code is single-use and expires after five minutes. Each paired device receives its own credential; credentials are not stored in config.json.
The endpoint uses HTTP/WebSocket by default and has no internet relay. HTTPS/WSS is required for PWA installation and browser notifications on LAN devices. Configure both webTlsKey and webTlsCert to enable it.
Do not expose the endpoint through router port forwarding. Use a trusted LAN or a VPN for remote access.
After pairing:
- Install the chat as a PWA from the browser’s install command, if desired.
- If the browser asks for permission, choose Allow.
- If the prompt does not appear, click
Enable notificationsin the chat. - If notifications are blocked, allow them in the browser’s site settings and refresh the chat.
Web Push ready means that the browser subscription was successfully saved. The indicator is hidden when setup is valid. It does not guarantee that the phone’s operating-system notification settings will display the notification.
Pesk stores:
%APPDATA%\pesk\web-devices.json— paired devices and hashed credentials.%APPDATA%\pesk\web-push-vapid.json— server VAPID keys.%APPDATA%\pesk\web-push-subscriptions.json— browser subscriptions, one active subscription per paired device.
In the Pairing menu, Web Push setup status is separate from delivery control. Enable push/Disable push controls whether Pesk sends updates; it does not grant browser permission or remove the subscription. The web chat is network-only and does not cache the application shell for offline use.
Web Push uses the browser vendor’s delivery service (for example, FCM or APNs) as an outbound dependency. Pesk does not need a public inbound endpoint or a separate notification server. The browser must be able to reach its push service, and Pesk must be able to make outbound HTTPS requests.
To generate a self-signed certificate for local/LAN HTTPS, run the helper from a shell and include the computer’s LAN IP:
./scripts/generate-tls-cert.sh "$APPDATA/pesk/tls" 192.168.1.23Replace 192.168.1.23 with the computer’s actual LAN IP. The script prints the webTlsKey and webTlsCert entries to add to the active configuration.
src/— Electron main process, controllers, preload bridge, and renderer modulessrc/renderer/— separate pet, chat, and menu pagesassets/— application icon and tray artworktests/— Jest testsscripts/— build cleanup, renderer asset-copy, and TLS certificate helpers




