Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
},
"metadata": {
"description": "Deep video and image work for coding agents: analyze, describe, search, caption, clip, detect faces, and publish via the tinycloud CLI.",
"version": "0.3.16"
"version": "0.3.17"
},
"plugins": [
{
"name": "tinycloud",
"source": "./",
"description": "Video and image understanding and editing via the tinycloud CLI (Cloudglue): watch/see/extract/search/ask/face over videos and images, captions, clips, collections, plus one-command workflows for sales coaching, blog posts, ad analysis, meeting breakdowns, and YouTube publishing.",
"version": "0.3.16",
"version": "0.3.17",
"author": { "name": "Cloudglue" },
"homepage": "https://tinycloud.sh",
"repository": "https://github.com/cloudglue/tinycloud",
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "tinycloud",
"displayName": "Tinycloud Video",
"description": "Video and image understanding and editing via the tinycloud CLI (Cloudglue): watch/see/extract/search/ask/face over videos and images, captions, clips, collections, and one-command video workflows.",
"version": "0.3.16",
"version": "0.3.17",
"author": { "name": "Cloudglue", "url": "https://cloudglue.dev" },
"homepage": "https://tinycloud.sh",
"repository": "https://github.com/cloudglue/tinycloud",
Expand Down
27 changes: 26 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,32 @@ redaction that shipped the literal `[redacted]` where the cursor belonged,
and `collections sync` mirrors no longer silently truncate at 100 files
(pre-0.3.16, every listing was the first 50 rows with `has_more: false`).
Because the skill teaches `--describe` and show pagination, the floor was
raised to 0.3.16 (same merge-after-CDN gate). The host-level `profile` verb and the leading global flags `--home`/`--profile`
raised to 0.3.16 (same merge-after-CDN gate). 0.3.17 picks up SDK 0.7.23 and
adds the **`query` verb — analytical structured queries** over collection
data via Cloudglue `/v1/query` (verbs 16→17, features 40→42: `query.v1` +
`query.export.v1`): a single read-only SQL SELECT, or a natural-language
question compiled to SQL server-side (the compiled statement returns in
`data.sql`; an uncompilable question errors instead of guessing), runs over
three per-request virtual tables — `files` (one row per file+collection,
with `metadata`/`source_metadata` JSON columns), `entities`, and
`segment_entities` (each file's MOST RECENT completed extraction only) —
so where `probe`/`ask` find content semantically, `query` counts, groups,
and joins it. Surface: positional question or `--sql` (exactly one),
repeatable `--in` collection scopes (up to 20), `--dry-run`
(validate/compile + output columns, no execution, reduced cost),
`--max-rows` (default 1000, max 10000; `data.truncated` on cap), `--export
csv|jsonl` (server-side background export → gzipped download to `-o` /
`tinycloud-output/exports/`; `--background` returns `pending` with a `query
show` next-hint), and free subcommands `schema` (virtual tables + each
collection's extracted fields/extract_schema — the taught always-first
step) / `list` / `show <id>` (`-o` downloads a completed export while its
24h link lives) / `cancel <id>` (aborts an in-flight export and refunds).
Sync SQL bills 2 credits, NL 4, dry-run 1–2, exports reserve 4 (+1/100MB);
schema/list/show/cancel are free, and failed runs auto-refund. `query` is
also a workflow step node and an agent tool (it joins the LLM tool set,
unlike `login`). Because the skill teaches the verb, the floor was raised
to 0.3.17 (same merge-after-CDN gate — the dist PR merges only after CDN
`channels.stable` = 0.3.17). The host-level `profile` verb and the leading global flags `--home`/`--profile`
(also `$TINYCLOUD_HOME`; 0.3.3+) relocate state and are intentionally absent
from `commands --json` — like the launcher's install/update, they're CLI/host
concerns, not video operations.
Expand Down
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ The npm package is a small launcher: on first run it downloads the matching
platform distribution from Cloudglue's CDN (cached under
`~/.tinycloud/versions/<version>/`), verifies its checksum, and execs the real
binary. The package version pins the binary version, so
`npx @cloudglue/tinycloud@0.3.16` always runs tinycloud 0.3.16. It also adds two
`npx @cloudglue/tinycloud@0.3.17` always runs tinycloud 0.3.17. It also adds two
wrapper commands:

```bash
tinycloud install --version 0.3.16 # pre-download a version
tinycloud install --version 0.3.17 # pre-download a version
tinycloud install --latest # install latest stable and pin to it
tinycloud update # move to latest stable, prune old versions
```
Expand Down Expand Up @@ -126,6 +126,7 @@ go to stderr) — pass `--json`.
| `search` | Keyword search over cached video context |
| `probe` | Semantic moment/video search over a Cloudglue scope |
| `ask` | Grounded Q&A over one or more videos |
| `query` | Analytical SQL / natural-language queries over collection structured data (0.3.17+) |
| `clip` | ffmpeg-backed cut, thumbs, stitch, transcode, burn, split, audio, info |
| `grab` | Download a remote video (YouTube, TikTok, Loom, direct) |
| `face` | Detect faces in a video, or match/search a known face, ranked by similarity |
Expand Down Expand Up @@ -153,6 +154,8 @@ tinycloud caption ./demo.mp4 --format srt --transcript --json
tinycloud clip cut ./demo.mp4 --start 12 --end 28 -o clip.mp4 --json
# Grounded Q&A over one or more videos
tinycloud ask "What objections came up?" --in ./demo.mp4 --json
# Analytics over a collection — SQL or plain English (0.3.17+)
tinycloud query "how many videos per source platform?" --in collection:col_123 --json
# Detect faces, or match a known face against a video (0.3.4+; query image: JPEG/PNG)
tinycloud face match ./person.jpg ./demo.mp4 --max-faces 10 --json
```
Expand All @@ -171,7 +174,10 @@ tinycloud ask "What did customers object to?" --in collection:col_123 --json

`media-descriptions` backs `ask`/`probe`/`search`, `face-analysis` backs
`face list`/`face search`, and `entities` (created with `--prompt`/`--schema`)
backs `library collections entities`.
backs `library collections entities`. Any collection is also queryable with
`query` (0.3.17+) — read-only SQL or natural language over its files,
metadata, and extracted entities (`tinycloud query schema` shows what's
queryable).

`tinycloud commands --json` is the authoritative, machine-readable list of
every command and flag. Full per-verb flags and cost classes:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cloudglue/tinycloud",
"version": "0.3.16",
"version": "0.3.17",
"description": "Agent CLI for deep video and image work, by Cloudglue. Downloads the tinycloud binary on first run.",
"bin": {
"tinycloud": "bin/tinycloud.js"
Expand Down
26 changes: 24 additions & 2 deletions skills/tinycloud/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ Full schema and error codes: [reference/envelope.md](reference/envelope.md).

## 2. Core verbs (cheat sheet)

Cloud verbs (`watch see extract probe ask publish face`) call the Cloudglue API
using the configured key — usage is billed per the
Cloud verbs (`watch see extract probe ask query publish face`) call the
Cloudglue API using the configured key — usage is billed per the
[rate card](https://app.cloudglue.dev/home/billing/rate-card). `search clip
setup` are local and free; `grab jobs` are network-only.
`tinycloud commands --json` is the authoritative command/flag list.
Expand Down Expand Up @@ -93,6 +93,15 @@ tinycloud probe "renewal call" --in collection:col_123 --scope file \
--filter "source_metadata.parties.email~=%@acme.com" --json # filter by stored fields (0.3.15+)
tinycloud ask "What objections came up?" --in ./demo.mp4 --json

# MEASURE things (0.3.17+): analytics over collection structured data — SQL or plain English.
# probe/ask FIND content; query COUNTS/GROUPS/JOINS it (files + entities + metadata).
tinycloud query schema --in collection:col_123 --json # always first: tables + extracted fields
tinycloud query "how many videos per source platform?" --in collection:col_123 --json # NL → SQL (compiled stmt in data.sql)
tinycloud query --sql "SELECT source, COUNT(*) AS n FROM files GROUP BY source ORDER BY n DESC" \
--in collection:col_123 --json # SQL directly (cheaper)
tinycloud query --sql "SELECT * FROM files ORDER BY filename" --in collection:col_123 \
--export csv --json # full result → gzipped download

# Local editing (free, ffmpeg-backed)
tinycloud clip info ./demo.mp4 --json
tinycloud clip cut ./demo.mp4 --start 12 --end 28 -o ./tinycloud-output/clip.mp4 --json
Expand Down Expand Up @@ -123,6 +132,7 @@ tinycloud ask "what's discussed?" --in collection:col_desc --json #
tinycloud face search ./person.jpg --in collection:col_faces --json # face-analysis → face list / face search
tinycloud library collections entities col_ents ./demo.mp4 --json # entities → collections entities
tinycloud probe "kickoff" --in collection:col_meta --scope file --json # metadata (free, no processing) → probe --scope file / ask
tinycloud query "top entities by file count?" --in collection:col_ents --json # ANY type → query for analytics (count/group/join, 0.3.17+)
tinycloud library collections remove cloudglue://files/<id> --from col_desc --json
tinycloud library collections delete col_desc --json

Expand Down Expand Up @@ -202,6 +212,18 @@ Authoring your own recipes: [reference/workflow-authoring.md](reference/workflow
collection:col_…`), and a `metadata` collection is file-level — probe it
with `--scope file` (segment scope errors). `source_metadata.*` filters are
file-level facts too, so pair them with `--scope file`.
- `query` (0.3.17+) is for analytics, not search: when the task is to COUNT,
GROUP, rank, or join across a collection ("how many…", "which … most",
"total hours per host"), reach for `query`, not `probe`/`ask`. Run `query
schema` first — the `entities`/`segment_entities` tables hold each file's
LATEST completed extraction only, and a `metadata` collection has no
extraction at all (query its `files.metadata` / `files.source_metadata`
JSON columns). Exactly one of a positional question or `--sql` per run; an
uncompilable question errors instead of guessing — write the SQL yourself
for deep nested-JSON work. Sync results cap at `--max-rows` (default 1000);
`data.truncated: true` means switch to `--export csv|jsonl`. Runs bill per
the rate card (SQL cheaper than NL; `--dry-run` cheaper still), while
`schema`/`list`/`show`/`cancel` are free.
- `workflow status` / `workflow resume` are not implemented in 0.3.x; treat
`paused`/`partial` as terminal and surface `resume` metadata to the user.
- `--no-upload` / `--no-download` make commands refuse cloud upload / local
Expand Down
12 changes: 12 additions & 0 deletions skills/tinycloud/reference/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ connector?" or an envelope field needs explaining.
or processing the media — free to index, no processing configs. Query with
`probe --scope file` (optionally `--filter` on `source_metadata.*` /
`metadata.*` paths) or `ask`; feature id `library.collections.metadata.v1`.
- **Structured query (0.3.17+)** — an analytical read-only SQL `SELECT` (or a
natural-language question compiled to SQL server-side) run by `tinycloud
query` over a collection's structured data; features `query.v1` /
`query.export.v1`. Complements semantic search: `probe`/`ask` FIND
content, `query` MEASURES it (counts, group-bys, joins). Runs are stored
(`query list`/`show`) and large results export to gzipped CSV/JSONL.
- **Virtual tables** — the three per-request tables a structured query sees:
`files` (one row per file+collection: attributes plus `metadata` and
`source_metadata` JSON columns), `entities` (file-level extracted fields),
and `segment_entities` (segment-level entities with timestamps). Built from
each file's most recent completed extraction; discover the exact columns
and extracted fields with `tinycloud query schema --in collection:col_…`.
- **Source metadata** — the provider-supplied fields a connector attaches to
a synced file (`source_metadata`: title, participants, dates, tags, AI
summary; Iconik adds `iconik_metadata.<Field>` custom fields). Peek it
Expand Down
11 changes: 9 additions & 2 deletions skills/tinycloud/reference/pipelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ tinycloud search "pricing" --in ./demo.mp4 --json
- `--refresh` → force recompute (spends even on cache hits).
- `--no-cache` → don't persist results (still spends).
- These four flags exist on `watch`, `extract`, `caption`, and `workflow`
only — `ask`/`probe` always go to the cloud (use `search` for a free
cached lookup).
only — `ask`/`probe`/`query` always go to the cloud (use `search` for a
free cached lookup; `query show <id>` re-fetches a stored query run for
free).
- `meta.cache` in every envelope tells you what was reused vs written.

