Merge remote-tracking branch 'origin/main' into pr-36-generic-agent-config

# Conflicts:
#	docs/config.html
#	docs/config.md
#	src/cli.test.ts
#	src/cli.ts
#	src/client/src/components/settings/SettingsSessiondPanel.ts
#	src/client/src/components/settings/settingsConfigDraft.test.ts
#	src/client/src/components/settings/settingsConfigDraft.ts
#	src/server/app.test.ts
#	src/server/app.ts
#	src/server/configRoutes.test.ts
#	src/server/configRoutes.ts
#	src/server/piWebPluginService.test.ts
#	src/server/piWebPluginService.ts
#	src/server/piWebStatus.test.ts
#	src/server/piWebStatus.ts
#	src/server/piWebStatusCache.ts
#	src/server/sessions/authService.test.ts
#	src/server/sessions/piSessionService.ts
#	src/server/sessions/sessionRoutes.test.ts
This commit is contained in:
Federico Jaramillo Martinez
2026-07-13 20:30:08 +02:00
289 changed files with 29164 additions and 6419 deletions
+141 -32
View File
@@ -3,10 +3,10 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Configure PI WEB — config files, paths, and session tools</title>
<title>Configure PI WEB — config files, uploads, paths, and session tools</title>
<meta
name="description"
content="Configure PI WEB config files, external path access, session daemon tools, plugins, shortcuts, uploads, and runtime environment variables."
content="Configure PI WEB config files, external path access, manual upload defaults, session daemon tools, plugins, shortcuts, and runtime environment variables."
/>
<link rel="canonical" href="https://pi-web.dev/config" />
<meta property="og:type" content="website" />
@@ -14,7 +14,7 @@
<meta property="og:title" content="Configure PI WEB" />
<meta
property="og:description"
content="Reference for PI WEB config files, path access allowlists, session daemon options, plugins, shortcuts, uploads, and environment variables."
content="Reference for PI WEB config files, path access allowlists, manual upload defaults, session daemon options, plugins, shortcuts, and environment variables."
/>
<meta property="og:url" content="https://pi-web.dev/config" />
<meta property="og:image" content="https://pi-web.dev/assets/pi-web-banner.png" />
@@ -23,7 +23,7 @@
<meta name="twitter:title" content="Configure PI WEB" />
<meta
name="twitter:description"
content="Reference for PI WEB config files, path access allowlists, session daemon options, plugins, shortcuts, uploads, and environment variables."
content="Reference for PI WEB config files, path access allowlists, manual upload defaults, session daemon options, plugins, shortcuts, and environment variables."
/>
<meta name="twitter:image" content="https://pi-web.dev/assets/pi-web-banner.png" />
<link rel="icon" type="image/svg+xml" href="assets/favicon.svg" />
@@ -80,8 +80,8 @@
<h1>Configure PI WEB where your agents work.</h1>
<p>
PI WEB configuration covers the machine-local and project-local settings you usually need: bind address,
trusted development-host settings, UI preferences, plugin enablement, file-explorer path access, upload
limits, agent runtime selection, and session-daemon tools.
trusted development-host settings, UI preferences, PI WEB plugin enablement, file-explorer path access,
manual upload defaults, upload limits, agent runtime selection, and session-daemon tools.
</p>
</div>
</section>
@@ -91,11 +91,13 @@
<aside class="toc" aria-label="Config page contents">
<strong>On this page</strong>
<a href="#files">Config files</a>
<a href="#deployment-paths">Deployment paths</a>
<a href="#precedence">Precedence and reloads</a>
<a href="#global-config">Global config</a>
<a href="#project-config">Project config</a>
<a href="#keys">Config matrix</a>
<a href="#path-access">External path access</a>
<a href="#manual-uploads">Manual uploads</a>
<a href="#agent-runtime">Agent runtime</a>
<a href="#session-tools">Session tools</a>
<a href="#completion-tools">Completion tools</a>
@@ -110,8 +112,20 @@
<li><strong>Project config:</strong> <code>&lt;project&gt;/.pi-web/config.json</code> for commit-able project settings.</li>
</ul>
<p>
Each PI WEB machine has its own config. When using Fleet/machine federation, edit a remote machine's
config by opening that machine directly or changing files on that machine.
Each PI WEB machine has its own config. When using Fleet/machine federation, Settings uses the selected
machine for config that affects work running there: agent runtime selection, session daemon tools,
PI WEB plugin enablement, external path access, and upload defaults. Gateway/browser-only settings stay local to the gateway:
keyboard shortcuts, remote machine registry/tokens, and gateway host/port/allowed-hosts. Remote servers
that do not advertise selected-machine settings support report those settings as unavailable instead of
silently falling back to the gateway.
</p>
<p>
Pi package settings are separate from PI WEB config. They live in Pi's package-manager settings on the
target machine and are managed by Pi (<code>pi install</code>, <code>pi remove</code>, <code>pi update</code>) or
<strong>Settings → Pi packages</strong>. In a federated setup, <strong>Settings → Pi packages</strong>
targets the currently selected machine. The PI WEB <code>plugins</code> config key only enables or
disables discovered PI WEB browser plugins on the machine whose config you are editing; it does not
install, remove, or update Pi packages.
</p>
<p>
If you installed services with a custom config path, rerun
@@ -121,12 +135,32 @@
</p>
</section>
<section id="deployment-paths">
<h2>Reverse-proxy deployment paths</h2>
<p>
The deployment path is not a PI WEB config-file key or environment setting. The published client is
portable: one build works at <code>/</code> and at canonical trailing-slash prefixes such as
<code>/ai/</code> or <code>/test/ai/</code>.
</p>
<p>
For a nested deployment, redirect the slashless prefix to the trailing-slash URL, strip the prefix
before forwarding to PI WEB, and proxy authenticated HTTP and WebSocket traffic through the same
location. Relative browser and PWA URLs then stay within that prefix. See the
<a href="install#reverse-proxy-prefix">reverse proxy deployment example</a> for complete Nginx
configuration.
</p>
</section>
<section id="precedence">
<h2>Precedence and reloads</h2>
<p>Runtime values are resolved in this order:</p>
<p>Machine-global runtime values are resolved in this order:</p>
<div class="code-card">
<pre><code>defaults → config file → environment overrides</code></pre>
<pre><code>defaults → global config file → environment overrides</code></pre>
</div>
<p>
Supported project-local settings are then applied for that project's workspaces. For upload defaults,
<code>&lt;project&gt;/.pi-web/config.json</code> overrides the global value.
</p>
<p>
Environment overrides include <code>PI_WEB_HOST</code>, <code>PI_WEB_PORT</code> / <code>PORT</code>,
<code>PI_WEB_ALLOWED_HOSTS</code>, <code>PI_WEB_MAX_UPLOAD_BYTES</code>, <code>PI_WEB_AGENT_COMMAND</code>,
@@ -135,11 +169,13 @@
<code>PI_WEB_SUBSESSIONS</code>.
</p>
<ul>
<li><code>host</code> / <code>port</code>: restart the web/API service or process.</li>
<li><code>maxUploadBytes</code>: restart both the web/API process and the session daemon.</li>
<li><code>agent.command</code> / <code>agent.dir</code> / <code>spawnSessions</code> / <code>subsessions</code>: restart the session daemon.</li>
<li><code>host</code> / <code>port</code>: restart the gateway web/API service or process.</li>
<li><code>maxUploadBytes</code>: restart both the web/API process and the session daemon on that machine.</li>
<li><code>agent.command</code> / <code>agent.dir</code> / <code>spawnSessions</code> / <code>subsessions</code>: restart the session daemon on that machine.</li>
<li><code>pathAccess</code>: applies on the next request; existing file views may need a browser refresh.</li>
<li><code>plugins</code>: reload the browser tab after changing plugin enablement.</li>
<li><code>uploads.defaultFolder</code>: applies to newly opened Files upload dialogs and new direct drag/drop batches after config/workspace refresh.</li>
<li><code>plugins</code>: reload the browser tab after changing PI WEB plugin enablement.</li>
<li>Pi package install/remove/update: not a PI WEB config key; after a mutation, type <code>/reload</code> in each idle PI WEB session on the target machine to refresh Pi runtime resources such as extensions, skills, prompt templates, themes, and context/system prompt files as supported by Pi. Reload the browser page separately for PI WEB browser plugin changes. A routine session daemon restart is not required.</li>
<li><code>shortcuts</code>: saved settings apply in the browser after config refresh/save.</li>
</ul>
</section>
@@ -147,9 +183,11 @@
<section id="global-config">
<h2>Global config example</h2>
<p>
<code>pi-web install</code> creates the initial file. You can also save settings from
<strong>Settings → General</strong>, <strong>Settings → Plugins</strong>, <strong>Settings → Keyboard</strong>,
and <strong>Settings → Session daemon</strong>.
<code>pi-web install</code> creates the initial file. You can also save PI WEB config settings from
<strong>Settings → General</strong>, <strong>Settings → PI WEB plugins</strong>,
<strong>Settings → Keyboard</strong>, and <strong>Settings → Session daemon</strong>. Machine-affecting
Settings fields target the selected machine; gateway host/port/allowed-hosts and keyboard shortcuts stay
local. Pi package operations live separately under <strong>Settings → Pi packages</strong>.
</p>
<div class="code-card">
<div class="copy-row">
@@ -162,6 +200,9 @@
"pathAccess": {
"allowedPaths": ["~/SDKs", "/opt/reference"]
},
"uploads": {
"defaultFolder": ".pi-web/uploads"
},
"maxUploadBytes": 67108864,
"agent": {
"command": "pi",
@@ -186,8 +227,7 @@
<h2>Project-local config</h2>
<p>
Project-local config lives at <code>&lt;project&gt;/.pi-web/config.json</code>. Use it for settings that should
follow a repository. When a project config defines <code>pathAccess</code>, PI WEB merges it after the
global path list.
follow a repository.
</p>
<div class="code-card">
<div class="copy-row">
@@ -198,13 +238,25 @@
"version": 1,
"pathAccess": {
"allowedPaths": ["~/SDKs", "/opt/reference"]
},
"uploads": {
"defaultFolder": "manual/uploads"
}
}</code></pre>
</div>
<p>
Project-local <code>pathAccess.allowedPaths</code> entries must still be host-absolute or
<code>~</code>-prefixed; relative roots are not supported. Plugins may own separate project files, such as
<code>.pi-web/tasks.json</code> for the built-in Workspace Tasks plugin.
Project-local <code>pathAccess.allowedPaths</code> entries are merged after the global list and deduplicated.
Paths must still be host-absolute or <code>~</code>-prefixed; relative roots are not supported.
</p>
<p>
Project-local <code>uploads.defaultFolder</code> overrides the global upload destination for workspaces in
that project. Current PI WEB servers include this workspace-effective value on local and federated
workspace responses; older remote servers may omit it and the browser falls back to the global/default
upload folder.
</p>
<p>
Plugins may own separate project files, such as <code>.pi-web/tasks.json</code> for the built-in Workspace
Tasks plugin.
</p>
</section>
@@ -213,7 +265,11 @@
<p>
Use this table as the quick reference for where a setting can live, which environment variable overrides
it, and whether project-local config overrides or merges with global config. Rows with JSON key
<code></code> are runtime-only environment variables, not config-file keys.
<code></code> are runtime-only environment variables, not config-file keys. <code>Global</code> means
machine-global. In Settings, selected-machine-safe global keys (<code>pathAccess</code>, <code>uploads</code>,
<code>maxUploadBytes</code>, <code>agent</code>, <code>spawnSessions</code>, <code>subsessions</code>, and <code>plugins</code>)
are edited for the selected machine; gateway host/port/allowed-hosts, keyboard shortcuts, and machine
registry/tokens stay local.
</p>
<div class="table-scroll" role="region" aria-label="PI WEB configuration matrix" tabindex="0">
<table class="config-matrix">
@@ -261,13 +317,21 @@
<td><strong>Merges:</strong> global roots first, then project roots; duplicates removed</td>
<td>Next file request; refresh existing views if needed</td>
</tr>
<tr>
<td>Manual file upload default folder</td>
<td><code>uploads.defaultFolder</code></td>
<td></td>
<td>Global + project</td>
<td><strong>Overrides:</strong> project value wins for workspaces in that project; otherwise global/default applies</td>
<td>New Upload dialogs and direct drag/drop batches after config/workspace refresh</td>
</tr>
<tr>
<td>Upload/body limit</td>
<td><code>maxUploadBytes</code></td>
<td><code>PI_WEB_MAX_UPLOAD_BYTES</code></td>
<td>Global</td>
<td>Not supported locally</td>
<td>Restart web/API and session daemon</td>
<td>Restart web/API and session daemon on that machine</td>
</tr>
<tr>
<td>Agent CLI command</td>
@@ -275,7 +339,7 @@
<td><code>PI_WEB_AGENT_COMMAND</code></td>
<td>Global/session daemon</td>
<td>Not supported locally</td>
<td>Restart session daemon; affects doctor/status/update checks</td>
<td>Restart session daemon on that machine; affects doctor/status/update checks</td>
</tr>
<tr>
<td>Agent state directory</td>
@@ -283,7 +347,7 @@
<td><code>PI_WEB_AGENT_DIR</code> (<code>PI_CODING_AGENT_DIR</code> for Pi compatibility)</td>
<td>Global/session daemon</td>
<td>Not supported locally</td>
<td>Restart session daemon; affects auth, models, settings, and sessions</td>
<td>Restart session daemon on that machine; affects auth, models, settings, and sessions</td>
</tr>
<tr>
<td>Agent can spawn sessions</td>
@@ -291,7 +355,7 @@
<td><code>PI_WEB_SPAWN_SESSIONS</code></td>
<td>Global/session daemon</td>
<td>Not supported locally</td>
<td>Restart session daemon</td>
<td>Restart session daemon on that machine</td>
</tr>
<tr>
<td>Tracked subsessions (beta)</td>
@@ -299,10 +363,10 @@
<td><code>PI_WEB_SUBSESSIONS</code></td>
<td>Global/session daemon</td>
<td>Not supported locally; also requires <code>spawnSessions</code></td>
<td>Restart session daemon</td>
<td>Restart session daemon on that machine</td>
</tr>
<tr>
<td>Plugin enablement/settings</td>
<td>PI WEB plugin enablement/settings</td>
<td><code>plugins.&lt;id&gt;.enabled</code>, <code>plugins.&lt;id&gt;.settings</code></td>
<td></td>
<td>Global</td>
@@ -437,12 +501,41 @@
<code>realpath</code>, requires roots to be existing directories, and rejects symlink escapes outside the
allowed roots.
</p>
<p>
In <strong>Settings → General</strong>, external filesystem roots are saved on the selected machine.
Gateway host, port, and allowed-hosts fields stay on the gateway config.
</p>
<div class="callout warning">
This is not a sandbox for the underlying Pi Coding Agent or your OS user. It only controls PI WEB UI/API
file exposure outside a workspace. Add only roots you trust PI WEB to list and read through the browser UI.
</div>
</section>
<section id="manual-uploads">
<h2>Manual upload defaults</h2>
<p>
The Files panel can upload files by dropping them onto the panel or by using the toolbar
<strong>Upload</strong> button. <code>uploads.defaultFolder</code> sets the workspace-effective default
destination. The built-in default is <code>.pi-web/uploads</code>; a project-local value overrides the
global value for workspaces in that project.
</p>
<p>
The value must be a non-empty workspace-relative folder. PI WEB normalizes repeated separators and
backslashes to <code>/</code>, and rejects absolute paths or <code>..</code> traversal. In the upload
dialog only, clearing the destination field uploads that batch to the workspace root.
</p>
<p>
Manual uploads use the workspace file-write path: paths stay workspace-relative, parent folder creation is
enabled by default, and overwrite is disabled by default. Browser-owned XHR progress is shown per
batch/file, and conflicts or errors stay visible in the upload progress UI.
</p>
<p>
For machine federation, Settings saves the global upload default on the selected machine. Current remote
PI WEB servers also return workspace-effective upload defaults on workspace responses; older remote
servers may omit them and the browser falls back to the global/default upload folder.
</p>
</section>
<section id="agent-runtime">
<h2>Agent runtime</h2>
<p>
@@ -480,7 +573,8 @@
intentionally using the legacy Pi-compatible <code>PI_CODING_AGENT_SESSION_DIR</code> name.
</p>
<div class="callout warning">
Restart the session daemon after changing agent settings. The web/API process can display the new config
In <strong>Settings → Session daemon</strong>, agent settings are saved on the selected machine. Restart
the session daemon on that machine after changing them. The web/API process can display the new config
immediately, and status/plugin discovery may re-read it on later requests, but active session runtime
ownership is intentionally long-lived.
</div>
@@ -503,8 +597,23 @@
to be enabled.
</p>
<p>
Tracked subsessions let an agent delegate work to child sessions, get notified when children stop
working, and inspect their transcripts. Restart the session daemon after changing this setting.
Tracked subsessions let an agent delegate work to child sessions, receive a notification when each child
stops working, and inspect their status and transcripts. Calling <code>spawn_subsession</code> returns
immediately. The parent can continue independent work while treating every child whose result it needs
as pending. Before producing work that depends on those results, the parent reaches a join point and
yields until every required child has sent a completion notice.
</p>
<p>
A completion notice wakes an idle parent. If the parent is busy, the notice queues until the current
turn ends rather than interrupting in-flight work. For multiple required children, each notice resolves
one pending child; after processing it, the parent yields again if another required child is pending.
<code>list_subsessions</code>, <code>check_subsession</code>, and <code>read_subsession</code> provide
on-demand status and transcript inspection for deliberate progress checks or recovery. Completion
notifications, rather than polling these tools, are the normal synchronization mechanism.
</p>
<p>
In <strong>Settings → Session daemon</strong>, these keys are saved on the selected machine. Restart the
session daemon on that machine after changing them.
</p>
<p>Environment override: <code>PI_WEB_SUBSESSIONS=0|1|true|false</code>.</p>
</section>
+33 -16
View File
@@ -11,10 +11,18 @@ PI WEB uses two config files:
- **Global PI WEB config:** `$PI_WEB_CONFIG`, or `$XDG_CONFIG_HOME/pi-web/config.json`, or `~/.config/pi-web/config.json`.
- **Project-local PI WEB config:** `<project>/.pi-web/config.json` for commit-able project settings.
Each PI WEB machine has its own config. When using Fleet/machine federation, edit a remote machine's config by opening that machine directly or changing files on that machine.
Each PI WEB machine has its own config. When using Fleet/machine federation, Settings uses the selected machine for config that affects work running there: agent runtime selection, session daemon tools, PI WEB plugin enablement, external path access, and upload defaults. Gateway/browser-only settings stay local to the gateway: keyboard shortcuts, remote machine registry/tokens, and gateway host/port/allowed-hosts. Remote servers that do not advertise selected-machine settings support report those settings as unavailable instead of silently falling back to the gateway.
Pi package settings are separate from PI WEB config. They live in Pi's package-manager settings on the target machine and are managed by Pi (`pi install`, `pi remove`, `pi update`) or **Settings → Pi packages**. In a federated setup, **Settings → Pi packages** targets the currently selected machine. The PI WEB `plugins` config key only enables or disables discovered PI WEB browser plugins on the machine whose config you are editing; it does not install, remove, or update Pi packages.
If you installed services with a custom config path, rerun `pi-web install --config /path/to/config.json` after changing that path or after upgrading from a version that only applied the custom path to the web service. This regenerates service files so the web/API and session daemon use the same `PI_WEB_CONFIG`.
## Reverse-proxy deployment paths
The deployment path is not a PI WEB config-file key or environment setting. The published client is portable: one build works at `/` and at canonical trailing-slash prefixes such as `/ai/` or `/test/ai/`.
For a nested deployment, redirect the slashless prefix to the trailing-slash URL, strip the prefix before forwarding to PI WEB, and proxy authenticated HTTP and WebSocket traffic through the same location. Relative browser and PWA URLs then stay within that prefix. See the [reverse proxy installation guide](https://pi-web.dev/install#reverse-proxy-prefix) for a complete Nginx example.
## Precedence and reloads
Machine-global runtime values are resolved as:
@@ -29,12 +37,13 @@ Environment overrides include `PI_WEB_HOST`, `PI_WEB_PORT` / `PORT`, `PI_WEB_ALL
Process restarts depend on the key:
- `host` / `port`: restart the web/API service or process.
- `maxUploadBytes`: restart both the web/API process and the session daemon.
- `agent.command` / `agent.dir` / `spawnSessions` / `subsessions`: restart the session daemon.
- `host` / `port`: restart the gateway web/API service or process.
- `maxUploadBytes`: restart both the web/API process and the session daemon on that machine.
- `agent.command` / `agent.dir` / `spawnSessions` / `subsessions`: restart the session daemon on that machine.
- `pathAccess`: applies on the next request; existing file views may need a browser refresh.
- `uploads.defaultFolder`: applies to newly opened Files upload dialogs and new direct drag/drop batches after config/workspace refresh.
- `plugins`: reload the browser tab after changing plugin enablement.
- `plugins`: reload the browser tab after changing PI WEB plugin enablement.
- Pi package install/remove/update: not a PI WEB config key; after a mutation, type `/reload` in each idle PI WEB session on the target machine to refresh Pi runtime resources such as extensions, skills, prompt templates, themes, and context/system prompt files as supported by Pi. Reload the browser page separately for PI WEB browser plugin changes. A routine session daemon restart is not required.
- `shortcuts`: saved settings apply in the browser after config refresh/save.
## Global config example
@@ -92,7 +101,7 @@ Plugins may own separate project files, such as `.pi-web/tasks.json` for the bui
## Configuration matrix
Rows with JSON key `—` are runtime-only environment variables, not config-file keys.
Rows with JSON key `—` are runtime-only environment variables, not config-file keys. `Global` means machine-global. In Settings, selected-machine-safe global keys (`pathAccess`, `uploads`, `maxUploadBytes`, `agent`, `spawnSessions`, `subsessions`, and `plugins`) are edited for the selected machine; gateway host/port/allowed-hosts, keyboard shortcuts, and machine registry/tokens stay local.
| Config | JSON key | Env var | Scope | Project-local behavior | Applies / restart |
| --- | --- | --- | --- | --- | --- |
@@ -102,11 +111,11 @@ Rows with JSON key `—` are runtime-only environment variables, not config-file
| Dev-server allowed hosts | `allowedHosts` | `PI_WEB_ALLOWED_HOSTS` | Global | Not supported locally | Restart dev web/UI |
| External filesystem roots | `pathAccess.allowedPaths` | — | Global + project | **Merges**: global roots first, then project roots; duplicates removed | Next file request; refresh existing views if needed |
| Manual file upload default folder | `uploads.defaultFolder` | — | Global + project | **Overrides**: project value wins for workspaces in that project; otherwise global/default applies | New Upload dialogs and direct drag/drop batches after config/workspace refresh |
| Upload/body limit | `maxUploadBytes` | `PI_WEB_MAX_UPLOAD_BYTES` | Global | Not supported locally | Restart web/API and session daemon |
| Agent CLI command | `agent.command` | `PI_WEB_AGENT_COMMAND` | Global/session daemon | Not supported locally | Restart session daemon; affects doctor/status/update checks |
| Agent state directory | `agent.dir` | `PI_WEB_AGENT_DIR` (`PI_CODING_AGENT_DIR` for Pi compatibility) | Global/session daemon | Not supported locally | Restart session daemon; affects auth, models, settings, and sessions |
| Agent can spawn sessions | `spawnSessions` | `PI_WEB_SPAWN_SESSIONS` | Global/session daemon | Not supported locally | Restart session daemon |
| Tracked subsessions (beta) | `subsessions` | `PI_WEB_SUBSESSIONS` | Global/session daemon | Not supported locally; also requires `spawnSessions` | Restart session daemon |
| Upload/body limit | `maxUploadBytes` | `PI_WEB_MAX_UPLOAD_BYTES` | Global | Not supported locally | Restart web/API and session daemon on that machine |
| Agent CLI command | `agent.command` | `PI_WEB_AGENT_COMMAND` | Global/session daemon | Not supported locally | Restart session daemon on that machine; affects doctor/status/update checks |
| Agent state directory | `agent.dir` | `PI_WEB_AGENT_DIR` (`PI_CODING_AGENT_DIR` for Pi compatibility) | Global/session daemon | Not supported locally | Restart session daemon on that machine; affects auth, models, settings, and sessions |
| Agent can spawn sessions | `spawnSessions` | `PI_WEB_SPAWN_SESSIONS` | Global/session daemon | Not supported locally | Restart session daemon on that machine |
| Tracked subsessions (beta) | `subsessions` | `PI_WEB_SUBSESSIONS` | Global/session daemon | Not supported locally; also requires `spawnSessions` | Restart session daemon on that machine |
| Plugin enablement/settings | `plugins.<id>.enabled`, `plugins.<id>.settings` | — | Global | Not core local config; plugins may read their own project files | Reload browser tab |
| Keyboard shortcuts | `shortcuts.<actionId>` | — | Global | Not supported locally | Applies after settings save/config refresh |
| Project config version | `version` | — | Project | Project-local only; must be `1` when present | Next project-config read |
@@ -139,6 +148,8 @@ Accepted root forms:
When an absolute request is served, PI WEB expands `~`, canonicalizes the configured roots with `realpath`, requires roots to be existing directories, and rejects symlink escapes outside the allowed roots.
In **Settings → General**, external filesystem roots are saved on the selected machine. Gateway host, port, and allowed-hosts fields stay on the gateway config.
This is not a sandbox for the underlying Pi Coding Agent or your OS user. It only controls PI WEB UI/API file exposure outside a workspace.
### Manual upload defaults
@@ -162,9 +173,9 @@ The value must be a non-empty workspace-relative folder. PI WEB normalizes repea
Manual uploads use the workspace file-write path: paths stay workspace-relative, parent folder creation is enabled by default, and overwrite is disabled by default. Direct drag/drop always keeps `overwrite` off; the review dialog lets you explicitly enable overwrite when needed. Browser-owned XHR progress is shown per batch/file, conflicts and errors stay visible in the upload progress UI, and the final file-write response is the source of truth.
For machine federation, current remote PI WEB servers return `workspace.effectiveConfig.uploads.defaultFolder` on the existing workspace-list response. Older remote servers can omit that optional field without breaking clients; the Files panel falls back to the global/default upload folder.
For machine federation, Settings saves the global upload default on the selected machine. Current remote PI WEB servers also return `workspace.effectiveConfig.uploads.defaultFolder` on the existing workspace-list response. Older remote servers can omit that optional field without breaking clients; the Files panel falls back to the global/default upload folder.
The per-request size limit is still controlled by `maxUploadBytes` / `PI_WEB_MAX_UPLOAD_BYTES`.
The per-request size limit is still controlled by `maxUploadBytes` / `PI_WEB_MAX_UPLOAD_BYTES` on the machine serving the upload.
### Agent runtime selection
@@ -187,7 +198,7 @@ Environment variables take precedence over the config file. `PI_WEB_AGENT_COMMAN
Session directory overrides are environment-only; use `PI_WEB_AGENT_SESSION_DIR` unless you are intentionally using the legacy Pi-compatible `PI_CODING_AGENT_SESSION_DIR` name.
Restart the session daemon after changing agent settings. The web/API process can display the new config immediately, and status/plugin discovery may re-read it on later requests, but active session runtime ownership is intentionally long-lived.
In **Settings → Session daemon**, agent settings are saved on the selected machine. Restart the session daemon on that machine after changing them. The web/API process can display the new config immediately, and status/plugin discovery may re-read it on later requests, but active session runtime ownership is intentionally long-lived.
### Session daemon tools
@@ -195,11 +206,17 @@ Restart the session daemon after changing agent settings. The web/API process ca
`subsessions` is beta and controls whether agents receive the tracked-subsession tools: `spawn_subsession`, `list_subsessions`, `check_subsession`, and `read_subsession`. It defaults to `false` and also requires `spawnSessions` to be enabled.
Tracked subsessions let an agent delegate work to child sessions, get notified when children stop working, and inspect their transcripts.
Tracked subsessions let an agent delegate work to child sessions, receive a notification when each child stops working, and inspect their status and transcripts. Calling `spawn_subsession` returns immediately. The parent can continue independent work while treating every child whose result it needs as pending. Before producing work that depends on those results, the parent reaches a join point and yields until every required child has sent a completion notice.
A completion notice wakes an idle parent. If the parent is busy, the notice queues until the current turn ends rather than interrupting in-flight work. For multiple required children, each notice resolves one pending child; after processing it, the parent yields again if another required child is pending. `list_subsessions`, `check_subsession`, and `read_subsession` provide on-demand status and transcript inspection for deliberate progress checks or recovery. Completion notifications, rather than polling these tools, are the normal synchronization mechanism.
In **Settings → Session daemon**, these keys are saved on the selected machine. Restart the session daemon on that machine after changing them.
### Plugin config
Plugins are enabled by default. Set `plugins.<id>.enabled` to `false` to remove a plugin from `/pi-web-plugins/manifest.json` before the browser imports it.
The `plugins` key is only for PI WEB browser plugin enablement/settings on the machine whose config you are editing. It does not install, remove, or update Pi packages; use **Settings → Pi packages** or Pi's package manager for package operations. In a federated setup, **Settings → PI WEB plugins** and **Settings → Pi packages** both target the currently selected machine, and each panel labels where changes will be saved or run.
Plugins are enabled by default. Set `plugins.<id>.enabled` to `false` to remove a plugin from that machine's `/pi-web-plugins/manifest.json` before the browser imports it. Settings lists discovered plugins from the selected machine, including disabled entries exposed by that machine.
```json
{
+12 -8
View File
@@ -131,8 +131,9 @@
<h2>Tools are failing, node is not found, or Pi cannot find commands</h2>
<p>
The shell environment needs to be set up so login shells have the required PATH entries for PI WEB, Pi,
and any tools your agents need. PI WEB services run commands through a non-interactive login shell, so
an interactive terminal can work while services fail.
and any tools your agents need. PI WEB services run commands through a non-interactive login shell owned
by systemd or launchd, so an interactive terminal—or even a caller-invoked login shell—can work while the
native service fails.
</p>
<div class="code-card">
<div class="copy-row">
@@ -156,14 +157,17 @@
<article id="doctor-fails" class="faq-item">
<h2>What does <code>pi-web doctor</code> check?</h2>
<p>
It checks whether the service shell and native service environment can find Node 22+, npm, Pi, and the Pi
Web binaries. It also prints installed and running PI WEB versions when available, reports optional ripgrep
availability for faster all-file <code>@</code>-mention suggestions, uses a bounded filesystem fallback when
ripgrep is unavailable, and reports user service lingering when relevant for server-style installs.
It keeps two kinds of checks separate. General login-shell readiness covers Node 22+, npm, Pi, and optional
ripgrep. Native-service diagnostics validate only the exact prerequisites of the selected service plan in
the real systemd user-manager or launchd <code>gui/&lt;uid&gt;</code> context. Development installs follow their
installed checkout plan; production checks are clearly labelled prospective when the installed executable
strategy cannot be reconstructed safely.
</p>
<p>
If something works in your terminal but fails in doctor, treat that as a login-shell PATH mismatch and
move the setup earlier in your shell startup chain.
Missing plan requirements fail doctor and include login-file guidance. Manager, timeout, malformed-output,
and cleanup failures are reported as probe infrastructure problems rather than being mislabeled as PATH
drift. On unsupported/manual-only platforms, native-service drift checks are skipped. Doctor also prints
installed and running PI WEB versions and reports systemd lingering when relevant.
</p>
</article>
+3 -3
View File
@@ -138,8 +138,8 @@
# laptop, phone, tablet — same live sessions
<span class="prompt">$</span> pi-web doctor
✓ login shell can find node >= 22
✓ native service shell can find pi
caller login shell can find node >= 22
✓ native-service plan requirements pass in manager context
✓ ready for persistent agent work</code></pre>
</aside>
</div>
@@ -251,7 +251,7 @@
<p>
Your device is replaceable. The sessions are not. Move between laptop, phone, tablet, and desktop
without moving the development environment. Under the hood, PI WEB coordinates the running sessions,
files, terminals, and remote machines like a browser-based control plane.
files, terminals, Pi package management, and remote machines like a browser-based control plane.
</p>
</article>
<article class="card">
+83 -4
View File
@@ -95,6 +95,7 @@
<a href="#pi-package">Install through Pi</a>
<a href="#manual-run">WSL / manual run</a>
<a href="#remote-access">Remote access</a>
<a href="#reverse-proxy-prefix">Reverse proxy prefixes</a>
<a href="#federated-machines">Federated machines</a>
<a href="#manage-services">Manage services</a>
<a href="#configure">Configure</a>
@@ -112,8 +113,11 @@
</ul>
<div class="callout warning">
<strong>Important PATH detail:</strong>
PI WEB services run through your login shell with <code>-lc</code>. Setup that only lives in interactive shell
files or prompt hooks may not be visible to services. Run <code>pi-web doctor</code> after installing.
PI WEB services run through a non-interactive login shell with <code>-lc</code>. Setup that only lives in
interactive shell files or prompt hooks may not be visible to the systemd or launchd manager. The installer
probes the safely verifiable requirements of the exact candidate plan in that manager context before changing
config or replacing services. Arbitrary configured command overrides are preserved but not executed by
preflight; run <code>pi-web doctor</code> later to repeat plan-specific diagnostics.
</div>
</section>
@@ -134,12 +138,13 @@
<span class="prompt">$</span> pi-web doctor</code></pre>
</div>
<p>Then open <a href="http://127.0.0.1:8504">http://127.0.0.1:8504</a>.</p>
<p>If preflight fails, no config or existing services are changed. Follow the detected shell guidance: zsh services read <code>~/.zprofile</code>, not interactive-only <code>~/.zshrc</code>; bash uses <code>~/.bash_profile</code> or <code>~/.profile</code>.</p>
<p>On Linux servers, also consider <code>sudo loginctl enable-linger "$USER"</code> so user services survive logout/reboot.</p>
</section>
<section id="one-line">
<h2>One-line install</h2>
<p>If you prefer a curl pipe, use the repository installer:</p>
<p>If you prefer a curl pipe for the native user-service install, use the repository installer. This path still requires Node.js, npm, and Pi Coding Agent on the host.</p>
<div class="code-card">
<div class="copy-row">
<strong>One-liner</strong>
@@ -220,6 +225,79 @@
</div>
</section>
<section id="reverse-proxy-prefix">
<h2>Reverse proxy root and path-prefix deployments</h2>
<p>
The published PI WEB client is deployment-independent. The same package works at the origin root
(<code>/</code>) or at canonical nested prefixes such as <code>/ai/</code> and <code>/test/ai/</code>;
no prefix-specific rebuild or PI WEB configuration is needed.
</p>
<p>
For a root deployment, proxy <code>/</code> directly to <code>http://127.0.0.1:8504</code> without
rewriting the path. For a nested deployment:
</p>
<ol>
<li>Redirect the slashless prefix, such as <code>/ai</code>, to <code>/ai/</code>. The browser uses the trailing-slash document URL as the application base.</li>
<li>Strip the prefix before forwarding. PI WEB continues to serve root paths on its localhost listener.</li>
<li>Apply authentication to the whole served <code>/ai/</code> application and preserve required authentication headers and cookies.</li>
<li>Forward WebSocket upgrades through the same location as HTTP, API, image, PWA, and plugin traffic.</li>
</ol>
<div class="code-card">
<div class="copy-row">
<strong>Nginx path-prefix proxy</strong>
<button class="copy-button" data-copy="#nginx-prefix-proxy">Copy</button>
</div>
<pre id="nginx-prefix-proxy"><code><span class="comment"># http context</span>
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
server_name pi.example.com;
ssl_certificate /etc/letsencrypt/live/pi.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pi.example.com/privkey.pem;
auth_basic "PI WEB";
auth_basic_user_file /etc/nginx/pi-web.htpasswd;
location = /ai {
return 308 /ai/$is_args$args;
}
location ^~ /ai/ {
<span class="comment"># The trailing slash strips /ai/ before forwarding.</span>
proxy_pass http://127.0.0.1:8504/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Authorization $http_authorization;
proxy_set_header Cookie $http_cookie;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 1h;
}
}</code></pre>
</div>
<p>
Use the same pattern for <code>/test/ai/</code> by changing both Nginx locations. If your proxy uses
bearer tokens, SSO, or another authentication mechanism, keep that policy on the prefixed application
location and continue forwarding the headers or cookies it requires; the slashless redirect serves no
PI WEB content. Do not create unprotected exceptions for <code>/api/</code> or
<code>/pi-web-plugins/</code>.
</p>
<p>
Once the proxy follows this contract, relative client assets, images, PWA assets, API calls, local and
federated plugins, and WebSocket URLs stay inside the prefix. Installed PWA <code>start_url</code> and
scope stay inside it as well.
</p>
</section>
<section id="federated-machines">
<h2>Federated machines</h2>
<p>
@@ -281,7 +359,8 @@
</div>
<p>
Use <strong>Settings → General</strong> for host, port, and external filesystem roots; <strong>Settings → Session daemon</strong>
for agent-spawn tools; <strong>Settings → Plugins</strong> for plugin enablement; and <strong>Settings → Keyboard</strong>
for agent-spawn tools; <strong>Settings → Pi packages</strong> for Pi package install/remove/update;
<strong>Settings → PI WEB plugins</strong> for browser plugin enablement; and <strong>Settings → Keyboard</strong>
for shortcut overrides.
</p>
<div class="callout">
+12 -8
View File
@@ -6,7 +6,7 @@
<title>PI WEB fleet — remote Pi web UI machines</title>
<meta
name="description"
content="Connect trusted PI WEB runtimes through machine federation so one web UI can supervise local and remote projects, sessions, files, git state, terminals, and plugins."
content="Connect trusted PI WEB runtimes through machine federation so one web UI can supervise local and remote projects, sessions, files, git state, terminals, Pi packages, and plugins."
/>
<link rel="canonical" href="https://pi-web.dev/machines" />
<meta property="og:type" content="website" />
@@ -81,7 +81,7 @@
<p>
Most PI WEB setups only need one runtime. When you do have more than one, machine federation lets the PI WEB
instance you opened act as a gateway to other trusted runtimes while each machine keeps its own repositories,
credentials, sessions, and plugins.
credentials, sessions, Pi package settings, and plugins.
</p>
</div>
</section>
@@ -111,7 +111,7 @@
<p>
After registration, the browser keeps talking to the current PI WEB origin. The gateway contacts the
selected remote PI WEB server and routes that machine's projects, workspaces, sessions, files, git state,
activity, and terminals to the browser UI.
activity, terminals, and Pi package-management operations to the browser UI.
</p>
<div class="code-card">
<div class="copy-row">
@@ -125,7 +125,7 @@ PI WEB gateway you opened
├─ [ Remote PI WEB runtime A ]
│ ↓ selected machine
│ projects, workspaces, sessions, terminals, plugins
│ projects, workspaces, sessions, terminals, Pi packages, plugins
└─ [ Remote PI WEB runtime B ]</code></pre>
</div>
@@ -151,7 +151,7 @@ PI WEB gateway you opened
<article class="card">
<div class="card-icon"></div>
<h3>Local ownership</h3>
<p>Each target machine keeps its own Pi auth, sessions, worktrees, terminal state, and plugins.</p>
<p>Each target machine keeps its own Pi auth, sessions, worktrees, terminal state, Pi package settings, and plugins.</p>
</article>
</div>
</section>
@@ -174,7 +174,9 @@ PI WEB gateway you opened
<p>
Prefer a private path such as NetBird, Tailscale, WireGuard, private LAN, SSH tunnel, or an authenticated reverse
proxy. If the remote is behind a path prefix, include that prefix in the machine URL, for example
<code>https://devbox.example.test/pi-web</code>.
<code>https://devbox.example.test/pi-web</code>. The machine registry normalizes the trailing slash; when
opening that deployment directly in a browser, use its canonical <code>https://devbox.example.test/pi-web/</code>
URL and configure the proxy to redirect the slashless form.
</p>
<div class="callout danger">
Do not expose PI WEB directly to the public internet. Register machines only over trusted network paths
@@ -213,6 +215,7 @@ PI WEB gateway you opened
<li>Pi sessions, transcripts, prompts, model controls, and commands.</li>
<li>Activity indicators and realtime updates.</li>
<li>Terminals and terminal command runs.</li>
<li>Pi package listing, install, remove, and update from <strong>Settings → Pi packages</strong> when supported by the target PI WEB runtime.</li>
<li>Remote plugins from the selected machine.</li>
</ul>
</section>
@@ -220,8 +223,9 @@ PI WEB gateway you opened
<section id="auth-credentials">
<h2>Credentials stay on the target machine</h2>
<p>
Model-provider credentials, Pi configuration, OAuth state, repositories, and active session runtimes stay
on the selected target machine. The gateway does not copy them into its own Pi configuration.
Model-provider credentials, Pi configuration, Pi package-manager settings, OAuth state, repositories, and
active session runtimes stay on the selected target machine. The gateway does not copy them into its own
Pi configuration.
</p>
<ul>
<li>API-key provider configuration can be proxied through the gateway.</li>
+74 -15
View File
@@ -90,10 +90,11 @@
<aside class="toc" aria-label="Plugin page contents">
<strong>On this page</strong>
<a href="#extend">What can be extended</a>
<a href="#packages-vs-plugins">Pi packages vs PI WEB plugins</a>
<a href="#ask-ai">What to ask AI to build</a>
<a href="#example">Canonical example</a>
<a href="#built-in-plugins">Built-in plugins</a>
<a href="#manage-plugins">Manage plugins</a>
<a href="#manage-plugins">Manage PI WEB plugins</a>
<a href="#remote-machine-plugins">Remote machine plugins</a>
<a href="#production">Production usage</a>
<a href="#agent-docs">AI-friendly docs</a>
@@ -125,6 +126,44 @@
</div>
</section>
<section id="packages-vs-plugins">
<h2>Pi packages vs PI WEB plugins</h2>
<p>
<strong>Pi packages</strong> are packages managed by Pi (<code>pi install</code>, <code>pi remove</code>,
<code>pi update</code>). A Pi package can provide extensions, skills, prompt templates, themes,
context/system prompt files, and/or PI WEB browser plugins. Many Pi packages do not include a PI WEB plugin.
</p>
<p>
<strong>PI WEB plugins</strong> are browser-side UI modules discovered from bundled, local, dev, and
installed Pi-package sources. Enabling or disabling a PI WEB plugin is a PI WEB config task; installing,
removing, or updating a Pi package is a Pi package-manager task.
</p>
<p>
Use <strong>Settings → Pi packages</strong> to view configured Pi packages or install/remove/update a
package. Enter only the package source, such as <code>npm:@scope/package</code>, a git/URL source, or a
local path. PI WEB uses Pi's default package location, equivalent to <code>pi install &lt;source&gt;</code>,
and does not ask for an install location.
</p>
<p>
When machine federation is enabled, <strong>Settings → Pi packages</strong> targets the currently selected
machine. The panel labels whether changes will run on the local/gateway machine or on a selected remote
PI WEB machine. If an older or unavailable remote PI WEB server does not expose package-management routes,
PI WEB reports the package management operation as unsupported or unavailable instead of silently falling
back to the gateway.
</p>
<p>
Use <strong>Settings → PI WEB plugins</strong> to enable or disable discovered PI WEB browser plugins
before the browser imports them. In a federated setup, this plugin enablement surface targets the
currently selected machine and labels where changes are saved. If an older or unavailable remote PI WEB
server does not advertise selected-machine settings support, PI WEB reports the plugin settings as
unsupported or unavailable instead of silently falling back to the gateway. After installing, removing, or
updating a Pi package, type <code>/reload</code> in each idle PI WEB session on the target machine to
refresh Pi runtime resources such as extensions, skills, prompt templates, themes, and context/system
prompt files as supported by Pi. Reload the browser page separately for newly discovered or changed
PI WEB browser plugins. A routine session daemon restart is not required.
</p>
</section>
<section id="ask-ai">
<h2>What to ask AI to build</h2>
<p>
@@ -204,18 +243,21 @@ After editing, check the manifest endpoint and browser-console failure cases.</c
plugins appear in <code>/pi-web-plugins/manifest.json</code>.
</p>
<p>
Built-in plugins can be managed from <strong>Settings → Plugins</strong> or with the top-level
Built-in plugins can be managed from <strong>Settings → PI WEB plugins</strong> or with the top-level
<code>plugins</code> config key.
</p>
<h3>Updates</h3>
<p>
<strong>Updates</strong> adds a conditional <strong>Updates</strong> workspace tab with PI WEB update,
restart, and installed-service guidance. It is built into PI WEB, enabled by default, and uses the
selected machine's plugin copy when machine federation is active.
restart, and installed-service guidance, plus a <strong>Check for PI WEB Updates</strong> action. It is
built into PI WEB, enabled by default, and uses the selected machine's plugin copy when machine
federation is active.
</p>
<ul>
<li>Plugin id: <code>updates</code></li>
<li>Selected-machine status refreshes every 15 minutes while a browser tab is connected.</li>
<li>Automatic npm release lookups are cached for six hours; the action bypasses the caches and checks immediately.</li>
</ul>
<div class="code-card">
<div class="copy-row">
@@ -258,11 +300,11 @@ After editing, check the manifest endpoint and browser-console failure cases.</c
"version": 1,
"tasks": [
{
"id": "docker.start",
"title": "Start Docker",
"group": "Docker",
"description": "Start the local Docker Compose environment.",
"command": "./docker/scripts/docker-compose-dev up -d"
"id": "app.start",
"title": "Start app",
"group": "Development",
"description": "Start the local development server.",
"command": "npm run dev"
},
{
"id": "db.reset",
@@ -285,12 +327,20 @@ After editing, check the manifest endpoint and browser-console failure cases.</c
</section>
<section id="manage-plugins">
<h2>Manage plugins</h2>
<h2>Manage PI WEB plugins</h2>
<p>
Open <strong>Settings → Plugins</strong> to review discovered bundled, local, dev, and Pi package plugins
for the PI WEB gateway you opened. PI WEB can disable any discovered plugin before the browser imports
it. Core app contributions such as the command palette, base workspace tools, and themes are not managed
through this plugin list.
Open <strong>Settings → PI WEB plugins</strong> to review discovered bundled, local, dev, and Pi package
plugins for the selected PI WEB machine. When the local machine is selected, this is the gateway plugin
list; when a remote machine is selected, the list comes from that remote PI WEB server and includes
disabled discovered plugins it exposes. PI WEB can disable any discovered selected-machine plugin before
the browser imports it. Core app contributions such as the command palette, base workspace tools, and
themes are not managed through this plugin list.
</p>
<p>
This surface is only for PI WEB plugin enablement. To install, remove, or update Pi packages that may
provide plugins or other Pi resources, use <strong>Settings → Pi packages</strong>. In a federated setup,
both the Pi packages panel and the PI WEB plugins panel target the selected machine; plugin enablement
still writes the PI WEB <code>plugins</code> config key rather than changing Pi package-manager settings.
</p>
<div class="code-card">
<div class="copy-row">
@@ -336,13 +386,22 @@ After editing, check the manifest endpoint and browser-console failure cases.</c
</ul>
<p>
Remote plugin enablement is controlled by the remote machine's PI WEB plugin config. To edit or disable
one, open that machine directly or update its config file.
one, select that machine and use <strong>Settings → PI WEB plugins</strong> when the remote server exposes
selected-machine settings, or open that machine directly/update its config file.
</p>
<p>
Plugin package metadata can set <code>machineSpecific: true</code>. Use it for plugins like Updates whose
UI should come from the selected PI WEB instance; on remote machines, the gateway copy is hidden unless
the remote machine exposes its own copy.
</p>
<p>
Current PI WEB manifests publish leading application-root module references. The browser keeps them
inside the current application base, so local and federated plugins follow root or nested reverse-proxy
deployments without a prefix-specific build while remaining compatible with existing gateways.
Federated gateways also accept manifest-relative references such as
<code>./&lt;plugin-id&gt;/plugin.js</code> and legacy plugin-root-relative references such as
<code>nested/plugin.js</code> from remote machines.
</p>
<p>
For portable plugin assets, prefer URLs relative to the plugin module, such as
<code>new URL("./asset.json", import.meta.url)</code>. If a remote plugin constructs absolute asset URLs,
+46 -18
View File
@@ -13,6 +13,18 @@ Plugins can currently:
They do **not** run in the session daemon, do not get a server-side hook API, and are not sandboxed.
## Pi packages vs PI WEB plugins
**Pi packages** are packages managed by Pi (`pi install`, `pi remove`, `pi update`). A Pi package can provide extensions, skills, prompt templates, themes, context/system prompt files, and/or PI WEB browser plugins. Many Pi packages do not include a PI WEB plugin.
**PI WEB plugins** are browser-side PI WEB UI modules discovered from bundled, local, dev, and installed Pi-package sources. Enabling or disabling a PI WEB plugin is a PI WEB config task; installing, removing, or updating a Pi package is a Pi package-manager task.
Use **Settings → Pi packages** to view configured Pi packages or install/remove/update a package. Enter only the package source, such as `npm:@scope/package`, a git/URL source, or a local path. PI WEB uses Pi's default package location, equivalent to `pi install <source>`, and does not ask for an install location.
When machine federation is enabled, **Settings → Pi packages** targets the currently selected machine. The panel labels whether changes will run on the local/gateway machine or on a selected remote PI WEB machine. If an older or unavailable remote PI WEB server does not expose package-management routes, PI WEB reports the package management operation as unsupported or unavailable instead of silently falling back to the gateway.
Use **Settings → PI WEB plugins** to enable or disable discovered PI WEB browser plugins before the browser imports them. In a federated setup, this plugin enablement surface targets the currently selected machine and labels where changes are saved. If an older or unavailable remote PI WEB server does not advertise selected-machine settings support, PI WEB reports the plugin settings as unsupported or unavailable instead of silently falling back to the gateway. After installing, removing, or updating a Pi package, type `/reload` in each idle PI WEB session on the target machine to refresh Pi runtime resources such as extensions, skills, prompt templates, themes, and context/system prompt files as supported by Pi. Reload the browser page separately for newly discovered or changed PI WEB browser plugins. A routine session daemon restart is not required.
## Trust model
Plugins run as JavaScript in the browser app. Treat them as trusted code:
@@ -140,7 +152,7 @@ When [machine federation](https://pi-web.dev/machines) is enabled, PI WEB also l
- remote theme contributions are ignored for now because themes are app-wide;
- mixed PI WEB versions across federated machines are best-effort and not guaranteed compatible.
Remote plugin enablement is controlled by the remote machine's PI WEB plugin config. To edit or disable a remote machine plugin, open that machine directly or update its config file.
Remote plugin enablement is controlled by the remote machine's PI WEB plugin config. To edit or disable a remote machine plugin, select that machine and use **Settings → PI WEB plugins** when the remote server exposes selected-machine settings, or open that machine directly/update its config file.
Plugin package metadata may set `machineSpecific: true` when the plugin's meaning is tied to the selected PI WEB machine:
@@ -155,9 +167,11 @@ const url = new URL("./asset.json", import.meta.url);
If a remote plugin constructs absolute asset URLs, it should use the `pluginId` from `activate()` because PI WEB gives remote plugins a gateway-scoped runtime id. Hard-coded `/pi-web-plugins/<original-id>/...` URLs may point at the gateway instead of the remote machine.
## Manage plugins
## Manage PI WEB plugins
Open **Settings → Plugins** to review discovered bundled, local, dev, and Pi package plugins for the PI WEB gateway you opened. PI WEB can disable any discovered gateway plugin before the browser imports it. Core app contributions such as the built-in command palette, base workspace tools, and themes are not managed through this plugin list.
Open **Settings → PI WEB plugins** to review discovered bundled, local, dev, and Pi package plugins for the selected PI WEB machine. When the local machine is selected, this is the gateway plugin list; when a remote machine is selected, the list comes from that remote PI WEB server and includes disabled discovered plugins it exposes. PI WEB can disable any discovered selected-machine plugin before the browser imports it. Core app contributions such as the built-in command palette, base workspace tools, and themes are not managed through this plugin list.
This surface is only for PI WEB plugin enablement. To install, remove, or update Pi packages that may provide plugins or other Pi resources, use **Settings → Pi packages**. In a federated setup, both the Pi packages panel and the PI WEB plugins panel target the selected machine; plugin enablement still writes the PI WEB `plugins` config key rather than changing Pi package-manager settings.
Plugin preferences are stored under the top-level `plugins` config key in the PI WEB config file:
@@ -183,14 +197,16 @@ After changing plugin enablement, reload the PI WEB browser tab. Already-loaded
PI WEB ships core, discoverable plugins in the main `@jmfederico/pi-web` npm package. No separate `pi install` step is required: update PI WEB, reload the browser tab, and the bundled plugins appear in `/pi-web-plugins/manifest.json`.
Built-in plugins can be managed from **Settings → Plugins** or with the top-level `plugins` config key.
Built-in plugins can be managed from **Settings → PI WEB plugins** or with the top-level `plugins` config key.
### Updates
**Plugin id:** `updates`
**What it does:** adds a conditional **Updates** workspace tab with PI WEB update, restart, and installed-service guidance.
**What it does:** adds a conditional **Updates** workspace tab with PI WEB update, restart, and installed-service guidance, plus a **Check for PI WEB Updates** action for the selected machine.
Updates is enabled by default. It declares `machineSpecific: true` so the gateway Updates tab only appears for the local machine; while a remote machine is selected, that remote machine's Updates plugin is used if available. To hide it, disable `updates` in **Settings → Plugins** or set:
While a browser tab is connected, PI WEB refreshes the selected machine's status every 15 minutes. npm release lookups are cached on that machine for six hours, so the automatic refresh normally contacts npm at most once in that window. Run **Check for PI WEB Updates** from the action palette to bypass both caches and check immediately. Operator settings that skip remote version checks, such as `PI_WEB_OFFLINE`, are still respected.
Updates is enabled by default. It declares `machineSpecific: true` so the gateway Updates tab and action only appear for the local machine; while a remote machine is selected, that remote machine's Updates plugin is used if available. To hide it, disable `updates` in **Settings → PI WEB plugins** or set:
```json
{
@@ -206,7 +222,7 @@ Updates is enabled by default. It declares `machineSpecific: true` so the gatewa
**Config file:** `.pi-web/tasks.json`
**What it does:** adds a **Tasks** workspace tab for running configured shell commands in dedicated PI WEB terminals.
Workspace Tasks is enabled by default. To hide it, disable `workspace-tasks` in **Settings → Plugins** or set:
Workspace Tasks is enabled by default. To hide it, disable `workspace-tasks` in **Settings → PI WEB plugins** or set:
```json
{
@@ -223,11 +239,11 @@ Configure workspace tasks in `.pi-web/tasks.json`:
"version": 1,
"tasks": [
{
"id": "docker.start",
"title": "Start Docker",
"group": "Docker",
"description": "Start the local Docker Compose environment.",
"command": "./docker/scripts/docker-compose-dev up -d"
"id": "app.start",
"title": "Start app",
"group": "Development",
"description": "Start the local development server.",
"command": "npm run dev"
},
{
"id": "db.reset",
@@ -273,7 +289,7 @@ PI WEB builds the gateway `/pi-web-plugins/manifest.json` from these sources:
Entries may be real directories or symlinks. This is the recommended development workflow.
3. Installed Pi packages that expose PI WEB plugin metadata. Pi packages may be user or project scoped.
3. Installed Pi packages that expose PI WEB plugin metadata. Pi packages may be user or project scoped. Installing/removing/updating Pi packages is done from **Settings → Pi packages** (or Pi's package manager), not from the PI WEB plugin enable/disable list.
Remote machines expose their own manifests through the gateway at `/api/machines/<machine-id>/pi-web-plugins/manifest.json`. Those plugin modules are rewritten to gateway-scoped asset URLs and registered under machine-scoped runtime ids so duplicate plugin ids on different machines do not collide.
@@ -309,7 +325,7 @@ Rules:
### Manifest and assets
The manifest contains each discovered plugin module:
The manifest contains each discovered plugin module. Current PI WEB releases emit `module` as a leading application-root reference:
```json
{
@@ -325,15 +341,25 @@ The manifest contains each discovered plugin module:
}
```
The browser maps leading application-root references into the current application base, so the same manifest works at the origin root or under a reverse-proxy path prefix. Keeping this output format also lets gateways from existing PI WEB releases consume plugins from an upgraded remote machine. For compatibility, federated gateways additionally accept explicit manifest-relative references such as `./my-plugin/pi-web-plugin.js` and legacy plugin-root-relative references such as `nested/pi-web-plugin.js`; all accepted forms are rewritten to deployment-portable, gateway-relative references.
`source` describes where the plugin came from (`bundled`, `local`, or the Pi package source). `scope` is `bundled`, `local`, `user`, or `project`. `machineSpecific` controls whether the gateway copy is valid for remote machines or only each selected machine's own copy can appear.
A plugin can fetch its own static assets with URLs under:
At an origin-root deployment, a plugin's static assets are available under:
```text
/pi-web-plugins/<plugin-id>/<path-inside-plugin-root>
```
PI WEB prevents asset path traversal outside the plugin root. JavaScript, JSON, CSS, and HTML get appropriate content types; other files are served as octet-stream.
Prefer module-relative asset URLs so they also work for remote machine plugins. For example, a built plugin module can reference an SVG shipped beside it:
```js
const iconUrl = new URL("./assets/icon.svg", import.meta.url);
```
The final installed plugin package must contain `assets/icon.svg` at that path relative to the final built module. PI WEB serves files that already exist in the package; it does not copy a source `public/` directory or apply Vite-style public-directory semantics. Configure the plugin build and package contents to emit or copy the asset into its final module-relative location.
PI WEB prevents asset path traversal outside the plugin root. JavaScript, JSON, CSS, HTML, and SVG files get appropriate content types; unknown file types are served as octet-stream.
## Plugin module shape
@@ -452,6 +478,7 @@ interface PluginRuntimeContext {
openTerminal: (options?: { terminalId?: string }) => void;
refreshFiles: () => void | Promise<void>;
refreshGit: () => void | Promise<void>;
checkForPiWebUpdates?: () => void | Promise<void>;
startSession: () => void | Promise<void>;
archiveSession: () => void | Promise<void>;
stopActiveWork: () => void | Promise<void>;
@@ -466,6 +493,7 @@ Notes:
- `enabled` is evaluated when the action palette asks for actions.
- `selectWorkspaceTool()` expects a qualified panel id such as `my-plugin:workspace.info`.
- `openTerminal()` switches to the built-in terminal panel. Pass `{ terminalId }` to deep-link to a specific terminal.
- `checkForPiWebUpdates()` forces a fresh update check on the selected machine and refreshes `state.piWebStatus`. It is optional so plugins remain compatible with older PI WEB hosts.
- Only fields documented here and declared in `plugin-api.d.ts` are stable public plugin API. Anything else is experimental: it may become public API later, change shape, or disappear.
### Prompt editor API
@@ -746,7 +774,7 @@ Labels should use the same helper through a plugin-owned cache because `items()`
const envCache = new Map();
function envKey(machine, workspace) {
return `${machine.id}:${workspace.id}:docker/development.be-go.local.env`;
return `${machine.id}:${workspace.id}:.env.local`;
}
function loadEnvLabel(context) {
@@ -756,7 +784,7 @@ function loadEnvLabel(context) {
const pending = { status: "loading", label: undefined };
envCache.set(key, pending);
context.files.readFile("docker/development.be-go.local.env")
context.files.readFile(".env.local")
.then((file) => {
pending.status = "ready";
pending.label = file.content.match(/^DEV_URL=(.+)$/m)?.[1];