plik_KM
How to send Kosta files via the Plik MCP — when, how, where credentials live, and how to verify the backend is healthy. Read this once per session before the first upload.
Files1
View on GitHubSKILL.mdskills/personal-ops/plik_KM/SKILL.md
GitHubPlik file sharing
Plik (root-gg/plik 1.4.2) is the self-hosted "send Kosta a file via short link" backend. It runs in Docker on the Mac Studio, exposed via Tailscale Funnel. The official Plik CLI ships an MCP server (plik --mcp) that is wired into every Hermes profile and the Claude Hermes hybrid.
When to use it
Use native Telegram attach (the platform reply tool with files=[…]) for:
- Images under 10MB (PNG/JPG/WebP — render as inline photos).
- Audio under 10MB (OGG — sends as voice bubble).
- Short videos under 10MB (MP4 — plays inline).
- Small PDFs and Office files Kosta opens in the moment.
Use plik upload_file / upload_files / upload_text for:
- Any file > 10MB (Telegram's document cap is 50MB and gets unreliable above ~10MB).
- Formats Telegram won't preview (zip, sqlite, log dumps, build artifacts).
- Anything Kosta should be able to reopen from another device or after the chat scrolls away.
- Code/log dumps the model would otherwise paste as a giant wall of text — use
upload_textwith a meaningful filename.
If both are viable, prefer native attach so Kosta gets the inline render.
TTL policy
Plik's default TTL is 24h. Choose explicitly per upload:
| Situation | ttl |
Notes |
|---|---|---|
| One-off oversized artifact, ephemeral | 0 (server default = 24h) |
Also include the source path or regeneration command in the reply. |
| Week-scope working artifact | 604800 (7 days) |
Logs being investigated, screenshots from an ongoing thread. |
| "For the record" / archived deliverable | 2592000 (30 days) |
The server max — anything longer requires a config change. |
| Sensitive payload | combine TTL with password and one_shot: true |
Encrypts at rest, deletes after first download. |
Avoid quietly shipping a 24h link when Kosta said "stable" or "I'll need this later". State the TTL in the reply so he knows.
Credentials and auditability
| Field | Value |
|---|---|
| 1Password vault | CLI |
| 1Password item | Plik (Mac Studio) |
| Backend URL | https://macstudio.tailf7342a.ts.net/plik |
| Plik account | ildunari (admin) |
| API token field | credential (used by plik --mcp, hand-off via ~/.plikrc) |
| Web/Telegram-mini-app login field | password |
| CLI config | ~/.plikrc — URL + Token |
The token is loaded by the MCP server from ~/.plikrc at process start. Hermes profiles and the Claude hybrid all spawn plik --mcp under the kosta UID, so they share the same ~/.plikrc and the same ildunari token.
Verify before relying on it
op read "op://CLI/Plik (Mac Studio)/credential" >/dev/null && \
curl -sS -o /dev/null -w 'plik health: HTTP %{http_code}\n' https://macstudio.tailf7342a.ts.net/plik/version
Both should succeed (1Password item readable, plik /version returns 200) before trusting the upload path. If either fails, fall back to native attach (for small files) or tell Kosta the plik backend is unreachable — do not retry blindly.
If the token has rotated (1P updated, but a stale ~/.plikrc is still cached on the gateway process), the upload will return 403 Forbidden : invalid token. Re-pull via:
TOKEN=$(op read "op://CLI/Plik (Mac Studio)/credential")
printf 'URL = "https://macstudio.tailf7342a.ts.net/plik"\nToken = "%s"\n' "$TOKEN" > ~/.plikrc
Then restart the calling gateway so the MCP child reloads ~/.plikrc.
MCP tools
plik --mcp exposes these tools:
upload_text(content, filename, ttl?, one_shot?, password?, comments?)— inline text → named file.upload_file(path, ttl?, one_shot?, password?, comments?, stream?)— single file by absolute path.upload_files(paths, ttl?, one_shot?, password?, comments?)— multiple files in one upload.server_info()— version, feature flags, what's allowed.list_profiles()— Plik CLI profiles defined in~/.plikrc(currently just the default).
All upload tools return {"url": "https://macstudio.tailf7342a.ts.net/plik/#/?id=…", "id": "…", "expires_at": "…"} shape. The URL points at the bundled Plik UI; rewrite to the custom UI (see "Two UI surfaces" below) only when sharing the link with a human who will load it interactively. For machine-to-machine and quick chat shares, the bundled URL is fine.
Two UI surfaces
There are two web UIs on top of the same Plik backend:
| Route | What it is | When |
|---|---|---|
/plik/ |
Plik's bundled Angular SPA (1.4.2 stock) | Fallback / admin. Stays untouched as a recovery path. Also the default for share links returned by the MCP tools. |
/plik/ui/ |
Custom UI built for Hermes (dark editorial theme, harmonized with the Hermes mini-app dock) | What humans actually use — Hermes mini-app dock Plik tab and Claude hybrid Plik tab both route here. |
The custom UI's HTML/CSS/JS lives at /Users/Kosta/plik-ui/ and is served by an nginx Docker container (plik-ui, port 9080) bound there read-only. Tailscale Funnel forwards /plik/ui/... to that nginx; everything else under /plik continues to go to the Plik backend at port 8080. Sub-paths:
/plik/ui/— upload composer (drag-drop + all toggles + real QR + share URL)./plik/ui/inbox.html— list/filter/revoke your uploads./plik/ui/d.html?id=…— public download page for a share (handles password-protected uploads via HTTP Basic auth modal, renders comments as markdown)./plik/ui/m/and/plik/ui/m/inbox.html— compact Telegram-mini-app variants of the same pages./plik/ui/login.html— local-login form. After login, sessions auto-redirect.
Auth model in the custom UI: standard Plik cookie + X-XSRFToken (cookie has Path=/plik so it's readable from /plik/ui/*). API token auth via X-PlikToken is also supported by the server but the UI uses cookies for simplicity.
To swap the public share-URL shape over to the custom UI, edit shareUrl() in /Users/Kosta/plik-ui/assets/api.js — it already builds /plik/ui/d.html?id=…. If MCP tools should return the custom URL shape too, that's a server-side rewrite (Plik's PlikDomain only controls the host, not the path).
Edge cases
- Plik backend down: MCP call returns an error. Surface "plik backend is unreachable, falling back to inline attach for small files" — never silently drop the artifact.
- Disk full on Studio:
~/plik-data/lives on the boot disk; periodicallydu -sh ~/plik-dataand prune expired uploads withpliklist/revoke. - Token leaked into logs: rotate via
curl -b cookies -X DELETE …/me/token/<id>, generate new one, update 1P +~/.plikrc, restart gateways. Never echoTOKENin shell output. - Source-tagging:
plikdoes not record which agent uploaded which file. If you need to disambiguate, setcommentsto something like"from: hermes-gpt"and the comment shows on the share page. - Streaming uploads: for ephemeral relays (forward a file someone sent you to Kosta without storing it on disk), set
stream: true. The file is not persisted server-side; the download has to be ready when Kosta clicks the link. - Password-protected uploads: when sharing secrets, pass
password. The recipient gets HTTP basic auth before download. one_shot: true: deletes after first download. Good for tokens/secrets sent in chat that Kosta will read once.
Operator
Plik backend (the API)
- Container:
docker ps --filter name=plik - Config file:
~/plik-config/plikd.cfg(host-mounted into container) - Data + sqlite DB:
~/plik-data/(host-mounted) - Restart:
docker restart plik(no Hermes-gateway impact) - Public path:
https://macstudio.tailf7342a.ts.net/plik(Tailscale Funnel →127.0.0.1:8080/plik) Path = "/plik"is set inplikd.cfgso the server handles the prefixFeatureAuthentication = "forced"— no anonymous uploads, everPlikDomain = "https://macstudio.tailf7342a.ts.net"— Plik generates links matching the public origin
Custom UI (the browser frontend)
- Container:
docker ps --filter name=plik-ui(nginx:alpine, port 9080) - Static root:
/Users/Kosta/plik-ui/(bind-mounted read-only) - Nginx config:
/Users/Kosta/plik-ui-conf/nginx.conf - Public path:
https://macstudio.tailf7342a.ts.net/plik/ui(Tailscale Funnel/plik/ui→127.0.0.1:9080) - Restart:
docker restart plik-ui(no Hermes-gateway impact) - Cache: currently
Cache-Control: no-storewhile iterating; can flip back to a short cache once the layout stabilises
To edit the UI: change files under /Users/Kosta/plik-ui/, refresh the browser. No build step. Note that m/index.html and m/inbox.html are byte copies of index.html and inbox.html with <body class="tg"> swapped in — patch the parents and re-copy.
Tailscale Funnel routes (state-changing — be careful)
The funnel is shared across many services. To list the live routing without touching it:
tailscale serve status
Funnel routes touching Plik:
/plik→http://127.0.0.1:8080/plik(Plik backend)/plik/ui→http://127.0.0.1:9080(nginx serving the custom UI)/plik-ui→http://127.0.0.1:9080(alias — kept while older bot/mini-app links still reference it)
Tailscale uses longest-prefix-match, so /plik/ui/... correctly hits nginx while /plik/... (anything else) hits Plik. Don't add a / route to the same hostname — it shadows everything.
If tailscale serve --bg --set-path=X ... accidentally turns off funnel, restore with tailscale serve --bg --https=443 --set-path=X ... (note --https=443 — that's what flags the route as funnel-exposed instead of tailnet-only).
If you change anything operational (config flags, auth model, retention, the mounted-paths, the funnel layout, the UI layout), update this skill in canonical Skillshare source, sync, commit, push.