## Worked examples
Expand Down Expand Up @@ -122,6 +123,12 @@ tinycloud library collections add ./interview.mp4 --to col_123 --json # →
tinycloud library collections show col_123 --json # poll files[].status → completed
tinycloud library collections entities col_123 ./interview.mp4 --json # structured entities (video + segment level)

# Analytics across any collection (0.3.17+) — count/group/join what was extracted
tinycloud query schema --in collection:col_123 --json # what's queryable (always first)
tinycloud query "which people appear in the most videos?" --in collection:col_123 --json
tinycloud query --sql "SELECT value_text AS person, COUNT(DISTINCT file_id) AS files \
FROM entities WHERE field='people' GROUP BY 1 ORDER BY 2 DESC" --in collection:col_123 --json

# Already-built collection: mirror description/transcript artifacts locally for free `search`
tinycloud library collections sync col_123 --artifacts descriptions,transcripts --json
tinycloud search "discount" --in collection:col_123 --json
Expand Down
80 changes: 78 additions & 2 deletions skills/tinycloud/reference/verbs.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ every verb. Regenerate doubts from it instead of trusting prose.
| `search` | local | no | Local keyword search over cached context |
| `probe` | cloud | yes | Semantic moment/video search over a Cloudglue-ready scope |
| `ask` | cloud | yes | Grounded Q&A over one or more videos |
| `query` | cloud | yes | Analytical SQL / natural-language queries over collection structured data (0.3.17+) |
| `clip` | local | no | Cuts, thumbs, audio, stitch, split, transcode, burn, explore |
| `grab` | network | no | Download a remote video (YouTube, TikTok, Loom, direct) |
| `face` | cloud | yes | Detect faces in a video, or match/search a query face (0.3.4+) |
Expand Down Expand Up @@ -187,6 +188,76 @@ tinycloud ask "<question>" --in <source|collection:col_…|all>

