get.quick.mio.vision

quick

Build/deploy an internal Miovision site on Quick — a folder of static files served at <site>.quick.mio.vision, with a zero-config global `quick.*` API for identity, db, realtime, AI, Snowflake, per-user SaaS integrations (Jira/Confluence/Slack/Drive/Salesforce), file uploads, and multi-site deploy.

First seen Jun 18, 2026

Installation

$ npx skills add https://get.quick.mio.vision

Summary

  • Build/deploy an internal Miovision site on Quick — a folder of static files served at <site>.quick.mio.vision, with a zero-config global `quick.*` API for identity, db, realtime, AI, Snowflake, per-user SaaS integrations (Jira/Confluence/Slack/Drive/Salesforce), file uploads, and multi-site deploy.
  • Use for internal Miovision web site/apps/tools/dashboards, or when the user mentions Quick.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Declared agents claude-code

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 18,145 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 41 installs

SKILL.md

Quick — internal Miovision sites

A site is a folder with index.html, deployed to https://<site>.quick.mio.vision. No backend, build step, or API keys — every server capability lives on the global quick object, loaded with one <script> tag (see [SDK](#sdk--global-quick)).

Okta gates the site: every visitor is a verified @miovision.com employee. No per-site permissions — the login wall is the only access control. So:

  • Never store secrets or customer PII. Any employee can read all of it.
  • Authenticated ≠ authorized: treat all stored data as org-readable.
  • Not for: public sites, non-employees, PII/secrets.

Rules

  • Static files only, served as-is. Prefer a single index.html with vanilla JS or CDN ESM.
  • Compose behavior from quick.*. Don't write a server.

Frontend stack

No build step — use CDN libraries. Defaults:

Deploy & fetch

The quick CLI ships a folder to <site>.quick.mio.vision and pulls it back. Both auth via Miovision SSO: first run opens a browser, then caches the token (~/.config/quick/) and reuses it; expired sessions re-login automatically. One login covers every site (domain-scoped cookie). Both need the Miovision network/VPN.

quick deploy [src] [site] [--to <folder>] [--tags <a,b>]

