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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@valyu/cli",
"version": "1.1.0",
"version": "1.2.0",
"description": "The search CLI for knowledge workers",
"license": "MIT",
"repository": {
Expand Down
36 changes: 33 additions & 3 deletions skills/valyu-cli/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ description: >
license: MIT
metadata:
author: valyu
version: "1.1.0"
version: "1.2.0"
homepage: https://valyu.ai
source: https://github.com/valyuAI/valyu-cli
inputs:
Expand All @@ -26,6 +26,7 @@ references:
- references/deepresearch.md
- references/workflows.md
- references/auth.md
- references/account.md
- references/error-codes.md
---

Expand All @@ -51,7 +52,12 @@ valyu
│ ├── create / update / delete # manage your org's templates (file-based)
├── batch # parallel deepresearch jobs with shared config
├── sources # list available proprietary data sources
├── login / logout / whoami # auth
├── account # self-service: keys, balance, top-ups, datasets
│ ├── whoami # org, tier, calling key + budget
│ ├── keys list / create / revoke / rotate # create --cap = budget-capped agent key
│ ├── balance / topup <amount> # credits (topup charges card on file, else checkout URL)
│ ├── datasets # tier entitlements
├── login / logout / whoami # auth (login defaults to browser device flow)
├── doctor # setup + connectivity check
├── upgrade # detect install source, show / run upgrade command
└── open # open platform / docs / API keys in browser
Expand Down Expand Up @@ -79,6 +85,26 @@ valyu deepresearch update "$ID" "Also cover regulatory risk" # mid-flight stee
valyu deepresearch create "..." --webhook-url https://your-app.com/hook -q
```

## Self-provisioning (zero-to-first-call for agents)

`valyu login` defaults to the **browser device flow** - it mints and stores a
scoped `val_` key, so an agent never has to ask a human to paste a secret. In
`--json` mode it streams line-delimited events (`device_code` → `auth_waiting` →
`auth_success`); surface `verification_uri_complete` to a human and read lines
until `auth_success`.

```bash
valyu login --json # drive device flow, parse NDJSON events
valyu account balance -q # check credit; topup if zero
valyu account keys create --name agent --cap 5 -q # budget-capped sub-agent key
valyu search web "..." -q
```

**Budget-capped agent keys** are the headline `account` pattern: `--cap 5` mints a
key that can spend at most $5 before the data plane returns `402 spend_cap_reached`.
The secret is shown exactly once. Requested scopes/cap can never exceed
the calling key's own (server-enforced). Full details: [references/account.md](references/account.md).

## Global flags

| Flag | Description |
Expand Down Expand Up @@ -203,6 +229,9 @@ valyu deepresearch create \
| Discover available research templates | `valyu workflows list` |
| Many parallel deepresearch tasks with shared config | `valyu batch create ...` |
| Discover available proprietary data sources | `valyu sources list` |
| Provision a budget-capped key for a sub-agent | `valyu account keys create --name agent --cap 5` |
| Check credit balance / add credits | `valyu account balance` / `valyu account topup 25` |
| See what datasets this key can reach (replan on 403) | `valyu account datasets` |
| Upgrade the CLI itself | `valyu upgrade` |

## Search types (for `valyu search <type>`)
Expand Down Expand Up @@ -247,5 +276,6 @@ valyu deepresearch create \
- **Search (web / paper / finance / sec / bio / patent / economics / news)** → [references/search.md](references/search.md)
- **AI answer (`answer`)** → [references/answer.md](references/answer.md)
- **URL content extraction (`contents`)** → [references/contents.md](references/contents.md)
- **Auth, profiles, login** → [references/auth.md](references/auth.md)
- **Auth, profiles, login (device flow)** → [references/auth.md](references/auth.md)
- **Account: keys, budget caps, balance, top-ups, datasets** → [references/account.md](references/account.md)
- **Error codes** → [references/error-codes.md](references/error-codes.md)
115 changes: 115 additions & 0 deletions skills/valyu-cli/references/account.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# valyu account

Self-service account management: API keys (with budget caps),
credit balance, top-ups, and dataset entitlements. Every subcommand is
`--json`-capable and human-pretty by default. Errors use the RFC 9457 + recovery
envelope (`code`, `hint`, `recovery`) so agents can branch and self-heal.

```
valyu account
├── whoami # org, tier, calling key + its budget
├── keys
│ ├── list # all keys for the org (default)
│ ├── create --name <n> [...] # mint a key (optionally capped)
│ ├── revoke <id> # revoke immediately (irreversible)
│ └── rotate <id> # revoke old secret, mint a new one (same settings)
├── balance # credit balance + PAYG usage + tier
├── topup <amount> # add credits (charges card on file, else checkout link)
└── datasets # what this key/org can reach + tier ladder
```

All commands resolve auth like the rest of the CLI: `--api-key` > `VALYU_API_KEY`
> stored profile (`valyu login`). The calling key must hold the relevant scope
(`keys:read`/`keys:write`/`billing:read`/`billing:write`).

## The budget-capped agent key (headline pattern)

Provision a sub-key a sub-agent can burn through without risking the whole balance:

```bash
valyu account keys create --name agent --cap 5
```

```
Created key agent val_a1b2c3d4
id <uuid>
scopes none
budget $5.00 total spend cap

Save this secret now - it is shown only once:

val_............................................................

```

The secret (`api_key`) is returned exactly once. Hand it to the sub-agent as
`VALYU_API_KEY`; when spend hits the cap the data plane returns
`402 spend_cap_reached`. With no `--scopes` the key is **search-only**: it can
call the data plane (search access is implicit in holding a valid key) and read
its own `whoami`, but cannot manage keys or billing. That is the right default
for an agent key.

Richer example - monthly cap, still search-only:

```bash
valyu account keys create \
--name research-bot --cap 50 --window monthly --json
```

Add `--scopes` only when the key needs to **manage** the account (read it, mint
or rotate keys, move money):

```bash
valyu account keys create \
--name ops --scopes account:read,keys:read,keys:write --json
```

### `keys create` options

| Flag | Description |
|------|-------------|
| `--name <name>` | Required. Human-readable key name (unique per org). |
| `--cap <usd>` | Spend cap in USD. Omit for uncapped (subject to your own remaining cap). |
| `--window <total\|monthly>` | Cap window (default `total`). `monthly` resets each month. |
| `--scopes <a,b>` | Comma-separated **management** scopes: `account:read`, `keys:read`, `keys:write`, `billing:read`, `billing:write`. Default none (search-only); search/data access is automatic. Must be a subset of yours. |
| `--type <user\|service_account>` | Key type (default `user`). |
| `--rate-limit <rpm>` | Rate limit in requests per minute. |
| `--expires <iso>` | Expiry as an ISO 8601 timestamp. |

**Escalation invariants** (enforced server-side): requested `scopes` and `cap`
can never exceed the calling key's own. Violations return `403`
`scope_escalation` / `cap_escalation` with a `recovery`
block showing your ceiling.

## balance & topup

```bash
valyu account balance -q
# {"credit_balance_usd":42.18,"payg_usage_usd":7.82,...,"tier":"tier_2"}

valyu account topup 25
# Charges your card on file and lands the credits immediately:
# {"charged":true,"amount_usd":25,...} -> "✓ Added $25 to your balance"
# If there's no card on file, it returns a Stripe Checkout link instead:
# {"checkout_url":"https://...","amount_usd":25} -> a human completes payment;
# credits land via the Stripe webhook.
```

`topup` requires the `billing:write` scope (opt-in at device-login consent).
Add `--open` to open the checkout URL in a browser (only applies when a checkout
link is returned).

## datasets

```bash
valyu account datasets -q # available_datasets + tier ladder
```

`datasets` is the replanning surface: on a `403 tier_insufficient` an agent reads
`available_datasets` to pick a reachable source instead.

## JSON for agents

Add `-q` (or `--json`) to any subcommand for machine output. On error the process
exits 1 and prints `{"error":{"message","code","hint","retryable","recovery"}}` -
branch on `code`, follow `recovery` (e.g. `topup_url`, `increase_cap_url`).
72 changes: 65 additions & 7 deletions skills/valyu-cli/references/auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,69 @@ Authentication and credential management.

## login

Store a Valyu API key.
Authenticate the CLI. **By default this runs the browser device flow** (RFC 8628):
it mints a fresh, scoped `val_` API key for your org and stores it - nothing to
copy-paste. Use `--key` for manual / CI logins.

```
valyu login [--key <key>] [--profile <name>]
valyu login [--device] [--no-browser] [--scope <scopes>] [--profile <name>]
valyu login --key <key> [--profile <name>]
```

| Flag | Description |
|------|-------------|
| `--key <key>` | API key to store (required in non-interactive mode) |
| `--key <key>` | Authenticate with an existing API key (manual / CI mode) |
| `--device` | Force the device flow (default when `--key` is omitted) |
| `--no-browser` | Print the verification URL + code instead of opening a browser |
| `--scope <scopes>` | Space-separated management scopes to request (default: `account:read keys:read keys:write billing:read`; search/data access is automatic) |
| `--profile <name>` | Profile name (default: "default") |

**Interactive:** Shows link to platform.valyu.ai/user/account/apikeys, then prompts for key.
**Device flow (default, recommended):**

**Non-interactive (CI/agents):**
```bash
valyu login
# 1. Prints a user code (e.g. WDJB-MJHT) and opens platform.valyu.ai/device
# 2. You log in + approve in the browser (choose scopes + optional budget cap)
# 3. The CLI mints + stores a scoped val_ key
```

The minted key's id is stored alongside it so `valyu logout` can revoke it
server-side. `billing:write` is NOT requested by default - tick it on the consent
screen if the key needs to move money (top-ups).

**Agent onboarding (line-delimited JSON events):** with `--json` (or in a non-TTY)
`login` streams one JSON object per line so an agent can drive the flow:

```bash
valyu login --json
{"event":"device_code","user_code":"WDJB-MJHT","verification_uri":"https://platform.valyu.ai/device","verification_uri_complete":"https://platform.valyu.ai/device?user_code=WDJB-MJHT","expires_in":900,"interval":5}
{"event":"auth_waiting","status":"authorization_pending","attempt":1}
{"event":"auth_success","profile":"default","valyu_key_id":"...","key_prefix":"val_a1b2c3d4","scope":"...","config_path":"..."}
```

Surface `verification_uri_complete` (or `user_code`) to a human, then keep reading
lines until `auth_success` (or `auth_error`). The CLI honours the server's
`interval` / `slow_down` / `expires_in` automatically.

**Manual / CI:**
```bash
valyu login --key val_xxx --profile production
# → {"success":true,"config_path":"...","profile":"production"}
```

## logout

Removes stored credentials locally by default (like `gh`/`aws`/`docker`). The
device-minted key keeps working until it expires or is revoked; pass `--revoke`
to also kill it server-side.

```
valyu logout [--profile <name>] [--yes]
valyu logout [--profile <name>] [--revoke] [--yes]
```

- Without `--profile`: removes all credentials
- With `--profile`: removes only that profile
- `--revoke`: also revoke the device-minted key server-side (best-effort)
- `--yes`: skips confirmation prompt

## whoami
Expand Down Expand Up @@ -85,8 +121,30 @@ valyu search web "query" --api-key val_xxx -q
{
"active_profile": "default",
"profiles": {
"default": { "api_key": "val_xxx" },
"default": { "api_key": "val_xxx", "valyu_key_id": "uuid" },
"production": { "api_key": "val_yyy" }
}
}
```

`valyu_key_id` is only present for device-flow logins (it lets `logout` revoke the
key server-side). Manual `--key` logins omit it - backward compatible.

## Account management

Once logged in, manage keys, budget, and usage with `valyu account ...`. See
[account.md](account.md). The headline pattern is provisioning a budget-capped key
for a sub-agent:

```bash
valyu account keys create --name agent --cap 5
```

## Custom base URL

The account + device endpoints default to `https://api.valyu.ai/v1/account`.
Point the CLI at a different deployment with `VALYU_ACCOUNT_API_BASE`:

```bash
VALYU_ACCOUNT_API_BASE=https://your-account-api.example.com/v1/account valyu login
```
4 changes: 3 additions & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { deepresearchCommand } from './commands/deepresearch/index.js';
import { workflowsCommand } from './commands/workflows/index.js';
import { batchCommand } from './commands/batch/index.js';
import { whoamiCommand } from './commands/whoami.js';
import { accountCommand } from './commands/account.js';
import { doctorCommand } from './commands/doctor.js';
import { openCommand } from './commands/open.js';
import { upgradeCommand } from './commands/upgrade.js';
Expand Down Expand Up @@ -98,6 +99,7 @@ ${pc.dim('Examples:')}
.addCommand(workflowsCommand)
.addCommand(batchCommand)
.addCommand(sourcesCommand)
.addCommand(accountCommand)
.addCommand(whoamiCommand)
.addCommand(doctorCommand)
.addCommand(openCommand)
Expand All @@ -107,7 +109,7 @@ program
.parseAsync()
.then(() => {
const ran = program.args[0];
if (ran === 'login' || ran === 'logout' || ran === 'upgrade') return;
if (ran === 'login' || ran === 'logout' || ran === 'upgrade' || ran === 'account') return;
return checkForUpdates().catch(() => {});
})
.catch((err) => {
Expand Down
Loading