Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
cacae15
implement remote connection mode
aronprins Apr 6, 2026
feaad69
fix local packaged server startup
aronprins Apr 6, 2026
d77fcdf
Add remote recovery loop for setup-required remotes
aronprins Apr 6, 2026
953e523
Keep remote setup flow in one launcher window
aronprins Apr 6, 2026
9b04219
Refine attached connection sheet loop
aronprins Apr 6, 2026
c017815
Improve launcher modal sizing and close button placement
aronprins Apr 6, 2026
a653d90
Hide launcher title bar
aronprins Apr 6, 2026
f9e1090
Default chooser to local mode
aronprins Apr 6, 2026
12438fa
Fix launcher modal resize measurement
aronprins Apr 7, 2026
4d5d617
Allow remote auth flow in app
aronprins Apr 8, 2026
8d6f8b5
Remove dead remote loop code
aronprins Apr 8, 2026
a1a764c
Improve launcher UX: sizing, accessibility, and interaction polish
aronprins Apr 8, 2026
a035821
Fix local embedded server restart lifecycle
aronprins Apr 8, 2026
6164b11
Strip bundled server bin shims before packaging
aronprins Apr 8, 2026
bc7bada
Redesign chooser as tabbed Local/Remote layout with smooth resize
aronprins Apr 8, 2026
5e38544
Clean up launcher chooser edit flow
aronprins Apr 8, 2026
3a07315
Fix launcher flicker and local session reloads
aronprins Apr 8, 2026
716ee7c
Align launcher sizing and menu behavior
aronprins Apr 8, 2026
c88e578
Fix launcher menu activation behavior
aronprins Apr 8, 2026
b5f8ae9
Restore dynamic window resize for both standalone and attached launcher
aronprins Apr 8, 2026
12f4e52
Defer launcher show until first content measurement
aronprins Apr 8, 2026
56d7330
Fix launcher modal content sizing on macOS
aronprins Apr 8, 2026
74c45c2
fix launcher sheet sizing and package aws sdk deps
aronprins Apr 9, 2026
f3ab73e
fix remote reconnect and local server recovery
aronprins Apr 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ build/server-bundle/
build/server-staging/
build/node-bin/
build/upstream-clone/
docs/development/paperclip/
docs/mockups/chooser-variations.html

# Electron-builder output
release/
Expand Down
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,17 @@
The goal is simple: **make running Paperclip as easy as opening an app.**

- 🖱 **One click to launch** — double-click the app and Paperclip starts automatically. No terminal, no `pnpm install`, no Node.js setup.
- 🌐 **Remote connection mode** — connect the desktop shell to verified upstream Paperclip remotes in authenticated mode, with saved connections and quick reconnects.
- 📦 **Paperclip inside** — ships an unmodified build of the upstream Paperclip server and UI. What you get in the app is exactly what you'd get by cloning and running the main repo.
- 🔄 **Auto-updates** — pulls new desktop releases automatically via GitHub Releases.
- 🖥 **Native menus, windowing, and system tray** — the Paperclip UI, but as a real desktop app.

Under the hood, on launch the app:
Under the hood, the app can either:

1. Picks a free local port (starting at `3100`)
2. Spawns the bundled Paperclip Node.js server
3. Waits for it to become healthy
4. Loads the Paperclip UI in a native Electron window
1. Run the embedded local server flow
2. Or verify a remote Paperclip origin via `/api/health` and `/api/auth/get-session` before loading it in a restricted remote-safe Electron window

When you quit the app, the server is cleanly shut down.
When local mode is active, the server is cleanly shut down when you quit the app.