Uploads src (default .) to site (default: dir's base name). A directory is walked recursively, preserving relative paths as served URLs; a single file is served under its base name. --to prefixes a server-side folder onto every served path.

quick deploy                            # cwd -> <folder-name>.quick.mio.vision
quick deploy . lunch-vote               # cwd -> lunch-vote.quick.mio.vision
quick deploy ./dist lunch-vote          # ./dist -> lunch-vote.quick.mio.vision
quick deploy ./dist --site lunch-vote   # same; --site wins over positional
quick deploy script.js newsite --to dist  # one file -> newsite/dist/script.js
quick deploy ./dist newsite --to assets    # ./dist/* -> newsite/assets/*
quick deploy . lunch-vote --tags food,voting  # deploy + tag (gallery filter labels)
  • Subdomain comes from the second positional or --site; the flag wins if both given.
  • A single-file src requires an explicit site (its own name can't double as the subdomain).
  • Deploys are additive (the server only writes the files you send), so deploying one file into a folder leaves the rest of the site untouched.
  • --tags sets the site's gallery labels (comma-separated slugs: a-z 0-9 -, max 32 chars each). Omitting the flag leaves existing tags untouched; tags can also be edited later in the gallery or via quick.sites.setTags.
  • Payload caps at 64 MiB. Over that, split the site or push large assets out of band (e.g. aws s3 sync).

quick fetch <site> [dir]

Inverse: downloads site's files into dir (default: the site name). Additive — overwrites fetched files, leaves unrelated local files alone.

quick fetch lunch-vote                  # -> ./lunch-vote
quick fetch lunch-vote ./dist           # -> ./dist

deploy and fetch accept --domain <domain> (or QUICK_DOMAIN env) to target a non-prod deployment; defaults to quick.mio.vision.

quick update

Replaces the running quick binary in place with the latest build from get.quick.mio.vision (same source as the curl installer), then re-runs quick init to refresh the agent skill so the two always move together. Detects your OS/arch automatically; pass --base <url> to pull from a different host. Only works on the installed binary — running under node/bun (dev) is refused.

quick update                            # self-update to the latest binary (+ refresh skill)
quick --version                         # print the installed version

Every command also does a quick background version check and prints a one-line notice to stderr if the binary is behind (it never touches stdout or fails the command): quick: a newer version is available … Run 'quick update' to upgrade. If you see it, run quick update before continuing — that upgrades the binary and refreshes this skill in one step. Set QUICKNOUPDATE_CHECK=1 to silence the check (e.g. pinned CI).

SDK — global quick

Every page's <head>:

<link rel="icon" href="/__quick/favicon.svg" type="image/svg+xml" />
<script src="/__quick/quick-sdk.js"></script>

Both are platform /__quick/ assets served by the server. The <script> is required — quick.* attaches to the global once it loads (no import/bundler). The <link> is the shared Quick "Q" tab mark; include verbatim, don't ship a per-site favicon.ico (a site that needs its own icon still can).

Identity

const me = await quick.me();   // { userId, email, name }

Database — quick.db

Schemaless JSON docs, scoped per site (Postgres JSONB).

const posts = quick.db.collection("posts");
const doc   = await posts.create({ title: "Hello" });   // { id, title }
await posts.get(doc.id);
await posts.update(doc.id, { title: "Edited" });        // shallow-merge; other fields kept
await posts.list();                                     // [{ id, ... }]
await posts.delete(doc.id);

Cross-site reads — collection(name, { site })

A collection is scoped to this page's site by default. Pass { site } to read/write another site's collection (e.g. a db inspector). Fine because all Quick data is org-readable — it's not a security boundary. subscribe() is NOT supported cross-site (the live feed rides this page's socket) — it throws; use list()/polling.

const theirs = quick.db.collection("posts", { site: "lunch-vote" });
await theirs.list();

Collections aren't enumerable — they exist only where docs were written, no "list collections" API. List sites with quick.sites.list(); the collection name must be known.

Queries — chained where

Sugar over list() + client-side filter: the whole collection is fetched then filtered in the browser, so use on reasonably-sized collections. Constraints AND together; a field may be constrained more than once. Chains are immutable.

const r = await quick.db.collection("employees")
  .where("salary", ">", 100000)
  .where("experience", ">", 0)
  .get();                                  // [{ id, ... }]

Operators: ==, !=, >, >=, <, <=, in (value in array), contains (substring).

Realtime — subscribe

Delivers only changes after you attach — seed with list() first, then subscribe. Returns an unsubscribe fn. Optional where restricts changes (matched client-side).

Your own writes echo back. subscribe fires for every write on the site, including this tab's — so a create() you awaited also arrives as onCreate. Combined with optimistic insert, that's a double-add. Don't guard with "add only if absent" (the echo can race your create()). Funnel every path through an upsert-by-id so the doc lands once.

let docs = await posts.list();   // seed, then go live

// Insert-or-replace by id — single funnel for local writes AND echoes.
function upsert(doc) {
  const i = docs.findIndex((d) => d.id === doc.id);
  if (i === -1) docs.push(doc); else docs[i] = doc;
  render();
}
async function add(title) { upsert(await posts.create({ title })); } // optimistic; echo re-upserts same id

const stop = posts.subscribe(
  { status: "published" },   // optional where; omit for every change
  {
    onCreate: (doc) => upsert(doc),
    onUpdate: (doc) => upsert(doc),
    onDelete: (id)  => { docs = docs.filter((d) => d.id !== id); render(); },
  },
);
// later: stop();

where takes a bare value for equality ({ status: "published" }) or an operator object ({ views: { gte: 100 } }; ops: eq, ne, gt, gte, lt, lte, in, contains). Chained query subscribes too: posts.where(...).subscribe({ onCreate, ... }). onDelete can't see the deleted doc's fields, so it fires for every delete regardless of where — reconcile by id.

A write notifies every page on the site (including the writer's), so plain CRUD is collaborative for free. Use quick.socket only for ephemeral data.

Sockets — quick.socket

Site-scoped broadcast for ephemeral data (cursors, presence, typing, WebRTC signaling). send reaches every other page on the site (never your own tab, never another site). Shared connection, lazy-opened, auto-reconnects. Caps: 100 concurrent connections, 50 msg/sec per connection — coalesce high-frequency events.

quick.socket.send({ type: "cursor", x, y, user: me.email });

const stop = quick.socket.onMessage((data) => {
  if (data.type === "cursor") drawCursor(data);
});
// later: stop();  — or quick.socket.close() to tear down.

Fire-and-forget, never saved. For stored/replayable data use quick.db + subscribe.

AI — quick.ai

Claude via Bedrock, proxied server-side (no API key in page). Vercel AI SDK call shape: pass prompt (one turn) or messages (conversation), plus optional model (Bedrock id) and generation settings.

const { text } = await quick.ai.generateText({ prompt: "Summarize my tasks" });

// Streaming (browser JS — no `process`). `stream` yields ordered parts: text
// deltas, plus tool-call / tool-result parts when you pass `tools` (render those
// inline to show the agent's work). With tools, `files` resolves at end-of-stream
// to the changes the model proposed (ready for quick.sites.upload).
const { stream } = quick.ai.streamText({
  messages: [{ role: "user", content: "Summarize my tasks" }],
});
for await (const part of stream) {
  if (part.type === "text") output.textContent += part.text;
  else if (part.type === "tool-call") console.log("tool:", part.name, part.args);
  else if (part.type === "tool-result") console.log("→", part.id, part.result ?? part.error);
}

// Cancel a generation with an `abortSignal` (a "stop" button), same as the AI
// SDK. Aborting ends the stream (the loop throws an AbortError) and tells the
// server to stop the model — so you stop paying for tokens too. Works the same
// on generateText (it rejects with an AbortError).
const ac = new AbortController();
stopButton.onclick = () => ac.abort();
const { stream } = quick.ai.streamText({ prompt: "Write a long essay", abortSignal: ac.signal });
try {
  for await (const part of stream) {
    if (part.type === "text") output.textContent += part.text;
  }
} catch (err) {
  if (err.name !== "AbortError") throw err; // ignore the user's own cancel
}

Snowflake (v1) — quick.snow

Read-only SELECT over internally-public data via a shared service account (same data for every user, no row-level identity). rows are positional arrays aligned to columns — zip them:

const { columns, rows } = await quick.snow.sql({
  query: "SELECT name, count FROM my_table LIMIT 10",
});
const objs = rows.map((r) => Object.fromEntries(columns.map((c, i) => [c, r[i]])));

AWS (read-only) — quick.aws

Read-only AWS, run with the platform's own AWS identity (no browser credentials, like quick.snow). For internal ops/cost dashboards. Each service exposes a generic command(Name, input) over a server allowlist of read-only commands, plus typed sugar for the common ones. Inputs/outputs are the AWS SDK's own JSON (PascalCase), passed through unchanged — match the AWS API docs. Pagination is the caller's job (loop NextToken); one call = one AWS command. A command off the allowlist is rejected; nothing here can write.

// Cost Explorer — billed $ (global service).
const ce = await quick.aws.costexplorer.getCostAndUsage({
  TimePeriod: { Start: "2026-06-01", End: "2026-06-22" },
  Granularity: "DAILY",
  Metrics: ["UnblendedCost"],
  GroupBy: [{ Type: "DIMENSION", Key: "SERVICE" }],
});
// CloudWatch — metrics.
const m = await quick.aws.cloudwatch.listMetrics({ Namespace: "AWS/Bedrock" });
await quick.aws.cloudwatch.getMetricData({ MetricDataQueries, StartTime, EndTime });
// CloudTrail — management events (rate-limited; page via NextToken).
await quick.aws.cloudtrail.lookupEvents({
  LookupAttributes: [{ AttributeKey: "EventSource", AttributeValue: "bedrock.amazonaws.com" }],
  StartTime, EndTime, MaxResults: 50,
});
// Escape hatch: any allowlisted command by name.
await quick.aws.costexplorer.command("GetDimensionValues", { /* … */ });

Allowlisted today: costexplorer (GetCostAndUsage, GetDimensionValues), cloudwatch (ListMetrics, GetMetricData), cloudtrail (LookupEvents). A 501 means the surface isn't enabled on this server. Stays a stub until QUICKAWSENABLED=true and the role grants the reads.

Runtime files — quick.files

Write files into this site at runtime (e.g. drag-drop publish). The file lands beside deployed assets (siblings untouched), served as a static asset at that path. Site-scoped.

await quick.files.upload("dist/2.0.0/quick-voice.js", file); // served at /dist/2.0.0/quick-voice.js
const files = await quick.files.list();                      // [{ path, size }, …]
await quick.files.delete("dist/2.0.0/quick-voice.js");

dropZone.addEventListener("drop", async (e) => {
  e.preventDefault();
  for (const file of e.dataTransfer.files) {
    await quick.files.upload(file.name, file);
  }
});

Integrations — quick.integrations

Read the current user's own external SaaS accounts (Jira, Confluence, Slack, Google Drive, Salesforce, GitLab), proxied server-side. The user links these once in WorkforceAI; Quick looks up their stored token and makes the upstream call on their behalf. The token never reaches the browser — pages only ever call the same-origin quick.* methods.

Key properties:

  • Per-user, not shared. Every call acts as whoever opened the page, using their connection. A different visitor gets their own data (or nothing, if they haven't linked that provider). This is unlike quick.snow, which is one shared service account for everyone.
  • Read-only. Only GET-style reads are proxied.
  • No per-site grants. Any site the user opens may use their connections.
// What has THIS user connected? Metadata only — never tokens.
const conns = await quick.integrations.list();
// [{ key: "jira", label, metadata, expiresAt, hasRefreshToken }, …]

Each provider has a small typed surface plus a generic get(path, query) escape hatch for any read on that provider's API. Put query params in the query object, not the path.

// Jira — the authed Atlassian user, then any Jira REST read.
const who = await quick.integrations.jira.myself();
const issues = await quick.integrations.jira.get("rest/api/3/search", {
  jql: "assignee = currentUser() ORDER BY updated DESC",
  maxResults: 20,
});

// Confluence
await quick.integrations.confluence.currentUser();
await quick.integrations.confluence.get("rest/api/space");

// Slack — the user's PERSONAL Slack (acts as them, not an org bot).
await quick.integrations.slack.authTest();
await quick.integrations.slack.users({ limit: 50, cursor });   // users.list, paginated
await quick.integrations.slack.get("api/conversations.list");

// Google Drive (Google Workspace integration, Drive-scoped)
await quick.integrations.drive.about({ fields: "user" });
await quick.integrations.drive.files({ q: "name contains 'report'" });
await quick.integrations.drive.get("drive/v3/files");

// Salesforce
await quick.integrations.salesforce.versions();
await quick.integrations.salesforce.get("services/data/v59.0/sobjects/Account");

// GitLab — the user's PERSONAL gitlab.com account (acts as them).
await quick.integrations.gitlab.currentUser();                 // GET /api/v4/user
await quick.integrations.gitlab.projects({ per_page: 20 });    // projects they belong to
await quick.integrations.gitlab.get("api/v4/merge_requests", { scope: "assigned_to_me" });

A call throws if the user hasn't linked that provider — gate on quick.integrations.list() (or catch) and prompt them to connect in WorkforceAI rather than assuming a connection exists.

Multi-site — quick.sites

List the sites on Quick and deploy files to a named site from the browser (the same primitive the CLI's quick deploy uses, exposed for tools like the gallery or an in-page deployer). Unlike quick.files, which always targets the current site, sites.upload writes to any site by name.

const sites = await quick.sites.list();
// [{ name, fileCount, author, updatedBy, tags: string[], updatedAt }, …]
// author = who first deployed (never changes); updatedBy = who last deployed.
// Both are { email, name } | null.

// Deploy files to another site. Each file's `contentBase64` is its bytes,
// base64-encoded; `path` is the served URL within that site. Additive — only
// the files you send are written, siblings untouched.
await quick.sites.upload("lunch-vote", [
  { path: "index.html", contentBase64: btoa("<h1>Hi</h1>") },
]);

// Replace a site's tags (the gallery's filter labels) without redeploying.
// Tags are slugs (a-z 0-9 -, max 32 chars); the reply is the normalized,
// deduped list as stored.
await quick.sites.setTags("lunch-vote", ["food", "voting"]);