From 6eadf3e9c565b52db05b135283bf32ba126e9b85 Mon Sep 17 00:00:00 2001 From: Himanshu Gupta Date: Mon, 17 Aug 2026 17:02:18 +0530 Subject: [PATCH] Document CLI and skills onboarding --- README.md | 59 +++++++++++++---- web/app/_directions/craft-code.tsx | 88 ++++++++++++++---------- web/app/_directions/craft-nav.tsx | 3 +- web/app/_directions/craft.tsx | 55 ++++++++++----- web/app/craft.css | 103 +++++++++++++++++++++-------- 5 files changed, 214 insertions(+), 94 deletions(-) diff --git a/README.md b/README.md index 2e1fba4..df82187 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,14 @@

Turn videos into useful context for LLMs and AI agents.

all-things-youtube npm version + video2ctx CLI npm version Node.js 22 Apache License 2.0

Live product · Documentation · + Agent Skills and CLI · npm library · Developer setup

@@ -38,14 +40,43 @@ Available now: ## Choose how to use it -| If you need… | Start here | -| -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -| A visual research workspace | [Open video2ctx](https://www.video2ctx.dev) | -| A hosted API for an agent or application | [Create an API key](https://www.video2ctx.dev/dashboard/developer), then use the [interactive API reference](https://docs.video2ctx.dev/api-reference/introduction) | -| Direct YouTube data from a supported agent | Use [`youtube-direct`](./.agents/skills/youtube-direct) with no video2ctx account, API key, hosted service, or npm installation | +| If you need… | Start here | +| -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| A visual research workspace | [Open video2ctx](https://www.video2ctx.dev) | +| A hosted API for an agent or application | [Create an API key](https://www.video2ctx.dev/dashboard/developer), then use the [interactive API reference](https://docs.video2ctx.dev/api-reference/introduction) | +| Direct YouTube data from a supported agent | Use [`youtube-direct`](./.agents/skills/youtube-direct) with no video2ctx account, API key, hosted service, or npm installation | | A hosted API directly from a supported agent | Install [`@video2ctx/cli`](./packages/video2ctx-cli), then use [`video2ctx-api`](./.agents/skills/video2ctx-api) for stateless reads or [`video2ctx-monitoring`](./.agents/skills/video2ctx-monitoring) for monitors | -| A server-side TypeScript YouTube client | Install [`all-things-youtube`](./packages/all-things-youtube/README.md) from npm | -| To contribute to or self-host the complete product | [Run the workspace locally](#run-the-workspace-locally) | +| A server-side TypeScript YouTube client | Install [`all-things-youtube`](./packages/all-things-youtube/README.md) from npm | +| To contribute to or self-host the complete product | [Run the workspace locally](#run-the-workspace-locally) | + +## Agent Skills and CLI + +For the complete hosted agent setup, install the CLI, authenticate, and add the companion skills: + +```bash +npm install --global @video2ctx/cli +video2ctx auth login +npx skills add devhims/video2ctx +video2ctx whoami --json +``` + +The CLI and skills are complementary. The CLI owns browser authentication, hosted transport, retries, credential storage, and machine-readable commands. The skills teach agents which route to choose and how to use each operation safely. + +The collection contains three skills with separate responsibilities: + +- **`youtube-direct`** handles one-off public YouTube search and extraction directly from the user's machine. It needs no video2ctx account, API key, hosted service, or npm package. +- **`video2ctx-api`** handles account and usage requests, managed hosted reads, and automatic fallback when a direct request fails. +- **`video2ctx-monitoring`** handles the stateful exception: recurring checks, schedules, alerts, and notification preferences. + +`youtube-direct` is self-contained. If direct, one-off public YouTube access is all you need, install the skills and select `youtube-direct`; the CLI and video2ctx account are not required: + +```bash +npx skills add devhims/video2ctx +``` + +The browser flow stores a revocable CLI session in private local configuration. For unattended environments, set `VIDEO2CTX_API_KEY` to a personal key instead. Never place credentials in prompts, logs, screenshots, or source control. + +After installation, an agent should use `youtube-direct` first for ordinary public one-off requests, continue through `video2ctx-api` automatically if direct access fails, and use `video2ctx-monitoring` only for recurring work. See the [`@video2ctx/cli` README](./packages/video2ctx-cli/README.md) and the [published skills](./.agents/skills) for the complete contracts. ## Under development @@ -210,9 +241,9 @@ For the complete request path and reliability model, see [`reference/engineering | [`platform/`](./platform) | TypeScript/Hono Cloudflare Worker with auth, API keys, billing, D1, R2, KV, AI, queues, workflows, and OpenAPI | | [`platform/youtube-processor/`](./platform/youtube-processor) | Private Node 22/Hono container for outbound YouTube operations and optional proxy egress | | [`packages/all-things-youtube/`](./packages/all-things-youtube) | Publishable normalized YouTube client and public TypeScript data model | -| [`packages/video2ctx-cli/`](./packages/video2ctx-cli) | Independently published CLI for device login and authenticated hosted API access | -| [`docs/`](./docs) | Public Mintlify documentation site | -| [`reference/`](./reference) | Internal architecture, design, deployment, and agent guidance | +| [`packages/video2ctx-cli/`](./packages/video2ctx-cli) | Independently published CLI for device login and authenticated hosted API access | +| [`docs/`](./docs) | Public Mintlify documentation site | +| [`reference/`](./reference) | Internal architecture, design, deployment, and agent guidance | | [`.github/workflows/ci.yml`](./.github/workflows/ci.yml) | Pull-request verification for the platform and web application | ## Configuration @@ -226,12 +257,12 @@ Local secret placeholders are documented in [`platform/.dev.vars.example`](./pla | `YOUTUBE_OAUTH_ENCRYPTION_KEY` | Platform | Encrypts stored YouTube refresh tokens | | `TURNSTILE_SECRET` | Platform | Protects selected production endpoints | | `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`, `STRIPE_PRO_PRICE_ID` | Platform | Subscription checkout and webhook processing | -| `UPSTASH_REDIS_REST_URL`, `UPSTASH_REDIS_REST_TOKEN` | Platform | Stores the anonymous landing-page rolling quota | -| `LANDING_RATE_LIMIT_SALT` | Platform | HMAC-hashes visitor IPs before they are used as Redis keys | +| `UPSTASH_REDIS_REST_URL`, `UPSTASH_REDIS_REST_TOKEN` | Platform | Stores the anonymous landing-page rolling quota | +| `LANDING_RATE_LIMIT_SALT` | Platform | HMAC-hashes visitor IPs before they are used as Redis keys | | `OUTBOUND_PROXY_URL` | Processor | Optional HTTP(S) proxy for outbound YouTube traffic | | `PLATFORM_API_BASE_URL` | Web | Overrides the platform origin; defaults to localhost in development and the public API in production | | `NEXT_PUBLIC_PLATFORM_API_BASE_URL` | Web | Browser-visible platform origin used by the anonymous landing-page inspection | -| `NEXT_PUBLIC_TURNSTILE_SITE_KEY` | Web | Browser-visible Turnstile site key used by the Scale inquiry form | +| `NEXT_PUBLIC_TURNSTILE_SITE_KEY` | Web | Browser-visible Turnstile site key used by the Scale inquiry form | Do not place production secrets in Git or build variables. Add Cloudflare runtime secrets interactively as described in [`reference/engineering/IMPLEMENTATION.md`](./reference/engineering/IMPLEMENTATION.md#cloudflare-setup). @@ -252,7 +283,7 @@ Common commands, run from the repository root: | `npm run docs:dev` | Preview the Mintlify documentation site locally | | `npm run docs:generate` | Regenerate the consumer OpenAPI file and internal endpoint inventory | | `npm run docs:check` | Fail when generated documentation artifacts are stale | -| `npm run docs:verify` | Validate the Mintlify build, links, and accessibility | +| `npm run docs:verify` | Validate the Mintlify build, links, and accessibility | Before opening a pull request, run: diff --git a/web/app/_directions/craft-code.tsx b/web/app/_directions/craft-code.tsx index 936deaf..b50c27a 100644 --- a/web/app/_directions/craft-code.tsx +++ b/web/app/_directions/craft-code.tsx @@ -1,19 +1,27 @@ 'use client'; import { useEffect, useRef, useState } from 'react'; +import { ChecksIcon, CopyIcon } from '@phosphor-icons/react'; import { ClipTabs } from './clip-tabs'; -/* One code moment, not a route table. - * - * The audience is a developer deciding whether this beats writing their own - * scraper, so exactly one honest example of each way in earns its place. Both - * samples are real: the bearer-token curl is the documented auth scheme, and - * the package call is `getTranscript` as the npm README actually exports it. - */ +/* One install surface for the supported agent and developer routes. Keep every + * command copyable as-is: this is onboarding, not a decorative code sample. */ -type Sample = 'curl' | 'node'; +type Sample = 'skills' | 'cli-skill' | 'curl' | 'node'; const SAMPLES: Record = { + skills: { + label: 'Agent Skills', + note: 'Choose any or all three skills. YouTube Direct works immediately without an account or hosted service.', + code: 'npx skills add devhims/video2ctx', + }, + 'cli-skill': { + label: 'CLI + Skill', + note: 'The CLI handles authenticated hosted commands. The companion skills teach agents when and how to use them.', + code: `npm install --global @video2ctx/cli +video2ctx auth login +npx skills add devhims/video2ctx`, + }, curl: { label: 'Hosted API', note: 'Any language, one request. Bearer auth with a key from the dashboard.', @@ -21,23 +29,19 @@ const SAMPLES: Record = { --header "Authorization: Bearer $VIDEO2CTX_API_KEY"`, }, node: { - label: 'npm package', + label: 'NPM Package', note: 'Server-side TypeScript, no key and no hosted service in the path.', - code: `import { getTranscript } from 'all-things-youtube'; - -const transcript = await getTranscript({ - videoId: 'S4tdkSVuxZA', - lang: 'hi', -}); - -console.log(transcript.translatedTo); // { languageCode: 'hi', name: 'Hindi' }`, + code: 'npm install all-things-youtube', }, }; -const TABS = (Object.keys(SAMPLES) as Sample[]).map((id) => ({ id, label: SAMPLES[id].label })); +const TABS = (Object.keys(SAMPLES) as Sample[]).map((id) => ({ + id, + label: SAMPLES[id].label, +})); export function CraftCode() { - const [sample, setSample] = useState('curl'); + const [sample, setSample] = useState('skills'); const active = SAMPLES[sample]; return ( @@ -50,18 +54,20 @@ export function CraftCode() { idPrefix='craft-code' label='Ways to call it' /> - -
-        {active.code}
-      
+
+
+          {active.code}
+        
+ +