Never pass `--background` to `ask`.

### query — structured analytics over collections (cloud, 0.3.17+)

```bash
tinycloud query "<question>" --in collection:col_… [--in collection:col_…] # NL → SQL
tinycloud query --sql "SELECT …" --in collection:col_… [--max-rows <n>] [--dry-run]
tinycloud query "<question-or---sql>" --in collection:col_… --export csv|jsonl [-o <path>] [--background]
tinycloud query schema --in collection:col_… # ALWAYS first: what's queryable
tinycloud query list [--status completed|failed|in_progress|cancelled] [--limit <n>] [--offset <n>]
tinycloud query show <query-id> [-o <path>] # re-fetch a stored run; -o downloads an export
tinycloud query cancel <query-id> # abort an in-flight export (refunds)
```

Where `probe`/`ask` FIND content semantically, `query` MEASURES it (features
`query.v1`/`query.export.v1`): a single read-only SQL `SELECT` — or a plain-
English question compiled to SQL server-side — over three virtual tables
built per request from the `--in` collections (repeatable, up to 20; joins
across collections work):

- `files` — one row per (file, collection): `filename`, `title`, `uri`,
`source`, `created_at`, `bytes`, `duration_seconds`, `width`/`height`,
`has_audio`, plus `metadata` (user metadata) and `source_metadata`
(connector fields) as JSON columns.
- `entities` — file-level extracted fields as (`field`, `value`,
`value_text`) rows.
- `segment_entities` — segment-level entities JSON with
`segment_index`/`start_time`/`end_time`.

