WebChat - Transform CLI into a Conversation

WebChat makes any agent CLI available through a chat-style interface that users can reach from their browser.

What WebChat Delivers

πŸ’¬

Conversational UI

Stream CLI input/output through a WhatsApp-inspired interface with bubbles, timestamps, and typing indicators.

πŸ”

Router Login

WebChat uses the router login flow, so access follows the same local or SSO session model as other authenticated router surfaces.

πŸ› οΈ

Agent Ready

When a static workspace agent is configured, WebChat automatically connects to that agent’s manifest cli command.

Access

Use ploinky webchat to print the current access URL. The command reports the router login URL; --rotate is accepted for compatibility but WebChat does not use a surface-specific token.

ploinky webchat          # show the router login URL
ploinky webchat --rotate # show the same login URL
Access URL format: http://127.0.0.1:8080/webchat

How Commands Are Chosen

WebChat derives its runtime command from the static workspace agent:

  1. Static agent – Configure one with ploinky start <agent> <port>. The router records the agent’s manifest path.
  2. Manifest CLI – When the agent’s manifest.json defines a cli command, WebChat runs it inside the agent container.
  3. No CLI? – Sessions still open, but the chat will display a notice that no command is bound.

This flow depends entirely on the static workspace agent: keep its manifest updated to control which CLI the chat session runs.

URL Parameters and CLI Arguments

WebChat accepts arbitrary query parameters in its URL. When an explicit agent query parameter is present, the router keeps the remaining query parameters attached to the WebChat session and forwards them to that agent's CLI command as long-form CLI flags encoded as single tokens.

/webchat?agent=achilles-cli&path=/absolute/path

# launches the selected agent as:
ploinky cli achilles-cli --path=/absolute/path

The router reserves agent for agent selection, tabId for the browser client, and sessionId for folder-history routing. These internal values are not forwarded as agent CLI flags. Agent CLIs remain responsible for interpreting ordinary forwarded flags and values.

Session Experience

Folder Sessions

WebChat stores its selectable continuation history under <cwd>/.copilot_history/. The folder contains current_session.json plus one JSON file per conversation. Refreshing the page reuses the selected folder session and a surviving agent process, while the browser keeps its client-only tabId in sessionStorage.

  • Load History renders the current session only when requested. The composer remains available while older messages are hidden.
  • New+ creates an empty session and makes it current for the folder.
  • Load Session lists the first user-message preview and relative activity time, such as 2 days ago, without message counts or agent metadata.
  • Connected browser clients using the same working directory receive session changes and new turns through the shared EventSource runtime.

If the original process no longer exists, the next conversational message carries the prior messages in a delimited context block. Historical inputs are not replayed as commands. Slash commands remain unchanged and defer restoration until a later conversational message.

A newly started CLI receives PLOINKY_WEBCHAT_SESSION_ID and PLOINKY_WEBCHAT_HAS_HISTORY. A value of 1 tells a generic agent that this is an existing conversation, so it should not emit new-conversation startup content. Empty sessions, including those created by New+, receive 0.

Message Rendering

  • βœ… Automatic timestamps for each exchange
  • βœ… Rich markdown rendering (tables, code blocks, lists)
  • βœ… Long output folding with β€œShow more” expansion
  • βœ… Agent progress metadata displayed as a collapsible block above the final answer
  • βœ… Side panel to inspect full message history

Input Controls

  • βœ… Auto-resizing composer with keyboard shortcuts (Enter to send, Shift+Enter for new line)
  • βœ… Light/Dark/Explorer/Obsidian Dark theme selector with persistent preference (Explorer loads by default; switch via Settings β†’ Appearance)
  • βœ… Slash command autocomplete β€” type / to open a command menu; supports agent-declared subcommands and argument completions
  • βœ… Composer @ autocomplete β€” typing @ opens a grouped menu of static configured tags plus files and folders uploaded in the current WebChat session; selecting a file inserts a stable @file:uploads/<sessionId>/<path> token and attaches a structured reference to the outgoing envelope
  • βœ… Cancel button β€” appears during active processing; sends an interrupt signal to the agent

Session Uploads

WebChat stores uploaded files in a per-session directory under the current working directory: <cwd>/uploads/<webchat_sid>/. webchat_sid is the WebChat session cookie issued to the authenticated browser; it is not the browser tab id.

  • The attachment menu has Upload file and Upload folder entries. Folder uploads preserve file.webkitRelativePath as the relative path inside the session upload directory.
  • Composer @ suggestions search only the current session upload directory. Other sessions' uploads never appear.
  • Uploads use POST /webchat/uploads and are read back via GET /webchat/uploads?path=<session-relative-path>. Downloads reuse stored MIME metadata and set X-Content-Type-Options: nosniff. The server rejects absolute paths, traversal segments, NUL bytes, symlink escapes, and reserved .secrets/*.secrets names.

Security Practices

  • Use HTTPS or SSH tunnels when exposing the WebChat URL beyond localhost.
  • Protect router session cookies and the encrypted .ploinky/.secrets store used by local auth, dashboard tokens, and manifest env.
  • .copilot_history is authenticated, workspace-confined project state but is plaintext. It receives a local .gitignore to reduce accidental commits.

Troubleshooting

  • Blank session? Verify the static agent has a cli command in its manifest.
  • 401 errors? Run ploinky webchat again to confirm the token and URL.
  • Need a different command? Update the agent manifest and restart the workspace so WebChat picks up the change.
  • Custom launch flags ignored? Confirm you opened /webchat with ?agent=<name>; without an explicit agent selection the router uses the default WebChat target and does not synthesize agent-specific CLI flags.