Skip to main content

WebUI wrapper for Claude Code with auto journal - PWA frontend, REST + WebSocket API

Project description

pAInapple Code

A self-hosted bridge for Claude Code: the server runs the CLI on your machine, remote clients connect to it — streaming chat, interactive permission cards, an embedded terminal, git tools, multi-session tabs. It can also drive the OpenAI Codex CLI as a second engine (experimental).

The distinguishing feature is the Auto Journal: after every turn, a background agent commits all file changes to a per-project shadow git repo and writes a structured summary — work done, decisions, learnings — into a local DuckDB that later sessions can query.

The goal is native apps for every platform; a desktop app is in development. Today the client is a web app that installs as a PWA on iOS, Android, and desktop — a workable setup in practice: much of this project was written from a phone and an iPad through this same UI.

Documentation · Install · Features · Security

pAInapple Code session with the Auto Journal widget open next to the chat

Before you start

pAInapple Code hands a browser tab full control of a Claude Code instance on your machine. Three things to know before the quick start:

The default permission mode is Ask. The bridge drives Claude through the official Agent SDK; every tool call pauses on an approve/deny card — with a readable preview of the edit or command — until you decide. Less restrictive modes are opt-in, per session: Accept Edits, Auto (Claude's own classifier gates each call), Plan (read-only), and full bypass. 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 cover the interactive modes; for autonomous use, run the bridge in a container or VM. painapple --in-docker (below) is the built-in way to do that.

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 — adequate on a home network or VPN; 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 started here can be resumed in the plain CLI with claude --resume <id>. It doesn't rewrite prompts, inject planning steps, or change Claude's behavior. The same wrapper can drive the OpenAI Codex CLI, selected per session, resumable with codex exec resume <id> — the Codex path is newer and has had less testing than the Claude path.

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". The client works as a PWA on a phone or iPad, but the networking between them is yours to wire up. The practical path: keep the default 127.0.0.1 bind and add a reverse proxy (Caddy, nginx) or a VPN for remote access — mobile browsers handle self-signed certificates poorly.

Requirements

  • Direct install: Python 3.12+ and the Claude Code CLI, installed and authenticated. (The Docker image bundles both.)
  • Optional: the OpenAI Codex CLI, if you want the Codex engine.
  • 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.

Plain pip install painapple-code into a venv works too — see the pip/pipx guide.

Containers: painapple --in-docker

For the autonomous permission modes, run the bridge isolated. Docker is a built-in run mode — the same invocation, sandboxed in the prebuilt image:

pipx install painapple-code
painapple pull              # fetch the prebuilt image (one time)
painapple --in-docker       # serve the current directory, containerized

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. For a durable named sandbox, painapple setup myapp (pick "Docker" as the run mode) then painapple start myapp. Raw docker run / compose / Podman recipes and source builds: Docker install guide.

Desktop app (in development)

A native desktop app is in development. It wraps the same setup wizard in a GUI — 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.json boots every Codespace with the bridge installed, started, and port-forwarded → Dev Container Feature
  • From sourcegit clone, venv/bin/pip install -e ., run with venv/bin/painapplesource 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 most common flags:

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 to distinguish multiple instances
--tls auto Self-signed TLS, auto-enabled on non-loopback binds
--default-provider claude-sdk Default AI engine for new sessions — Claude Code (SDK or classic line protocol) or OpenAI Codex
--profile Run a named profile — several independent deployments (host or docker mode) under one user
--in-docker off Run the same invocation in a container instead (prebuilt image, cwd mounted)

painapple setup is an interactive wizard that saves global defaults (network/TLS + the container runtime for --in-docker); painapple setup NAME creates a named deployment — host or docker mode — that painapple start NAME runs in the background. painapple list shows every instance on the machine, and status/logs/password NAME inspect any of them.

painapple --help prints the full list; every flag, environment variable, and accent-color preset is in the server CLI reference.

Highlighted features

A selection — the full list is in the feature docs.

Auto Journal (shadow git)

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 the project's own history is queryable: from the Journal widget, over a SQL endpoint, or by future sessions. The optional shadow-git-helper agent covers that last case — write "consult shadow-git-helper about X" and a sub-agent digs through past turns without loading them into your main context. It's not a backup mechanism; it's a searchable record of what was done and why.

Journal widget showing per-turn Haiku summaries, files changed and cost, grouped by session

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

AI engines — Claude and Codex, per session

The bridge drives Claude Code by default and can run the OpenAI Codex CLI as a second engine — picked per session, so a Claude tab and a Codex tab sit side by side. Each engine brings its own model catalog, permission vocabulary (Codex maps to its sandbox tiers), and effort scale; a setup panel on every fresh session makes the choice one tap. Settings has a per-engine panel with model show/hide, per-engine defaults, and an in-app Log in flow for the CLI itself. → Engines guide

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.

Collapsed per-turn summary bar with file pills, tool counts, cost and duration

Comments stash

Click the bubble next to any paragraph, add a note, and it attaches — quote included — to your next prompt.

Selecting a paragraph, adding a note, and the stash attaching itself to the 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.

Embedded terminal running ls, git status and the project test suite

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). Mark favorites; reuse any result or fork it into a new session.

Prompt history explorer with search filters, a favorited prompt, and reuse actions

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.

  1. Windowing system — works, but doesn't support multiple instances of the same widget and could use a rethink.
  2. 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.
  3. 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.
  4. Codex engine — functional, but much newer than the Claude path and not yet as thoroughly tested.

License

AGPL 3.0 — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

painapple_code-1.0.0rc16.tar.gz (10.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

painapple_code-1.0.0rc16-py3-none-any.whl (2.3 MB view details)

Uploaded Python 3

File details

Details for the file painapple_code-1.0.0rc16.tar.gz.

File metadata

  • Download URL: painapple_code-1.0.0rc16.tar.gz
  • Upload date:
  • Size: 10.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for painapple_code-1.0.0rc16.tar.gz
Algorithm Hash digest
SHA256 e85a67cd3a0d2a1dfcc5fedd3a5cac8478c260cf649d565ca2a74a0e2d652f63
MD5 818555ea4b7407e88618ff7fdd766d70
BLAKE2b-256 35f9ddb97f0ac7f3b72410de701bce82a6b15e53cfcc57eba0e482cf09d3f00e

See more details on using hashes here.

Provenance

The following attestation bundles were made for painapple_code-1.0.0rc16.tar.gz:

Publisher: pypi-publish.yml on wrotek/painapple-code

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file painapple_code-1.0.0rc16-py3-none-any.whl.

File metadata

File hashes

Hashes for painapple_code-1.0.0rc16-py3-none-any.whl
Algorithm Hash digest
SHA256 9416fe9dd9084092fe2640b75409bca858c3053060b5a159cce3fec38454722f
MD5 78116bcdaa75bcf5f974a466f6876216
BLAKE2b-256 a5114776f09e3b2026dc4651c226009d3abae793b29893610ffcfc2d20777ce8

See more details on using hashes here.

Provenance

The following attestation bundles were made for painapple_code-1.0.0rc16-py3-none-any.whl:

Publisher: pypi-publish.yml on wrotek/painapple-code

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page