The entity tables reflect each file's **most recent completed extraction
only** (re-extraction replaces rows — no double counting), and files without
extractions still appear in `files` — so `LEFT JOIN`, always on **both**
`file_id` and `collection_id` (`USING (file_id, collection_id)`). A
`metadata` collection has no extraction (`extract_schema: null`) — query its
`files.metadata`/`files.source_metadata` columns with
`json_extract`/`json_extract_string`.

**Run `query schema --in collection:col_… --json` before writing SQL** — it
returns the table columns plus each collection's extracted field names,
levels (file vs segment), and verbatim `extract_schema`/`prompt`, i.e. the
JSON paths you need. Standard SQL works (JSON functions, CTEs, window
functions, `date_trunc`); DDL/DML, multiple statements, and
`ATTACH`/`COPY`/`SET`/`PRAGMA` are rejected.

Exactly one of the positional question or `--sql` per run. NL runs return
the compiled statement in `data.sql` — inspect, tweak, resubmit as `--sql`
(which also bills less). NL suits straightforward analytics (counts,
rankings, group-bys); a question that can't compile fails with a clear
error instead of guessing — write the SQL directly for deep nested-JSON
work. `--dry-run` validates/compiles and returns the effective SQL +
output columns without executing (reduced cost; can't combine with
`--export`).

