Omniscio documentation
Browse all documentation
  1. Getting Started17
  2. Sessions & Agents132
  3. Inbox & Notifications67
  4. Projects & Tasks97
  5. Automation & Scheduling79
  6. Knowledge & Memory27
  7. AI Features72
  8. Integrations106
  9. Plugins & Marketplace34
  10. Cloud & Teams59
  11. Settings & Customization66
  12. Account & Billing28
  13. Troubleshooting79
  14. CLI & API Reference27
  15. Legal & Policies5
  16. Uncategorised17

Share via CLI — part 2 (behaviour and security)

The rules behind the four Share-via-CLI endpoints and their security model: a publish is de-duplicated globally and presentation-aware, its telemetry source is fixed server-side, it is apply-immediately with no inbox approval, and the whole surface is localhost-only behind a bearer token. Part 1 covers the endpoints themselves — route shapes, bodies and status codes.

What it is

The behaviour and security that apply to every Share-via-CLI publish: how identical content is de-duplicated, why the telemetry source cannot be spoofed, why there is no inbox approval gate, and the localhost-plus-bearer-token boundary the surface sits behind. Part 1, share-cli.md, is the endpoint reference — route shapes, body schemas and status codes.

Where to find it

The endpoints these rules apply to are on Part 1 of this page, share-cli.md. The user-facing flow and its own security model are on share-artifacts.md.

How it behaves

Behavioural notes

  • Dedup is global AND presentation-aware — findActiveByContentHash() matches against every active (non-revoked, non-expired) row regardless of who published it (in-app, CLI, IPC), so a CLI publish can reuse a token first generated by the paste modal and vice-versa. The dedup key folds the raw bytes plus the presentation knobs (title / fullBleed / background, and markdownStyle for a markdown page) together, so re-publishing identical bytes with a different title / layout / colour / reading skin mints a fresh link instead of returning the old presentation; identical bytes and identical presentation reuse the same token.
  • sourceType is not configurable from the body. The CLI route hard-codes sourceType: 'cli' server-side so the telemetry origin cannot be spoofed.
  • No inbox approval gate — publish is apply-immediately. The design rationale is that publish doesn't spawn Claude (no real-money cost from approval bypass) and the renderer-side flow is also apply-immediately, so gating only the CLI would be asymmetric. Firebase storage costs are real but bounded by the shared 10-mutations/min rate limit.
  • Retries: send X-Client-Request-Id. A retry carrying the same id as a finished publish returns that share instead of minting another — for a page and a video alike. For a page, content-hash dedup also returns the same token for the same bytes; a video is never de-duplicated by content, so the same file published twice makes two shares.
  • The 1 MB body cap is dispatcher-level, so any content over ~1 MB will be rejected at the parse layer even though the Zod schema allows up to 2 MB. For >1 MB inline content, stage the bytes to a file first and publish by path.
  • Build a scrollable document, not a full-viewport app shell (the #1 mobile-render failure). A share renders inside a sandboxed iframe whose height is not the phone's visible viewport (mobile browser chrome + the sandbox wrapper eat vertical space), so an artifact locked to 100vh/100dvh with overflow:hidden and a bottom-pinned bar (a composer, toolbar, or footer) clips that bar off-screen and unreachable — the user cannot scroll or zoom to it. Author every published artifact as natural top-to-bottom flow: no 100vh/100dvh height lock on html/body, no overflow:hidden page root, no flex-stretch that fills the screen, no bottom-pinned regions (reserve position:fixed for genuine overlays). This is independent of fullBleed — a full-bleed page still scrolls fine as long as its own document flows. Verify before you hand over the link: open the live data.url at a short mobile height (~390×600) and confirm the key content (especially any input box or button) is visible without scrolling past the fold.
  • CLI publishes are unprotected by default. The body schema does NOT accept passwordHash / viewCap / notifyOnView fields — every CLI-published share starts with no password gate, no view cap, view count 0, and notify_on_view = false. To add a password after publishing, either open the resulting share in the in-app Shares view and use the Edit modal (UX detailed in shares-view.md § Editing a share), or call POST /share/:token/protection with a { "password": "<plaintext>" } body — the endpoint derives the hash server-side via deriveSharePasswordHash() (so no crypto has to be duplicated in shell callers) and re-mirrors the credential immediately; pass { "password": null } to clear it. The in-app Edit modal still hashes in the renderer via SubtleCrypto; the CLI route instead accepts the plaintext over the loopback, bearer-gated connection and never persists it. This route sets or clears the password only — view cap and view-notify stay in-app.

Security model

Same as the in-app flow — see share-artifacts-part-2.md § Security model. The CLI surface adds two specifically-CLI considerations:

  • Localhost-only: the CLI control server binds to 127.0.0.1:19519 and is not reachable from other machines. A misconfigured router cannot expose it.
  • Bearer token treatment: the token is the credential for every mutation. Never include it in curl -v output (which dumps headers to terminal), never paste it into chat, never commit it to a repo. Rotate at Settings → CLI Control → Regenerate if any of those happen.

Related

  • share-cli.md — Part 1: the four endpoints — publish, list, revoke and delete — with their route shapes, body schemas and status codes
  • share-artifacts.md — the in-app flow with the same publish pipeline
  • cli-control.md — the CLI control server's design, auth model, and full route catalogue

Last verified 2026-10-10