> For everything Paperclip itself can do — orchestrating AI agents, running autonomous companies, governance, budgets, org charts, etc. — see the **[upstream Paperclip repo](https://github.com/paperclipai/paperclip)**. This project does not modify or extend Paperclip's functionality; it only packages it.

Expand Down Expand Up @@ -94,6 +93,7 @@ Requirements: Node.js 20+, pnpm 9.15+.
pnpm install # Install deps
pnpm dev # Run Electron in dev mode against the bundled server
pnpm build # Compile the Electron main/preload TypeScript
pnpm test:connections # Run connection persistence, preflight, and origin-policy tests
pnpm prepare-server # Stage the Paperclip server bundle into build/
pnpm build-ui # Stage the Paperclip UI
pnpm pack # Build an unpacked app directory (no installer)
Expand All @@ -103,7 +103,9 @@ pnpm dist:mac # macOS (.dmg + .zip, signed/notarized via local script)

Key files:

- `src/main.ts` — Electron main process: spawns the Paperclip server, manages its lifecycle, and opens the window
- `src/main.ts` — Electron main process: launcher IPC, local/remote boot orchestration, menu actions, and server lifecycle
- `src/connection/` — Connection persistence, remote validation/preflight, and exact-origin window policy helpers
- `src/launcher-html.ts` — Internal launcher UI for the chooser, remote connect flow, saved connections, and local boot states
- `src/preload.ts` — Preload script for the renderer
- `src/updater.ts` — Auto-update wiring (`electron-updater` against GitHub Releases)
- `electron-builder.yml` — Packaging config; bundles the `@paperclipai/server` npm package plus a platform-specific Node.js binary into `Resources/app-server/`
Expand Down
182 changes: 182 additions & 0 deletions docs/guides/local-testing-remote-connection-mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# Local Testing Guide: Remote Connection Mode

This guide captures the exact local test paths for the remote connection mode implementation on `feature/remote-connection-mode`.

## Quick remote-mode test

Use this when you want to verify the new launcher, chooser, remote connect flow, saved connections, and menu-based quick connect.

```bash
git checkout feature/remote-connection-mode
pnpm install
pnpm dev
```

Notes:

- `pnpm dev` compiles the Electron shell and launches it directly from `dist/main.js`
- this is the fastest path for testing remote mode
- use it to verify:
- chooser flow
- remote verification states
- sign-in-required remotes
- saved connections CRUD
- Connection menu quick connect entries

## Full local package test

Use this when you want the packaged desktop app shape rather than the direct dev shell.

```bash
git checkout feature/remote-connection-mode
pnpm install
pnpm test:connections
pnpm run pack
```

Important:

- use `pnpm run pack`, not `pnpm pack`
- `pnpm pack` is pnpm's built-in tarball command and does not run the Electron Builder packaging script

What `pnpm run pack` does:

1. builds the Electron TypeScript
2. stages the bundled `@paperclipai/server`
3. stages the Paperclip UI
4. runs Electron Builder with `--dir`

## Result from the latest local run

These commands were run in this repo:

```bash
pnpm test:connections
pnpm run pack
```

Observed result:

- `pnpm test:connections` passed
- `pnpm run pack` successfully completed:
- Electron TypeScript build
- server bundle staging
- UI staging from `@paperclipai/ui@2026.403.0`
- Electron Builder then stopped during macOS signing with:

```text
macOS release signing requires APPLE_CODESIGN_IDENTITY or CSC_NAME.
```

## Current artifact paths

Even though the signing hook failed, Electron Builder did create an unpacked app bundle directory before aborting:

```text
release/mac/Paperclip Desktop.app
```

This path exists from the latest local run.

## Signing requirement

The current macOS packaging flow requires one of these environment variables before a full packaged build can complete:

```bash
export APPLE_CODESIGN_IDENTITY="Developer ID Application: ..."
```

or

```bash
export CSC_NAME="Developer ID Application: ..."
```

Without one of those values, `pnpm run pack` will stop in `scripts/after-pack.mjs`.

## Recommended local test sequence

If you want the shortest reliable path today:

1. Run `pnpm dev` to test remote mode end-to-end.
2. Run `pnpm test:connections` to verify the connection logic and security checks.
3. Only run `pnpm run pack` if you have a signing identity configured or specifically want to inspect the partially-built unpacked app bundle.

## Testing when you do not have a remote Paperclip

You can still test a large part of the feature without a real remote.

### Expected negative-path tests

These are useful and should behave as follows:

- `https://localhost:3100`
- expected to fail
- the embedded local Paperclip server is plain HTTP, not HTTPS
- if nothing is listening there yet, `host unreachable` is expected
- `http://localhost:3100`
- once the embedded local mode is already running, this should identify Paperclip but reject it for remote mode
- expected reason: `deploymentMode=local_trusted`
- this is correct behavior, not a bug
- `https://example.com`
- expected result: reachable but not Paperclip
- malformed URLs
- expected result: inline validation failure

Important:

- the desktop app intentionally blocks `local_trusted` remotes in remote mode
- the normal embedded local startup uses `local_trusted` by default
- so `localhost` is not a valid positive remote-mode target for this feature

### Positive-path remote test without owning a real remote machine

If you want to test the success path on your own machine, start a second Paperclip instance manually in upstream `authenticated` mode on a different port.

At minimum, that instance needs:

- `PAPERCLIP_DEPLOYMENT_MODE=authenticated`
- `BETTER_AUTH_SECRET=...`

Useful additional settings for a local authenticated test instance:

- `PORT=3200`
- `PAPERCLIP_AUTH_PUBLIC_BASE_URL=http://127.0.0.1:3200`
- `PAPERCLIP_ALLOWED_HOSTNAMES=127.0.0.1,localhost`

That gives you a remote-mode target like:

```text
http://127.0.0.1:3200
```

This is the easiest way to test:

- verified authenticated remote
- sign-in-required state
- bootstrap/setup-required state
- saved remote profiles
- reconnect behavior
- remote window isolation

If that authenticated test instance has not been bootstrapped yet, or there is no active session yet, Desktop should still open the verified remote and let the upstream Paperclip UI handle setup or sign-in in-app.

## What to verify manually

- Local vs Remote chooser behavior
- `Remember my choice and don't ask again`
- remote verification success for authenticated Paperclip remotes
- sign-in-required remote behavior
- setup-required remote behavior in the remote Paperclip UI
- blocking of:
- non-Paperclip endpoints
- `local_trusted` remotes
- malformed URLs
- embedded credential URLs
- saved connections:
- add
- edit
- duplicate
- delete
- reconnect from the Connection menu
- local boot path still opens the embedded server flow
6 changes: 6 additions & 0 deletions docs/prds/remote-connection-mode-prd.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ Validation:

- Require `http://` or `https://`
- Normalize trailing slashes
- Reject URLs that embed `username:password@host` credentials
- Warn for non-HTTPS unless hostname matches private or tailnet patterns
- Block malformed URLs before any network call

Expand Down Expand Up @@ -422,12 +423,17 @@ Store only:
- profile metadata
- last known health metadata
- local settings
- per-profile or per-origin Electron browser session state needed to preserve upstream remote sign-in continuity

Do not store:

- remote passwords
- raw auth tokens copied out of the browser context

Implementation note:

- if the user asks Desktop to remember an otherwise-unsaved remote choice, Desktop may first persist that verified remote as a normal saved profile so the reconnect target remains stable without storing credentials

---

## 10) Error Handling UX
Expand Down
Loading