Sync results return inline, capped by `--max-rows` (default 1000, max
10000) — `data.truncated: true` means narrow, aggregate, or export.
`--export csv|jsonl` streams the FULL result server-side to a gzipped
file (2 GB compressed cap; `--max-rows` is rejected with it — bound an
export with SQL `LIMIT` instead) and downloads it to `-o` (default
`./tinycloud-output/exports/`); add `--background` to get a `pending`
envelope immediately and poll `tinycloud query show <id>` (its `-o`
downloads once completed; the download link lives 24h — after that,
re-run the export). Runs are stored server-side: `list`/`show` browse
them (list rows omit columns/rows), `cancel` aborts an in-flight export
and refunds its reserved credits.

Billing (per the rate card): sync SQL and NL runs bill per query (NL >
SQL), `--dry-run` bills less, exports reserve credits + a size-based
component; `schema`/`list`/`show`/`cancel` are free. Failed runs are
refunded automatically. Server limits: 20 collections and ~2000 files in
scope per query, 15s execution, 1 concurrent query per account (excess →
429; just retry).

### clip — local derivatives (free, ffmpeg-backed)

Subcommands: `cut thumbs stitch transcode burn extract-audio split info explore`
Expand Down Expand Up @@ -312,6 +383,10 @@ same `create → add → poll show → query → delete` lifecycle):
| `rich-transcripts` | `collections sync --artifacts transcripts` |
| `metadata` (0.3.15+, free) | `probe --scope file` / `ask` |

Every type is additionally queryable with `query` (0.3.17+) for analytics —
counts, group-bys, joins over file attributes, user/connector metadata, and
(for `entities` collections) the extracted fields; see the `query` section.

`collections entities <col> <source>` returns a video's extracted entities
(video- and segment-level, `--limit`/`--offset`) from an `entities` collection.
For a one-off per-video pull without standing up a collection, `extract` returns
Expand Down Expand Up @@ -638,8 +713,9 @@ Output: `--json` (force JSONL envelopes), `--pretty` (one JSON array),

Cache — on `watch`, `see`, `extract`, `caption`, `face`, and `workflow` only:
`--refresh` (recompute), `--no-cache` (no persistence), `--cached` (reuse
exact-match history). `ask`/`probe` always call the cloud; use `search` for a
free cached lookup.
exact-match history). `ask`/`probe`/`query` always call the cloud; use
`search` for a free cached lookup (and `query show` to re-fetch a stored
query run for free).

Upload/download refusal — on every verb that resolves a source:
`--no-upload` (refuse cloud upload → `needs_upload`) on `watch`/`see`/`extract`/
Expand Down
Loading
Loading