{active.note}

@@ -86,13 +92,23 @@ function CopyButton({ text }: { text: string }) { }; return ( - ); } diff --git a/web/app/_directions/craft-nav.tsx b/web/app/_directions/craft-nav.tsx index 7bae0c5..689d1b8 100644 --- a/web/app/_directions/craft-nav.tsx +++ b/web/app/_directions/craft-nav.tsx @@ -9,7 +9,7 @@ const LINKS = [ { label: 'Pricing', href: '#pricing' }, { label: 'FAQ', href: 'https://api.video2ctx.dev/docs#tag/FAQ' }, { label: 'GitHub', href: 'https://github.com/devhims/video2ctx' }, - { label: 'NPM', href: 'https://www.npmjs.com/package/all-things-youtube' }, + { label: 'CLI + Skill', href: '#agent-setup', isNew: true }, ]; export function CraftNav() { @@ -56,6 +56,7 @@ export function CraftNav() { onClick={() => setOpen(false)} > {link.label} + {link.isNew ? NEW : null} ); })} diff --git a/web/app/_directions/craft.tsx b/web/app/_directions/craft.tsx index cf15d52..cd6e79d 100644 --- a/web/app/_directions/craft.tsx +++ b/web/app/_directions/craft.tsx @@ -25,14 +25,21 @@ const PARTS = [ { name: 'Search', detail: 'the way in when you have a question, not a link' }, ]; -/* Three equal doors. The API is one of them, not the product — the page reads - * as an endpoint vendor without this section. */ +/* Each route has a distinct boundary. Skills hold agent guidance, the CLI and + * hosted skills form one complementary setup, and the npm package is the + * direct TypeScript library. */ const WAYS = [ { - label: 'Workspace', - body: 'Collect moments into projects, ask questions across them, and monitor channels over time.', - action: 'Open the dashboard', - href: '/dashboard', + label: 'YouTube Direct', + body: 'Install the skills and agents can handle one-off public YouTube requests directly. No CLI, account, API key, or hosted service is required.', + action: 'Browse the skills', + href: 'https://github.com/devhims/video2ctx/tree/main/.agents/skills', + }, + { + label: 'CLI + Skill', + body: 'Install both for hosted agent work. The CLI handles browser authentication and stable commands; the skills provide routing and workflow guidance.', + action: '@video2ctx/cli', + href: 'https://www.npmjs.com/package/@video2ctx/cli', }, { label: 'Hosted API', @@ -41,11 +48,17 @@ const WAYS = [ href: 'https://docs.video2ctx.dev/api-reference/introduction', }, { - label: 'npm package', + label: 'NPM Package', body: 'A server-side TypeScript client for YouTube data, with no hosted service in the path.', action: 'all-things-youtube', href: 'https://www.npmjs.com/package/all-things-youtube', }, + { + label: 'Workspace', + body: 'Collect moments into projects, ask questions across them, and monitor channels over time.', + action: 'Open the dashboard', + href: '/dashboard', + }, ]; /* Plain-language trust, no invented metrics and no header names. */ @@ -133,8 +146,10 @@ export function CraftDirection() { structured context, with timestamps and links back to the source.

- Connect through the hosted API, MCP server, agent skill, or the{' '} - all-things-youtube npm package. + Start with the skills for direct work. Pair them with the{' '} + @video2ctx/cli for authenticated hosted operations, or use + the all-things-youtube npm package from server-side + TypeScript.

What comes back

    @@ -152,12 +167,16 @@ export function CraftDirection() {
    -
    +
    -

    Two lines from here to your agent.

    +

    Install once. Pick the right route.

    - The demo above and the call below hit the same data. Request - shapes, errors, and private project routes live in the reference. + YouTube Direct needs only the skill. Hosted agent work pairs the + CLI with the skills. Applications can use the API or npm library.

    @@ -167,10 +186,10 @@ export function CraftDirection() {
    -

    Three ways in.

    +

    Choose your route.

    - Same data, same source links. Pick whichever fits where you are - working. + Each surface has a clear job, whether an agent, application, or + person is doing the work.

      @@ -245,6 +264,10 @@ export function CraftDirection() { API reference {' '} ·{' '} + + @video2ctx/cli + {' '} + ·{' '} all-things-youtube diff --git a/web/app/craft.css b/web/app/craft.css index 07e733c..872cec9 100644 --- a/web/app/craft.css +++ b/web/app/craft.css @@ -123,6 +123,9 @@ html:has(.craft) body { .craft-nav-links a { padding-block: var(--space-xs); color: var(--ink-muted); + display: inline-flex; + align-items: center; + gap: 0.25rem; font-size: 0.75rem; font-weight: 530; text-decoration: none; @@ -130,6 +133,18 @@ html:has(.craft) body { transition: color var(--control) var(--out); } +.craft-nav-new { + padding: 0.1rem 0.28rem; + border-radius: 0.2rem; + background: var(--accent); + color: var(--accent-ink); + font-size: 0.58rem; + font-weight: 800; + line-height: 1.15; + letter-spacing: 0.025em; + transform: translateY(-0.26rem); +} + .craft-nav-actions { display: flex; align-items: center; @@ -1487,16 +1502,18 @@ html:has(.craft) body { } .craft-code-head { - display: flex; - align-items: center; - justify-content: space-between; - flex-wrap: wrap; - gap: var(--space-md); + display: block; +} + +.craft-code-frame { + margin-top: var(--space-lg); + position: relative; } .craft-code-block { - margin: var(--space-lg) 0 0; - padding: var(--space-lg); + margin: 0; + padding: var(--space-lg) calc(var(--space-lg) + 2.75rem) var(--space-lg) + var(--space-lg); border: 1px solid var(--rule); border-radius: var(--radius-home-lg); background: oklch(12.5% 0.006 75); @@ -1519,22 +1536,25 @@ html:has(.craft) body { font-size: 0.8rem; } -/* Both labels sit stacked in the same grid cell and crossfade in place, so the - * button never resizes mid-press. Success is quiet — no toast, no bounce. */ +/* The copy control belongs to the code surface it acts on. Both icons occupy + * the same grid cell, so success feedback never changes the button's size. */ .craft-copy { + width: 2.25rem; min-height: 2.25rem; - padding-inline: var(--space-md); + padding: 0; border: 1px solid var(--rule-strong); border-radius: var(--radius-home-pill); - background: transparent; + background: var(--paper-raised); color: var(--ink-soft); cursor: pointer; display: inline-grid; place-items: center; - font-size: 0.75rem; - font-weight: 600; + position: absolute; + z-index: 1; + inset: var(--space-sm) var(--space-sm) auto auto; transition: transform var(--press) var(--out), + border-color var(--control) var(--out), color var(--control) var(--out); } @@ -1542,26 +1562,29 @@ html:has(.craft) body { transform: scale(0.97); } -.craft-copy > span[aria-hidden] { +.craft-copy-icon { grid-area: 1 / 1; + display: grid; + place-items: center; transition: opacity var(--control) var(--out), - filter var(--control) var(--out); + transform var(--control) var(--out); } -.craft-copy > span[aria-hidden]:nth-child(2), -.craft-copy[data-copied='true'] > span[aria-hidden]:nth-child(1) { +.craft-copy-icon:nth-of-type(2), +.craft-copy[data-copied='true'] .craft-copy-icon:nth-of-type(1) { opacity: 0; - filter: blur(2px); + transform: scale(0.72); } .craft-copy[data-copied='true'] { + border-color: color-mix(in oklch, var(--accent) 48%, var(--rule-strong)); color: var(--accent); } -.craft-copy[data-copied='true'] > span[aria-hidden]:nth-child(2) { +.craft-copy[data-copied='true'] .craft-copy-icon:nth-of-type(2) { opacity: 1; - filter: none; + transform: scale(1); } .craft-sr { @@ -1583,10 +1606,14 @@ html:has(.craft) body { padding: 0; list-style: none; display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-xl); } +.craft-ways li:first-child { + grid-column: 1 / -1; +} + .craft-ways li { min-width: 0; padding-top: var(--space-lg); @@ -2014,6 +2041,10 @@ html:has(.craft) body { line-height: 1.65; } +.craft-agent-setup { + scroll-margin-top: 6rem; +} + /* ------------------------------------------------------------ hover only */ /* Touch devices fire hover on tap, so every hover state is gated. */ @@ -2127,6 +2158,10 @@ html:has(.craft) body { font-size: 0.82rem; } + .craft-nav-new { + transform: translateY(-0.2rem); + } + .craft-nav-menu { display: grid; } @@ -2144,6 +2179,10 @@ html:has(.craft) body { min-height: 0; } + .craft-ways li:first-child { + grid-column: auto; + } + .craft-pricing-description { min-height: 0; } @@ -2187,15 +2226,11 @@ html:has(.craft) body { } .craft-code-block { - padding: var(--space-md); + padding: var(--space-md) calc(var(--space-md) + 2.75rem) var(--space-md) + var(--space-md); font-size: 0.72rem; } - .craft-code-head { - align-items: stretch; - flex-direction: column; - } - .craft-form { grid-template-columns: minmax(0, 1fr); border-radius: var(--radius-home-lg); @@ -2212,6 +2247,20 @@ html:has(.craft) body { grid-auto-columns: unset; } + .craft-code .craft-tablist { + padding: var(--space-3xs); + border-radius: var(--radius-home-lg); + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--space-3xs); + } + + .craft-code .craft-tablist button { + width: 100%; + min-width: 0; + padding-inline: var(--space-sm); + border-radius: var(--radius-home-md); + } + /* The clipped duplicate assumes a horizontal row; on a stacked list it would * clip the wrong axis, so it is retired and colour handles the active state. */ .craft-tablist-active {