Skip to content

Repository files navigation

🧳 PortableCoder

A portable launcher for AI coding CLIs — copy the folder, run anywhere

Claude Code and OpenAI Codex on any Windows, macOS, or Linux machine — or a flash drive — with no system-wide install.

CI Node Platform Tools Made for Claude Code License: MIT


PortableCoder bundles a portable Node.js runtime and the selected tool's npm package inside one self-contained folder. Credentials are stored portably inside the folder (no registry writes, no system config, no admin rights), so the whole thing travels — USB stick, network share, or a plain copy to a new machine.

Supported tools: Claude Code and OpenAI Codex CLI. More can be added via scripts/adapters/catalog.jsonno code changes required.

✨ What's inside

🚀 Portable runtime 🔐 Portable auth 🔄 Auto-updates 🛡️ VM mode
Bundled Node.js + tool installs under runtime/ — no system Node needed, ever: pcoder bootstraps its own OAuth credentials live in state/auth/<tool>/ and travel with the folder Daily npm check at launch, fail-open when offline, safe reinstall path Optional QEMU Linux VM on Windows for isolated runs (Claude only)

🚀 Quick start

1 · Bootstrap (first time only)

No system Node.js required. Clone the repo and run the commands below — pcoder obtains its own Node.js on first use.

:: Windows
scripts\pcoder setup --init
scripts\pcoder runtime bootstrap-host-native --tool all
# Linux / macOS
scripts/pcoder setup --init
scripts/pcoder runtime bootstrap-host-native --tool all

This installs the requested tools into the folder (~50 MB per tool). Pass --tool claude or --tool codex to install just one. Run pcoder doctor afterwards to verify — it reports the resolved runner for every supported tool.

How Node.js gets there

runtime/ is gitignored, so a fresh clone contains no bundled Node.js. pcoder resolves a runtime in three steps:

  1. bundled runtime/node/ — used if present
  2. system node on PATH — used if found
  3. neither: auto-bootstrap. pcoder downloads a portable Node.js into runtime/node/, verifies it against the official SHASUMS256.txt, extracts it, and re-runs itself. Nothing is installed system-wide and nothing outside the folder is touched.

Step 3 runs without Node.js by design — the regular bootstrap (bootstrap-host-native.cjs) can't do this job because it is itself a Node script:

Host Script Requires
Windows scripts\runtime\bootstrap-node.ps1 Windows PowerShell 5.1 (built in) or pwsh
Linux / macOS scripts/runtime/bootstrap-node.sh bash, curl or wget, tar, and xz on Linux

Ubuntu and Alma/RHEL have everything needed out of the box, except that minimal RHEL/Alma images may omit xz — install it with sudo dnf install -y xz (Debian/Ubuntu: sudo apt-get install -y xz-utils) if the bootstrap asks for it.

You can also run either script directly, for example to pre-seed a machine before using pcoder:

powershell -ExecutionPolicy Bypass -File scripts\runtime\bootstrap-node.ps1
bash scripts/runtime/bootstrap-node.sh

Windows: use the full command above, not scripts\runtime\bootstrap-node.ps1 on its own. The scripts in this repo are unsigned, so on a machine whose execution policy is AllSigned (or RemoteSigned, if the folder was downloaded as a zip) PowerShell refuses to load the file:

... is not digitally signed. You cannot run this script on the current system.

-ExecutionPolicy Bypass applies to that one invocation only and changes nothing on the machine. You do not need it when using pcoderscripts\pcoder already passes it when it auto-bootstraps. See Execution policy if the flag doesn't help.

To turn the automatic step off — for an air-gapped host, or when you'd rather supply Node.js yourself — set PCODER_AUTO_BOOTSTRAP=0 (matching PCODER_AUTO_UPDATE=0). pcoder will then fail with instructions instead of downloading anything.

After the first bootstrap the whole folder is self-contained: copy it to a machine with no Node.js at all and it runs as-is.

2 · Authenticate

scripts\pcoder auth login                  :: Claude Code (default) — Anthropic OAuth
scripts\pcoder auth login --tool codex     :: OpenAI Codex — ChatGPT account or API key

Each login runs the tool's own login flow with HOME rewritten to a portable directory, so credentials land under state/auth/<tool>/host/home/ (gitignored) instead of your user profile. pcoder auth status shows the state for every tool.

Codex logs in with device authorization. pcoder invokes codex login --device-auth, which prints a URL and a short code to enter on any device with a browser, instead of opening a local browser and waiting on a localhost callback. That suits how PortableCoder is typically run — over SSH, on a headless or locked-down box, or from a folder on a flash drive — where a loopback redirect often can't complete. Claude Code continues to use its own default login flow.

3 · Launch

scripts\pcoder                             :: default tool, current directory
scripts\pcoder codex                       :: a specific tool
scripts\pcoder run --project C:\my-project :: a specific project folder
scripts\pcoder claude -p "explain this codebase"

After a tool name, remaining arguments are forwarded as-is — no -- separator needed unless an argument collides with a pcoder flag (--project, --mode, --tool, --no-sync-back). On Linux/macOS use scripts/pcoder with forward slashes.

⚙️ How it works

flowchart LR
    A["scripts/pcoder<br/>(.cmd / bash)"] --> B["pcoder.cjs<br/>launcher"]
    B --> C{"run mode?"}
    C -->|host-native| D["auto-update check<br/>(daily, fail-open)"]
    D --> E["rewrite HOME to<br/>state/auth/&lt;tool&gt;/"]
    E --> F["launch bundled tool<br/>runtime/&lt;tool&gt;/"]
    C -->|linux-portable<br/>Windows only| G["QEMU VM<br/>WHPX → TCG fallback"]
    G --> H["sync project via SSH,<br/>run tool in guest"]
Loading

scripts/adapters/catalog.json is the source of truth for tool dispatch: every entry with an npm_package becomes a launchable tool, with its own env vars, config directory, and auth wiring resolved from the catalog at startup.

🧭 Run modes

Mode How it works File access Tools Setup
host-native (default) Runs the tool directly on the host via bundled Node.js Full host filesystem claude, codex runtime bootstrap-host-native
linux-portable Runs the tool inside a QEMU Linux VM Synced project directory only claude only runtime bootstrap

On Windows, the configured windows_default_mode is used unless an auto-fallback applies: host-native is preferred when the bundled tool runtime exists (no VM startup cost), and forced when the tool's catalog entry has vm_supported: false (currently codex). On Linux/macOS, host-native is always used; linux-portable there reuses the same isolated-auth wiring without a VM.

scripts\pcoder setup --windows-mode linux-portable   :: change the default
scripts\pcoder run --mode linux-portable             :: override one session
scripts\pcoder setup --default-tool codex            :: pick a default tool

🔄 Keeping tools updated

Automatic updates

By default, pcoder checks npm for a newer version of the bundled tool at most once per 24 hours when launching it in host-native mode (3-second timeout; if the registry is unreachable the installed version launches immediately). When an update is found it is installed via the safe bootstrap path before the tool starts.

scripts\pcoder setup --auto-update false   :: disable permanently
set PCODER_AUTO_UPDATE=0                   :: disable for one invocation

Manual updates

Use the bootstrap with --force — it pulls the latest version published to npm and writes cleanly into runtime/<tool>/:

scripts\pcoder runtime bootstrap-host-native --tool all --force

--force re-installs the tools but keeps the bundled Node.js, which cannot replace itself while it is the interpreter running the bootstrap. To force a Node.js re-download too, run scripts/runtime/bootstrap-host-native.cjs with a system Node.js, or delete runtime/node/ first and let it re-bootstrap.

Warning: Do not use the tools' built-in self-updaters (claude --update, codex update, …) on a pcoder install. They rewrite their own binary in place, and the bundled install hardlinks that binary across two locations — an interrupted update breaks the next launch. pcoder refuses these invocations; set PCODER_ALLOW_TOOL_UPDATE=1 to bypass (not recommended).

🔐 Authentication

Each tool tracks its own auth mode (oauth or api).

OAuth (default) — credentials are written to state/auth/<tool>/host/ and travel with the folder. Nothing is stored in system directories. The exact login command per tool comes from login_args in the catalog, so Codex gets --device-auth while Claude gets a plain login.

API key mode — keys are injected from environment variables at launch and never written to disk by PortableCoder:

scripts\pcoder setup --claude-auth api
set ANTHROPIC_API_KEY=sk-ant-...
scripts\pcoder

ANTHROPIC_AUTH_TOKEN is accepted as an alias for ANTHROPIC_API_KEY. Codex uses OPENAI_API_KEY.

🛡️ VM mode (Windows, Claude only)

Runs Claude Code inside a self-contained QEMU Linux VM for environments where host-native execution isn't wanted. The tool has no direct host file access — project files sync in and out over SSH. Uses WHPX acceleration when available, falling back to software emulation (TCG).

scripts\pcoder runtime bootstrap          :: one-time: QEMU + Ubuntu image (~1 GB, SHA-256 verified)
scripts\runtime\windows\smoke-check.cmd   :: optional: verify the VM boots
scripts\pcoder run --mode linux-portable  :: launch

Bypassing approvals (advanced)

Both tools expose flags that disable their interactive approval prompts. These are forwarded as-is — pcoder does not parse, gate, or persist them.

scripts\pcoder claude --dangerously-skip-permissions
scripts\pcoder codex --dangerously-bypass-approvals-and-sandbox

Warning: these flags let the model run shell commands and modify files without asking. Anything your user account can do, the model can do. Use only in throwaway directories or VMs where the blast radius is contained.

📖 Command reference

Command Description
pcoder Launch the default tool in the current directory
pcoder <tool> [args...] Launch a specific tool (e.g. pcoder codex)
pcoder doctor Check environment health
pcoder setup --init Initialize state/settings.json with defaults
pcoder setup --show Print current settings
pcoder setup --default-tool <claude|codex> Change the default tool
pcoder setup --claude-auth <oauth|api> Change Claude authentication mode
pcoder setup --codex-auth <oauth|api> Change Codex authentication mode
pcoder setup --windows-mode <linux-portable|host-native> Change Windows run mode
pcoder setup --auto-update <true|false> Enable/disable automatic updates
pcoder setup --sync-back <true|false> Control whether VM files sync back after a run
pcoder auth status Show authentication status for all tools
pcoder auth login|logout [--tool <name>] Log in / out via OAuth
pcoder runtime probe Show available runtime backends
pcoder runtime bootstrap [--force] Download VM runtime (QEMU + Ubuntu)
pcoder runtime bootstrap-host-native [--tool <name|all>] [--force] Download Node.js + tool(s)
pcoder run [--tool <name>] [--project <path>] [--mode <mode>] [-- <tool args>] Full launch control

Environment variables

Variable Purpose
ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN Claude API key (api auth mode)
OPENAI_API_KEY Codex API key (api auth mode)
ANTHROPIC_BASE_URL / OPENAI_BASE_URL Override API base URLs
PCODER_CLAUDE_CMD / PCODER_CODEX_CMD Override the resolved tool command
PCODER_AUTO_UPDATE Set to 0 to skip the automatic update check for one invocation
PCODER_ALLOW_TOOL_UPDATE Set to 1 to allow the tools' native self-updaters (not recommended)
PCODER_VM_SSH_TIMEOUT_SECONDS Max seconds to wait for VM SSH (default: 300)
PCODER_VM_HOST / PCODER_VM_USER / PCODER_VM_SSH_KEY VM SSH connection overrides
PCODER_VM_PROJECTS_ROOT Remote path for synced projects
PCODER_SSH_CMD Override SSH client path
HTTP_PROXY / HTTPS_PROXY / NO_PROXY Proxy settings forwarded into the VM

📁 Repository layout

PortableCoder/
  scripts/
    pcoder.cmd / pcoder        ← Windows / POSIX entry points
    pcoder.cjs                 ← launcher logic (Node.js, cross-platform)
    lib/paths.cjs              ← shared path helpers
    adapters/catalog.json      ← tool adapter definitions (claude, codex, …)
    runtime/
      bootstrap-host-native.cjs  ← downloads Node + tools, verifies checksums
      bootstrap-node.ps1         ← no-Node fallback for Windows (PowerShell)
      bootstrap-node.sh          ← no-Node fallback for Linux/macOS (bash)
      windows/                   ← QEMU VM helper scripts
      linux/smoke-check.sh       ← Linux smoke test
  tests/                       ← unit tests (node:test, zero dependencies)
  runtime/                     ← bundled binaries (gitignored, travels with the folder)
  state/                       ← settings, auth, VM state (gitignored)
  docs/                        ← design specs and implementation plans

🧩 Adding a tool

scripts/adapters/catalog.json drives everything. To add a new CLI: add an entry with npm_package, bin_name, candidate_commands, command_env, config_dir_name/config_dir_env, auth_env_vars, api_key_env, and vm_supported, then run pcoder runtime bootstrap-host-native --tool <name>. No code changes needed — the launcher treats every catalog entry with an npm_package as launchable.

Optional login_args / logout_args set the argv pcoder auth login|logout invokes the tool with, for CLIs whose auth flow needs flags — codex uses ["login", "--device-auth"]. Omit them and the bare verb is used.

🔒 Security

  • OAuth credentials are stored in gitignored state/auth/<tool>/ — never committed, never written to system directories.
  • API keys are passed via environment variables and never written to disk by PortableCoder.
  • Downloads are verified: Node.js against SHASUMS256.txt, the Ubuntu VM image against SHA256SUMS, the QEMU installer against its SHA-512. A failed verification removes the artifact rather than leaving it to be trusted later.
  • Host-native mode gives the tool the same file access as any program you run; VM mode confines it to explicitly synced files.
  • CI runs gitleaks on every push.

Execution policy (Windows)

The .ps1 scripts in this repo are not code-signed. Windows only cares about that when you run a script file directly, and each entry point already handles it:

How you run it Signature needed?
scripts\pcoder … (normal use, including auto-bootstrap) No — it passes -ExecutionPolicy Bypass internally
powershell -ExecutionPolicy Bypass -File scripts\runtime\bootstrap-node.ps1 No — the flag scopes to that one process
scripts\runtime\bootstrap-node.ps1 (bare) Yes, and it fails without one

If the Bypass flag doesn't help, your policy is being enforced by Group Policy, which command-line flags cannot override. Check which scope is responsible:

Get-ExecutionPolicy -List

A value on MachinePolicy or UserPolicy means it's set by your organization — the supported fix is to ask IT to allow it or to sign the scripts with a certificate your machines already trust, not to work around the policy. A value on LocalMachine or CurrentUser is yours to change:

Set-ExecutionPolicy -Scope CurrentUser RemoteSigned

If the folder arrived as a downloaded .zip, Windows also tags the files as web content, which RemoteSigned blocks. Clear the tag with:

Get-ChildItem -Recurse *.ps1 | Unblock-File

🔬 Development process

This codebase is developed with Claude Code using a spec → plan → review loop: design documents live in docs/superpowers/specs/, implementation plans in docs/superpowers/plans/, and every change lands through CI that runs the unit suite, bootstraps both tools for real, and executes the smoke test — no masked failures.

npm test          # unit tests (node:test, no dependencies)
scripts/pcoder doctor

🤝 Contributing

Issues and PRs welcome. Before submitting: npm test, npx prettier --check "scripts/**/*.cjs" "tests/**/*.cjs", and make sure scripts/pcoder doctor passes. PRs run through the full CI gate.

📄 License

MIT © 2026 Mike Jenkins


Built with Claude Code · Bundle it, copy it, code anywhere 🧳

About

Portable launcher for AI coding CLIs (Claude Code, OpenAI Codex) — copy the folder, run anywhere. No system-wide install.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages