Documentation
Everything needed to install poim, sign in, and add your first server.
[X] No section matches that search.
Install
The script detects your platform, verifies the SHA-256, and installs to /usr/local/bin when it can write there, otherwise to ~/.local/bin.
curl -sSL https://poim-5vk.pages.dev/install | bash
poim
The script enforces TLS 1.2 or newer and refuses a plain HTTP URL. On a checksum mismatch it aborts without installing anything.
Remove it with curl -sSL https://poim-5vk.pages.dev/uninstall | bash.
Authentication
The CLI has no password. It authenticates with an API token you create in the web panel. There are two ways to supply one.
Token
Create one under Settings, then API Tokens. Choose the
write scope, copy the value, then run poim and
pick Login with token. The value is shown exactly once.
The token is stored at ~/.config/poim/credentials.json,
written atomically at mode 0600 inside a 0700 directory. The CLI
refuses to read the file if its permissions are looser than that.
Device code
For terminals without a paste buffer, pick Login with device
code. The CLI shows a code such as ABCD-1234 and a
URL. Enter the code in the panel and approve it. The CLI polls every two
seconds and signs itself in. The code expires after five minutes.
When a token stops working
A revoked or expired token is detected on the next call. The CLI discards it rather than retrying, and returns you to the login menu.
Keyboard and mouse
| Input | Action |
|---|---|
| Up / Ctrl+P | Move up, wrapping at the top |
| Down / Ctrl+N | Move down, wrapping at the bottom |
| Enter, Right | Activate the highlighted row |
| Left, Escape | Back one level |
| Escape on the main menu | Open the quit confirmation |
| Tab, Shift+Tab | Jump between sections |
| Home / End | First and last row |
| Page Up / Page Down | Scroll by ten rows |
| Any character | Fuzzy filter |
| Backspace | Delete one filter character |
| Ctrl+U | Clear the filter |
| Ctrl+C | Quit |
| Ctrl+L | Clear the screen |
| Mouse click | Select the row under the cursor |
| Mouse wheel | Scroll three rows |
| Mouse hover | Highlight the row |
Inside a live terminal, mouse reports are forwarded to the remote
program, so htop and vim behave normally.
Escape leaves the terminal and returns to the previous menu.
The agent
The agent is an 8 MB static Go binary. It makes outbound WebSocket connections only, so installing it opens no port on your server and nothing is added to your firewall.
In the CLI, open VPS Manager, then Add VPS, and run the command the panel prints:
curl -sSL https://poim-5vk.pages.dev/agent/install.sh | \
POIM_PANEL=https://poim-5vk.pages.dev POIM_ENROLL_CODE=XXXX-XXXX bash
It installs a systemd unit. Review it before you trust it:
cat /etc/systemd/system/poim-agent.service
journalctl -u poim-agent -f
Remove it from the server with:
systemctl disable --now poim-agent
rm /etc/systemd/system/poim-agent.service /etc/poim/agent.conf
API tokens
A token has a name, a scope, an optional expiry and a status. The value is 64 characters, stored only as a SHA-256 digest, and returned exactly once at creation or rotation.
| Scope | Allows |
|---|---|
| read | Read-only. GET requests succeed, writes are refused with a permission error. |
| write | Read plus adding, editing and removing servers, terminals, file transfer. |
| admin | Write plus user, team and system management. |
The current scope appears in the CLI status bar next to your username. Using a token outside its scope produces a clear permission error rather than a silent no-op.
Rotating a token issues a new value and invalidates the old one immediately. Revoking is permanent.
Architecture
Four layers. The rule that matters is in the middle.
1A browser 1B terminal (poim)
\ /
\ HTTPS + WSS /
2 PANEL: relay and sync hub
no shell, no PTY, no command execution
|
| outbound WebSocket only
v
3 agent on your server
real PTY, real metrics, argv to execve
The panel forwards opaque frames between a client and an agent. It does not parse them and cannot execute them. Compromising the panel yields token hashes and VPS metadata, not a shell on your servers. Compromising one server does not affect the panel or any other server.
The panel is a Cloudflare Worker with a Durable Object hub and D1 storage. The site is Cloudflare Pages. Both are free and both include TLS.
Security model
- Tenant isolation. Every database query filters on
user_id. There is no unscoped read path. - Token storage. SHA-256 digests only. The plaintext is never persisted and never logged.
- No shell in the command path. argv goes to
execve. Injection is structurally impossible, not filtered. - Bounded execution. Every remote command has a timeout. The agent caps concurrent sessions.
- Agent hardening. The systemd unit sets
NoNewPrivileges,ProtectSystem,ProtectHomeand an explicit capability bounding set. - Supply chain. Release archives carry SHA-256 sums. Both installers abort on a mismatch rather than proceeding.
- Read the full threat model, including six known limitations, in
SECURITY.md.
Environment variables
| Variable | Effect |
|---|---|
| POIM_PANEL | Panel origin to talk to. |
| POIM_LANG | Force a language. Overrides the stored preference. |
| POIM_THEME | Force a theme: dark, light, dracula, nord, solarized, monokai, gruvbox, tokyo-night. |
| POIM_CONFIG_DIR | Where credentials live. |
| POIM_DOWNLOAD_BASE | Installer: where release archives are fetched from. |
| POIM_INSTALL_DIR | Installer: where the binary is written. |
| NO_COLOR | Disable colour entirely. Respected deliberately. |
| COLORTERM | Set to truecolor or 24bit for 24-bit output. |
| POIM_DEBUG | Print resolved configuration at startup. |
Example:
POIM_LANG=vi POIM_THEME=nord POIM_DEBUG=1 poim
Troubleshooting
Menus are cut off
The terminal is below 80x24. The CLI shows a resize notice rather than a broken frame. Enlarge the window.
No colour in the menus
NO_COLOR is set, or TERM=dumb. Both are honoured. Use COLORTERM=truecolor.
A VPS stays pending
The agent has not connected. On the server run journalctl -u poim-agent -f. The usual cause is an outbound filter blocking WebSocket.
Permission denied on an action
Your token scope does not cover it. A read token cannot write. Create a token with the write or admin scope.
The web panel shows a VPS the CLI does not
Both hold a WebSocket to the panel and update on events. If one is stale the connection dropped. Reconnect by restarting that surface.
Version history
1.0.0 is the first release. See CHANGELOG.md
in the repository for the full entry.
Browser support: current Chrome, Edge, Firefox and Safari. The site works with JavaScript disabled; the download page needs it for the QR code and copy buttons.