WebUI wrapper for Claude Code with auto journal - PWA frontend, REST + WebSocket API
Project description
pAInapple Code
Claude Code, from any browser. A self-hosted bridge that runs the Claude Code CLI on your machine and serves a fast, installable web UI on top — streaming chat, interactive permission cards, a real terminal, git tools, and an automatic journal of every turn.
No cloud middleman: your machine, your Claude account, your data.
Documentation · Install · Features · Security
The desktop browser is the primary target, but it installs as a PWA on iOS and Android too — roughly a third of this app was written from a phone, and most of the rest from an iPad with a hardware keyboard.
Before you start
pAInapple Code hands a browser tab full control of a Claude Code instance on your machine. That's the point — but it deserves three honest paragraphs before the quick start.
You stay in the loop. By default the bridge drives Claude through the official Agent SDK in Ask mode: every tool call pauses on an approve/deny card — with a readable preview of the edit or command — until you decide. From there you can loosen per session as trust grows: Accept Edits, Auto (Claude's own classifier gates each call), Plan (read-only), or full bypass when you're sandboxed and feeling brave. Permission mode and model switch live, mid-turn, without restarting the session. → Permissions guide
Isolate the autonomous modes. The embedded terminal is a real PTY, and anything Claude is approved to run executes as the user who started the server — prompt injection and poisoned packages are real risks for any coding agent. Approval cards keep the interactive modes reasonable, but if you want Claude working autonomously, run the bridge in a container or VM. painapple docker (below) makes that the easy path.
Network defaults are conservative. The server binds 127.0.0.1 over plain HTTP; non-loopback binds auto-enable TLS with a self-signed cert. Auth is a single-password gate — fine on a home network or VPN, but for anything public put your own reverse proxy in front. → Security notes
What it is, and what it isn't
It is a thin wrapper around Claude Code — every prompt streams through the official CLI/Agent SDK, and any session you start here can be resumed in the plain CLI with claude --resume <id>. It doesn't rewrite your prompts, inject planning steps, or change Claude's behavior.
It is not a hosted service. You run it, on your hardware, with your own Claude account.
It is not (yet) zero-config "code from anywhere". It works well as a PWA on a phone or iPad, but the networking between them is yours to wire up. The comfortable path: keep the default 127.0.0.1 bind and add a reverse proxy (Caddy, nginx) or a VPN for remote access — self-signed certs on mobile browsers are a rougher ride.
Requirements
- Direct install: Python 3.12+ and the Claude Code CLI, installed and authenticated. (The Docker image bundles both.)
- Client: any modern browser with network access to the server.
Quick start
pipx (recommended)
pipx install painapple-code
painapple --workspace /path/to/your/project
Open http://localhost:8765/. The first run prints a bootstrap URL with the password embedded as ?tkn=… — open it once and a cookie keeps you logged in.
That's the whole install. Plain pip install painapple-code into a venv works too — see the pip/pipx guide.
Containers: painapple docker
Prefer isolation? (For the autonomous modes, you should.) The same package ships a container front-end with an interactive setup wizard — workspace, credentials, network, all arrow keys, back navigation, and a review screen:
pipx install painapple-code
painapple docker # first run opens the setup wizard
painapple docker up -d # start the bridge detached
The image bundles Python, Node, and the Claude Code CLI; state persists in named volumes and your project is bind-mounted. Docker and Podman are auto-detected. In a hurry, painapple docker quick skips the wizard and serves the current directory. Raw docker run / compose / Podman recipes and source builds: Docker install guide.
Desktop app (in development)
The same setup wizard is on its way into a native desktop app — clickable instead of terminal-based: pick a folder, click through, get a running containerized bridge. Watch the releases.
More ways to run it
- GitHub Codespaces / Dev Containers — one line in
devcontainer.jsonboots every Codespace with the bridge installed, started, and port-forwarded → Dev Container Feature - From source —
git clone,venv/bin/pip install -e ., run withvenv/bin/painapple→ source install
Authentication
Every HTTP and WebSocket request needs a password. The server generates one on first start, stores it in ~/.config/painapple-code/config.yaml (inside the container that's under /home/app/; mode 0600 either way), and logs a bootstrap URL with the token embedded as ?tkn=… — open it once, the cookie does the rest.
# Reveal the password
awk '/^password:/ {print $2}' ~/.config/painapple-code/config.yaml
# …or when running in a container
docker exec painapple-code awk '/^password:/ {print $2}' \
/home/app/.config/painapple-code/config.yaml
# Rotate: delete the config, restart, and a new password is generated
rm ~/.config/painapple-code/config.yaml # then restart the server
# …or when running in a container
docker exec painapple-code rm /home/app/.config/painapple-code/config.yaml \
&& docker restart painapple-code
Three auth paths: the bridge_auth cookie (set automatically after first login), ?tkn=<password> in any URL, or Authorization: Bearer <password> for curl and scripts.
Server options
The flags you'll actually reach for:
| Flag | Default | Description |
|---|---|---|
--host / --port |
127.0.0.1 / 8765 |
Bind address and port |
--workspace |
. |
The directory Claude operates in (--cwd is an alias) |
--workspace-root |
= --workspace |
Directory scanned for sibling projects on the welcome screen |
--instance-name, --accent |
— | Label + accent color, so DEV and STABLE don't look alike |
--tls |
auto |
Self-signed TLS, auto-enabled on non-loopback binds |
--default-provider |
claude-sdk |
claude-sdk (interactive permission cards, live switching) or claude (classic line protocol) |
painapple --help prints the full list; every flag, environment variable, and accent-color preset is in the server CLI reference.
Highlighted features
The full tour lives in the feature docs — these are the bits people ask about.
Interactive permissions
Every tool call can pause on an approve/deny card with a human-readable preview — Write shows the file and content, Edit an old→new diff, Bash the command. Deny with a typed reason and it's fed back to the model as guidance. Cards surface the engine's own "always allow" suggestions, and permission mode + model switch live, mid-turn, over the Agent SDK control plane — no session restart. The Stop button interrupts gracefully and keeps the process warm. → Permissions guide
Shadow Git with auto-journal
After each turn, a background Haiku fork summarizes what happened and commits all file changes to a per-project shadow git repo (respecting .gitignore). Summaries are parsed into structured fields — work done, decisions, learnings, problems solved — and stored in a local DuckDB, so future sessions can query the project's own history. The optional shadow-git-helper agent does exactly that: write "consult shadow-git-helper about X" and a sub-agent digs through the past without bloating your main thread. Not a backup — a memory.
Per-turn summary bar
Context usage, token delta, files changed with diff stats, tool counts, duration, cost, and which model ran — inline after every turn. File pills open diffs and previews directly.
Comments stash
Click the bubble next to any paragraph, add a note, and it attaches — quote included — to your next prompt.
Embedded terminal
A real PTY via xterm.js (Ctrl+`). On mobile there's a Termius-style key bar with Ctrl/Alt/arrows above the keyboard, and a virtual d-pad joystick on touch-and-hold.
Prompt history + favorites
Search every prompt you've ever sent, across all sessions and projects, with phrase, exclusion, date, and content filters (Alt+P or Ctrl+R). Heart the good ones; reuse or fork into a new session from any result.
And more
Multi-session tabs, git widget, cost analytics, file explorer with rendered previews and in-place markdown editing, a sandboxed browser widget, # snippets and agent triggers, paste-to-annotate screenshot editor, discussion threads forked from any text selection, and switchable density modes. → All features
Optional helpers
A shadow-git CLI, a shadow-query DuckDB wrapper, and the shadow-git-helper Claude agent ship with the package — the Docker image installs all three at build time. On a host install:
src/painapple_code/tools/install-helpers.sh # --update / --uninstall / --dry-run
No sudo, no $PATH edits — targets ~/.local/bin and ~/.claude/agents/. Details: optional helpers reference.
Data storage
Everything lives under ~/.painapple-code/ (or $PAINAPPLE_CODE_HOME; /data in Docker): per-project sessions, shadow git repos, the DuckDB turn store, and logs. Auth config sits apart in ~/.config/painapple-code/config.yaml (mode 0600), so wiping the data directory doesn't rotate your password. Full layout: data & storage reference.
Known weaknesses
This is an MVP — there are tradeoffs.
- Windowing system — works, but doesn't support multiple instances of the same widget and could use a rethink.
- Code editor — currently a notepad with syntax highlighting. The plan is a review-driven workflow rather than a VSCode-grade editor; the markdown inline editor is the exception and works well for plan/doc tweaks.
- GUI for OS-level features (git widget, file explorer) — exists but the maintainer prefers the embedded terminal for
grep/sed/find/du, so these widgets have not been a priority.
License
AGPL 3.0 — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file painapple_code-1.0.0rc5.tar.gz.
File metadata
- Download URL: painapple_code-1.0.0rc5.tar.gz
- Upload date:
- Size: 9.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e47d2f260c14cb2417dcea59eadcad4db45042f6e7949dde1e3274d10072b2c8
|
|
| MD5 |
54d7de24aec538eb27471c0b90c7843b
|
|
| BLAKE2b-256 |
32d4bf109ba6071f0b0605f3ee9d2c96d006c5dba0f8d7a56a3e4f0baf516b29
|
Provenance
The following attestation bundles were made for painapple_code-1.0.0rc5.tar.gz:
Publisher:
pypi-publish.yml on wrotek/painapple-code
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
painapple_code-1.0.0rc5.tar.gz -
Subject digest:
e47d2f260c14cb2417dcea59eadcad4db45042f6e7949dde1e3274d10072b2c8 - Sigstore transparency entry: 2139750992
- Sigstore integration time:
-
Permalink:
wrotek/painapple-code@735ba68555df3685095cbaf117c7d00866c50ce5 -
Branch / Tag:
refs/tags/v1.0.0-rc5 - Owner: https://github.com/wrotek
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@735ba68555df3685095cbaf117c7d00866c50ce5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file painapple_code-1.0.0rc5-py3-none-any.whl.
File metadata
- Download URL: painapple_code-1.0.0rc5-py3-none-any.whl
- Upload date:
- Size: 2.1 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74223229f9b912ecc1f512a2490f549e3412cbf9c421fd8f020aef72da2086d9
|
|
| MD5 |
6f3ae5ace1e9a345b4524a29e4d9632f
|
|
| BLAKE2b-256 |
059c792b20ff969e1ea38b9f7176f32e51e20cd9ae1d0a600926424e667c858e
|
Provenance
The following attestation bundles were made for painapple_code-1.0.0rc5-py3-none-any.whl:
Publisher:
pypi-publish.yml on wrotek/painapple-code
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
painapple_code-1.0.0rc5-py3-none-any.whl -
Subject digest:
74223229f9b912ecc1f512a2490f549e3412cbf9c421fd8f020aef72da2086d9 - Sigstore transparency entry: 2139750998
- Sigstore integration time:
-
Permalink:
wrotek/painapple-code@735ba68555df3685095cbaf117c7d00866c50ce5 -
Branch / Tag:
refs/tags/v1.0.0-rc5 - Owner: https://github.com/wrotek
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@735ba68555df3685095cbaf117c7d00866c50ce5 -
Trigger Event:
push
-
Statement type: