Skip to content
plakioPublic

About

Plak CLI is the simplest way to run local WordPress sites and deploy them to any cloud — instant environments, built-in HTTPS, and seamless workflows from your terminal.

Resources

Contributing

Stars

2 stars

Watchers

1 watching

Forks

Repository files navigation

plak

Plak CLI is a Bash + gum tool for everyday local developer tasks:

  • SSH server aliases in ~/.ssh/config
  • Local domain entries in /etc/hosts
  • SSH keys in ~/.ssh
  • Local WordPress and plain static sites served through Caddy/FrankenPHP

It follows a modular structure: source files are compiled into a single distributable plak.sh script.

Quickstart

# Install Plak CLI
curl -fsSL https://plak.sh/install | bash

# Install local dependencies
plak install

# Create a WordPress site
plak add my-site

# Access the dashboard
open https://plak.localhost

Requirements

  • Bash
  • gum
  • ssh and ssh-keygen
  • frankenphp, mariadb, mailpit, and wp-cli for local site management
  • sudo for writing to /etc/hosts when needed

Installation

Install Plak with Homebrew:

brew install plakio/tap/plak-cli

Or tap the repository first:

brew tap plakio/tap
brew install plak-cli

You can also install Plak directly with the installer script:

curl -fsSL https://plak.sh/install | bash

Install the Plak agent skill for Codex, Claude Code, OpenCode, Hermes, Pi, or the global agent skills directory:

plak skill install

For scripted setup:

plak skill install codex
plak skill install claude-code
plak skill install opencode
plak skill install hermes
plak skill install pi
plak skill install global
plak skill install all

all installs agent-specific targets only (codex, claude-code, opencode, hermes, and pi). Use global explicitly to install into ~/.agents/skills.

For local development, Plak can also install/check the local site stack:

./plak.sh install

Development

Compile the distributable script:

./compile.sh

Run locally:

./plak.sh status
./plak.sh server list

Run smoke tests:

./tests/smoke.sh

Install the local compiled script as plak:

./install.sh --dev

See docs/homebrew.md for release and tap maintenance.

Project Structure

main              # globals, help, OS detection, command router
shared/           # shared UI and validation helpers
commands/         # command modules
compile.sh        # builds plak.sh
plak.sh           # compiled distributable script
install.sh        # local installer

Commands

plak status
plak version
plak install
plak skill install
plak enable
plak disable
plak reload

The local site dashboard is served at https://plak.localhost after install. Each site has a linkable detail view at https://plak.localhost/#/site/<name> showing its type, URL, path, size and links to open the site, log in, or reach Adminer and Mailpit; WordPress version and plugin counts load on demand.

A WordPress site's detail view also manages plugins and themes: it lists name, version, status and available updates (special-casing must-use plugins and the active theme), and lets you activate, deactivate, update and delete. Update checks against WordPress.org run only when you ask; opening the list never blocks on a remote query. Invalid actions (deactivating a must-use plugin, deleting the active theme) are prevented in the UI and refused by the API, which passes arguments as data and respects the site's runtime.

A WordPress site's detail view also offers day-to-day tooling. Users lists each account with its roles and mints a one-time login link for any of them — not only administrators; links expire and are consumed on first use. Cron lists scheduled events and runs one event or all due events. Console runs WP-CLI inside the site with arguments passed as data, never as a shell command.

Every site's detail view includes a diagnostics panel. Logs reads the shared PHP error log (filtered to the site), wp-content/debug.log and the Caddy access log, with level/search filters, grouped consecutive repeats and expandable stack traces, reading only the tail of each file. Traffic aggregates the access log into requests, errors, bytes and latency, top paths and slowest requests over selectable windows, and classifies pages, assets, admin, AJAX/REST and cron explicitly; these are local request metrics, not production analytics.

The dashboard inbox reads mail captured by Mailpit, globally or filtered by site, attributing a message to a site by its addresses, subject or snippet. Opening a message marks it read; read/unread and delete go through Mailpit. The HTML body is sanitized, inline cid: images are resolved to data URIs, and the body renders in a sandboxed frame whose policy blocks scripts and remote images until you opt in.

The backups panel lists a site's snapshots and creates, restores, deletes and downloads them, and the dashboard can import a backup archive into a new site. Snapshot creation, restore and import run as background jobs whose progress survives a page reload.

The dashboard, Adminer and Mailpit are administrative surfaces: Caddy answers them only from the local machine (and WSL2's private adapter), and Tailscale exposes them only from the tailnet's address space. api.php repeats the check in PHP and requires same-origin Origin/Referer plus a per-install CSRF token on every mutating request. The Host header is never treated as authentication.

Sites

plak add <name> [--plain] [--agent|--no-agent]
plak import <name> <backup.zip> [--yes]
plak delete <name> [--force]
plak rename <old-name> <new-name>
plak list [--totals]
plak login <site> [<user>]
plak wp <site> <wp-cli arguments...>
plak agent <site> [--json]
plak path <name>
plak url <name>
plak log [site] [-f]

Run WP-CLI from any directory using the site's FrankenPHP runtime:

plak wp my-site plugin list --format=json
plak wp my-site option get siteurl
plak wp my-site core --help

Arguments after the site name, including --quiet, --json, and --help, are forwarded unchanged. Standard input/output, errors and the exit status are passed through; plak wp --help shows Plak's wrapper help. No TTY is needed.

Plak resolves the wp executable through symlinks and common shell wrappers referencing a literal PHAR path (including quoted paths with spaces and $HOME). Wrappers with computed paths that cannot be resolved are rejected with guidance to put the official WP-CLI PHAR on PATH. This keeps CLI and web on the same PHP.

New WordPress sites use WP_ENVIRONMENT_TYPE=local and keep debug logging enabled. Creation checks every installation stage and cleans up only the directory and database created by that invocation if provisioning fails. An existing database is never reused. If only the server reload fails, the completed site is kept and Plak reports how to retry the reload.

Agent-ready sites

A new WordPress site becomes agent-ready by default when wp-mcp-cli is installed, so nobody has to remember a flag:

plak add my-site            # agent-ready when wp-mcp-cli is available
plak add my-site --no-agent # opt out
plak add my-site --agent    # force, even if you want it explicit

This installs and activates the WP-MCP and HTML Editor plugins from downloads.plak.io, sets a standard permalink structure and enables WP-MCP's abilities (locked to the site's host) so its REST API answers, mints a scoped WordPress Application Password, registers the site with wp-mcp-cli under a profile named after the site, and verifies that WP-MCP abilities are discoverable. plak import and plak clone prepare WordPress sites the same way (or tell you how), and plak list shows which sites are agent-ready. Agent preparation requires WordPress and cannot be combined with --plain. The plugins are downloaded with the PlakCLI/<version> User-Agent, so the downloads host can allow Plak through its firewall without opening the archives to the world. --agent requires WordPress and cannot be combined with --plain.

plak install installs wp-mcp-cli and its jq dependency alongside Plak, and plak skill install also installs the official wp-mcp skill for the selected agents. After a successful --agent run the site is driven through wp-mcp:

wp-mcp --site my-site --json discover
wp-mcp --site my-site run wp-mcp/list-directory --input '{"path":"/"}'

If preparation fails after the site is created, the site is kept and the failure is reported as partial. Repair it idempotently (installs/activates the plugins, rotates the scoped password, refreshes the profile and re-verifies) with:

plak agent my-site
plak agent my-site --json

Migration

plak pull [--proxy-uploads]
plak push

Pull and push ship a self-contained Plak engine to the remote over SSH and run it there, so the remote needs neither internet access nor a publicly reachable backup URL. The backup itself travels over SSH. Before touching the remote database, Plak checks which archive and database tools are available (plak.sh/go diagnose reports the same set) and cancels with an actionable message when a required tool is missing. The helper and backup are removed on success and on controlled failures; if removal is impossible, Plak reports the remote path so it can be cleaned manually.

Database

plak db backup
plak db list

Snapshots

plak snapshot <site> create [--note <text>]
plak snapshot <site> list [--json]
plak snapshot <site> restore <id> [--yes]
plak snapshot <site> delete <id> [--yes]
plak snapshot <site> export <id> [--output <path>]

plak clone <source> <destination> duplicates a local site into an independent copy, reading the source database name from its real configuration (not a naming convention) and rewriting home/siteurl while preserving distinct values and local ports. Files are copied with copy-on-write when available and a portable copy otherwise. The clone starts with empty logs and drops exclusive domains and remote bindings, so it never collides with or deploys to the source's remote. A failure removes only the resources the clone created.

plak import creates a new site from a WordPress backup ZIP, tar.gz or tar (including Plak exports, Local exports, and hosting backups with a single-site WordPress tree and one recognisable SQL dump). It refuses path traversal, ambiguous or missing SQL dumps, existing destinations, and multisite backups, and rewrites home/siteurl plus the table prefix through the shared migration engine. A failed import keeps the partially created site for inspection and tells you how to remove it.

Snapshots are local recovery points of a site's files and database, stored under private/snapshots/<id> with a unique, sortable identifier. Static sites only capture files. Restoring keeps a safety snapshot of the current state first and applies the same recoverable database contract as migrations, so a partial restore is never reported as success. Export produces a portable ZIP.

Site Configuration

plak ports [--http PORT] [--https PORT] [--skip-urls] [--dry-run]
plak memory [set <value>] [--yes]
plak directive <add|update|delete|list> [site]
plak mappings <site> [add|remove|list] [domain]
plak proxy <add|list|delete>

Network Access

plak share [site]
plak lan <enable|disable|status|trust> [site]
plak tailscale <enable|disable|status>
plak wsl-hosts
plak trust
plak upgrade

SSH Remotes

plak remote list
plak remote add <name> --host <host> --user <user> [--port <port>] [--path <path>]
plak remote connect [name]
plak remote delete <name> --yes
plak remote attach <remote> <site>
plak remote detach <site>

remote add records an SSH host in ~/.ssh/config and stores the remote WordPress path as # plak-remote-path: <path> in the same block. Once remote attach binds a remote to a site, plak push and plak pull skip their interactive prompts.

Hosts

plak hosts list
plak hosts add <ip> <domain>
plak hosts delete <domain> --yes

hosts add/delete creates a timestamped backup next to the hosts file before writing. On /etc/hosts, this usually requires sudo.

SSH Keys

plak sshkey list
plak sshkey view [key-name-or-path]
plak sshkey create
plak sshkey delete

Notes

  • Interactive commands require a real terminal because gum opens TUI prompts.
  • Non-interactive list/status commands fall back to plain output for scripts and tests.
  • plak.sh is generated from main, shared/, and commands/.

WordPress core versions and stack health

Component history and selective rollback: history guide.

Multisite: see local network management for creation, subsites, network-aware clone/rename and supported boundaries. Linux database listing and browser CA trust are described in Linux compatibility.

plak add compatibility --wp-version 6.8.1
plak add development --wp-version nightly
plak core list                    # Installed versions; works offline
plak core compatibility --check   # Also query published WordPress.org version
plak core update compatibility --version 6.8.2
plak core update compatibility --version 6.8.1 --allow-downgrade
plak core update --all --version 6.8.2
plak health
plak health opcache --json

Core updates retain wp-content and wp-config.php, run the database schema update and report the effective version. Snapshot first: neither failed updates nor downgrades automatically restore the database. Nightly/development-build transitions also require --allow-downgrade because their direction may be unknown. Batch updates report each site and return failure if any site fails. Remote version checks have a 10-second timeout; an offline check still shows local versions, but updating to latest requires resolving the published release.

See stack health for OPcache tuning and the pending live HTTP/2 evaluation. Run plak reload after upgrading to deploy the web-process probe.

About

Plak CLI is the simplest way to run local WordPress sites and deploy them to any cloud — instant environments, built-in HTTPS, and seamless workflows from your terminal.

Resources

Contributing

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages