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
33 changes: 33 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,39 @@ README.md
See `docs/publishing.md`: GitHub release automation prepares Claude, OpenAI,
Copilot, and Grok submissions; it does not imply external marketplace approval.

## Skill Graph

`setup` is the single entry point for "get Spice working". It owns the closed loop — existing
installation → spicepod → seeded local dataset → `spice run` → `/v1/ready` → rows from `/v1/sql` —
with `skills/setup/scripts/spice-local.sh`, then hands off:

```text
setup → spicepod, secrets → connectors + datasets → acceleration, accelerators, cache, search, models, chat, sql, sdk
```

`cookbook` is the recipe track, not greenfield bootstrap. `cloud` and `terraform` cover Spice.ai Cloud.
Keep each skill self-contained: skills can be installed one at a time, so a skill may mention another
skill's helper but must not depend on it.

## Workflow Skills

A skill that sets something up or runs something must end on a verified result, not on a command
that merely succeeded. Treat these as regressions when reviewing or auditing skills:

- A Quick Start that stops at `spice init`, `spice validate`, or a started process. `spice validate`
passes with zero datasets and with missing data files; done means `/v1/ready` returns `ready`, each
dataset reports `Ready` in `/v1/datasets?status=true`, and a query returns rows.
- A `/v1/sql` JSON body without `"parameters"` (the runtime returns 400), or a JSON example without
the note that the raw SQL body is the default.
- Stopping runtimes with `pkill spiced` instead of the PID that was started.
- Optional services such as `--metrics-endpoint` in a first-run command.
- Secret references other than `${ store:KEY }` (spaced) in new or edited examples.
- A new reference-only skill for a workflow: bundle a script with explicit exit checks instead.

Skills never install or upgrade Spice: they check `spice version`, and installation stays with the
user (`validate_plugin.py` rejects remote-installer patterns). Describe runtime bugs by symptom and
workaround; report root causes upstream rather than documenting them in skills.

## SKILL.md Format

```markdown
Expand Down
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@

## Unreleased

- Make `setup` the single entry point that takes an agent from an empty directory to a verified SQL
result. Its Quick Start used to stop at an empty `spice init`, which `spice validate` reports as `OK`
with zero datasets. The new `scripts/spice-local.sh` checks the existing installation, seeds a local
dataset (a bundled 20-row CSV, or `--data` for the user's file), starts `spice run` in the background
on free loopback ports, waits for `/v1/ready`, and verifies that each dataset is `Ready` and a query
returns rows. It never installs software, refuses to start when the runtime is missing, detects a
different runtime already holding port 8090, and stops only the PID it started. `verify` returns a
ready-to-show report: directory, PID, addresses, log path, dataset status, sample rows, and why the
ports moved when they did. The skill defines
what counts as working, lists the anti-patterns (stopping after `spice init`, treating
`spice validate` as proof, `pkill spiced`, metrics on the first run), and explains a failed
user-run install whose download URL contains `/download//`.
- Document `/v1/sql` request bodies in setup, sql, cache, cookbook, and cloud: a raw SQL body works,
while a JSON body needs `"parameters"` (`[]` when unused) and exactly `Content-Type: application/json`.
`{"sql": "..."}` alone returns `400 Invalid JSON: missing field 'parameters'`.
- Use one secret placeholder style, `${ store:KEY }`, across datasets, secrets, cookbook, cloud, and
terraform. The secrets skill notes that spaces inside the braces are optional.
- Make spicepod's Quick Start a credential-free local CSV, keeping PostgreSQL and OpenAI as the next
example, and note that the `spiceai/quickstart` pod is `version: v1` and loads data from public S3.
- Add a "Verify" section to connectors and datasets: `/v1/ready`, then dataset status, then `SELECT … LIMIT 1`.
- AGENTS.md and the README lead with the skill graph from setup; the README's per-agent install details
are collapsed under a summary table. AGENTS.md lists workflow-skill regressions to check for.

- Add the `spice-cookbook` skill, which sets up and runs recipes from the [Spice.ai cookbook](https://github.com/spiceai/cookbook). It picks a recipe by name or goal, fetches the cookbook (or a pull request or branch), and checks the runtime version, Docker, secrets, tools, and ports with `scripts/cookbook.sh` before running the README steps. The script reports whether each secret is set without printing its value.
- Fix spice-setup and spicepod-config, which set bind addresses with `spice run -- --http ...`. That fails on every v2 CLI (`argument '--http' cannot be used multiple times`) because `spice run` already passes `--http`. Use `spice run --http-endpoint`, `--flight-endpoint`, and `--metrics-endpoint` instead.
- Fix spice-search and spice-text-to-sql `rrf()` examples: the score column has been `_fused_score` since v2.0.0, not `fused_score`.
Expand Down
37 changes: 35 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,39 @@ Open [Agent Skills](https://github.com/vercel-labs/skills) and plugins for AI co

This is the **Spice.ai Marketplace**: packaged skills/plugins any compatible harness can load. The format works across Claude Code, Cursor, Codex, Grok, OpenCode, Pi, and other agents that support the open Agent Skills / plugin standard — not Claude-only.

## Start here

Ask your agent to set up Spice, for example "set up Spice in `./my_app` and show me a SQL result".
The [setup](skills/setup/) skill is the entry point. It checks your existing installation, creates a
spicepod with a local sample dataset (or your own file), starts the runtime, waits for `/v1/ready`,
and finishes only when a query returns rows. Then it hands off to the specialists:

```text
setup → spicepod, secrets → connectors + datasets → acceleration, accelerators, cache, search, models, chat, sql, sdk
```

[cookbook](skills/cookbook/) runs ready-made recipes instead of your own project, and
[cloud](skills/cloud/) and [terraform](skills/terraform/) manage Spice.ai Cloud. You install Spice
itself by following the [installation docs](https://spiceai.org/docs/installation); the skills check
`spice version` and never install or upgrade it.

## Installation

| Agent | Install |
| --- | --- |
| Claude Code | `/plugin marketplace add spiceai/skills`, then `/plugin install spiceai@spiceai` |
| OpenAI Codex | `codex plugin marketplace add spiceai/skills`, then `codex plugin add spiceai@spiceai` |
| GitHub Copilot | `copilot plugin marketplace add spiceai/skills`, then `copilot plugin install spiceai@spiceai` |
| Grok Build | `grok plugin marketplace add spiceai/skills`, then `grok plugin install spiceai --trust` |
| Cursor, Grok Bot, OpenCode, Pi, others | `npx skills add spiceai/skills -a <agent>` (`cursor`, `opencode`, `pi`, ...) |

Plugin installs invoke skills as `/spiceai:setup` (Claude Code) or `$spiceai:setup` (Codex);
`npx skills add` installs them without the namespace (`$setup`). The sections below cover
global installs, project auto-discovery, and maintainer publishing.

<details>
<summary>Per-agent installation details and maintainer publishing notes</summary>

### OpenAI Codex

The plugin identifier is `spiceai`. When installed as a plugin, invoke its skills
Expand Down Expand Up @@ -142,6 +173,8 @@ To auto-suggest the plugin for all contributors, add this to your project's `.cl
}
```

</details>

## Versioning

Pull requests validate metadata, private-skill exclusion, and packaging, and produce a submission
Expand All @@ -159,7 +192,7 @@ The skills are version-aware. Each one names the release line it is written for,

| Skill | Description |
| --- | --- |
| [setup](skills/setup/) | Check an existing Spice installation, initialize a project, and run the runtime |
| [setup](skills/setup/) | **Start here.** Take a directory to a running runtime that answers SQL with rows, using an existing installation; CLI, ports, and `/v1/sql` reference |
| [cookbook](skills/cookbook/) | Find, set up, and run recipes from the Spice.ai cookbook, including from a pull request |
| [spicepod](skills/spicepod/) | Create and configure spicepod.yaml manifests |
| [datasets](skills/datasets/) | Connect to data sources and query across them with federated SQL |
Expand All @@ -181,7 +214,7 @@ related commands; configuration topics are not invented CLI subcommands.

| Skill | CLI, API, or SDK surface |
| --- | --- |
| `setup` | Existing installation, `spice init`, `spice run`, `spice version` |
| `setup` | Existing installation, `spice init`, `spice validate`, `spice run`, `spice version`, `/v1/ready` |
| `sql` | `spice sql`, `/v1/sql`, `/v1/nsql`, SDK SQL methods |
| `search` | `spice search`, `/v1/search`, SDK search methods |
| `chat` / `models` | `spice chat`, `spice models`, OpenAI-compatible APIs and provider configuration |
Expand Down
6 changes: 5 additions & 1 deletion docs/publishing.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ it does not reproduce or bypass marketplace safety scans.

## Network and credential disclosure for reviewers

The package contains instructions and two bundled helpers, with no hosted MCP server or install hooks.
The package contains instructions and three bundled helpers, with no hosted MCP server or install hooks.
Cloud management uses `https://api.spice.ai` with a user-provided personal/OAuth access token;
OAuth exchange uses `https://spice.ai/api/oauth/token`. Runtime SQL, search, and inference use
the user's existing local runtime or Cloud project endpoints and project API keys as appropriate.
Expand All @@ -81,6 +81,10 @@ their own credentials. Credentials are not included in the package.
The cookbook helper reads or fetches `https://github.com/spiceai/cookbook` (including a requested
branch/PR); cookbook workflows can run recipe dependencies and examples after inspecting their
requirements. Those recipes are outside this plugin archive and must be considered during review.
The setup helper (`skills/setup/scripts/spice-local.sh`) runs only the user's installed `spice` CLI
(`version`, `init`, `validate`, `run`), copies a bundled sample CSV into the project, and makes HTTP
requests to the local runtime on `127.0.0.1`. It refuses to start a runtime when `spice version`
reports none, because `spice run` would download one, and it stops only the process it started.
Documentation links point to Spice AI and the relevant upstream providers. Runtime installation
and upgrades are user-managed prerequisites; `setup` and `cookbook` stop if the runtime is missing.

Expand Down
4 changes: 4 additions & 0 deletions skills/cache/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ curl -H "cache-control: max-stale=60" -XPOST http://localhost:8090/v1/sql -d 'SE
curl -H "cache-control: only-if-cached" -XPOST http://localhost:8090/v1/sql -d 'SELECT 1'
```

These send raw SQL, which `/v1/sql` reads as the query. Keep that form when adding headers: a JSON body
needs exactly `Content-Type: application/json` and a `parameters` field (`[]` when unused), and
`{"sql": "..."}` alone returns `400 Invalid JSON: missing field 'parameters'`.

### Spice CLI

`--cache-control` takes only `cache` (default) or `no-cache` — `spice sql` silently treats any other
Expand Down
6 changes: 3 additions & 3 deletions skills/cloud/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ curl -X POST https://api.spice.ai/v1/projects/{projectId}/secrets \
-d '{"name": "OPENAI_API_KEY", "value": "sk-..."}'
```

Upsert operation — creates if new, updates if exists. Name must start with a letter or underscore; letters, numbers, and underscores only. Reference it in the spicepod as `${secrets:OPENAI_API_KEY}`.
Upsert operation — creates if new, updates if exists. Name must start with a letter or underscore; letters, numbers, and underscores only. Reference it in the spicepod as `${ secrets:OPENAI_API_KEY }`.

### Delete Secret

Expand Down Expand Up @@ -303,7 +303,7 @@ Runtime (data-plane) requests go to the project's `endpoint` (returned by `GET /
```bash
ENDPOINT="https://<project-endpoint-host>" # the project's endpoint

# SQL query
# SQL query: raw SQL body (a JSON body needs "parameters": [], else 400)
curl "$ENDPOINT/v1/sql" \
-H "X-API-Key: <api-key>" \
-H "Content-Type: text/plain" \
Expand Down Expand Up @@ -394,7 +394,7 @@ curl -X PUT https://api.spice.ai/v1/projects/123 \
-H "Content-Type: application/json" \
-d '{"spicepod": {"version": "v2", "kind": "Spicepod", "name": "analytics-project",
"datasets": [{"from": "postgres:public.orders", "name": "orders",
"params": {"pg_host": "db.example.com", "pg_user": "analytics", "pg_pass": "${secrets:PG_PASS}"}}]}}'
"params": {"pg_host": "db.example.com", "pg_user": "analytics", "pg_pass": "${ secrets:PG_PASS }"}}]}}'

# 5. Deploy
curl -X POST https://api.spice.ai/v1/projects/123/deployments \
Expand Down
15 changes: 15 additions & 0 deletions skills/connectors/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,21 @@ SELECT * FROM partitioned_data WHERE year = '2024' AND month = '01';
- `name: myschema.foo` creates `spice.myschema.foo`
- Use `.` to organize datasets into schemas

## Verify a New Dataset

After adding or changing a dataset (`spice run` reloads `spicepod.yaml`), confirm it serves rows
before building on it. `spice validate` only checks syntax; it passes with a wrong path or host.

```bash
curl -s http://127.0.0.1:8090/v1/ready # "ready"; 503 "not ready" while loading or failing
curl -s 'http://127.0.0.1:8090/v1/datasets?status=true' # this dataset should show "status": "Ready"
curl -s -X POST http://127.0.0.1:8090/v1/sql -H 'Content-Type: text/plain' -d 'SELECT * FROM my_dataset LIMIT 1'
```

A dataset with `"status": "Error"` has an `error_message` (path or format matching no files, a missing
secret, an unreachable host); fix that first. setup's `spice-local.sh verify <dir> --dataset my_dataset`
runs all three checks.

## Documentation

- [Data Connectors](https://spiceai.org/docs/components/data-connectors)
Expand Down
5 changes: 4 additions & 1 deletion skills/cookbook/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ thing you'll handle here.
`.env` beats both, so a placeholder in the recipe's `.env` hides the user's real key. On v2.1.x, put
the value in `.env` itself or delete the placeholder line, or upgrade. `inspect` applies the installed
runtime's precedence, and `ignored_values` names any real value that loses to a placeholder.
- **Names**: `${secrets:NAME}` accepts `SPICE_NAME` or `NAME`. A recipe that reads `SPICE_OPENAI_API_KEY`
- **Names**: `${ secrets:NAME }` accepts `SPICE_NAME` or `NAME`. A recipe that reads `SPICE_OPENAI_API_KEY`
therefore ignores an exported `OPENAI_API_KEY`. `inspect` flags that case as `similar_in_shell`.
- **Getting a value in without seeing it**: when the value is already in the shell or a CLI, write it
to `.env.local` without echoing it:
Expand Down Expand Up @@ -175,6 +175,8 @@ it demonstrates. Rewrite steps meant for a person at a terminal:
- **"In a new terminal, run `spice sql`"**: pipe the query in, `echo "SELECT ...;" | spice sql` (add
`--endpoint` if you moved ports), or use the HTTP API, which returns JSON:
`curl -s -X POST http://127.0.0.1:8090/v1/sql -H 'Content-Type: text/plain' -d 'SELECT ...'`.
Keep the raw SQL body. A JSON body needs exactly `Content-Type: application/json` and
`"parameters": []`; `{"sql": "..."}` alone returns `400 Invalid JSON: missing field 'parameters'`.
- **Other REPLs** (`spice chat`): use the matching HTTP endpoint, e.g. `/v1/chat/completions`.
- **Long-running producers** (streaming data into a file, a load generator): run them in the background
for a bounded time, then continue.
Expand Down Expand Up @@ -228,6 +230,7 @@ When the user asks, or when they only wanted a check:
| `argument '--http <BIND_ADDRESS>' cannot be used multiple times` | `spice run -- --http ...` | `spice run --http-endpoint ...` |
| 401 or `Incorrect API key` from a model provider | A placeholder or empty key is being used | Re-run `inspect`; fix the variable name, the file, or the v2.1.x precedence |
| `spice sql` can't connect | Runtime still starting, crashed, or on other ports | Check `/v1/ready` and the log; pass `--endpoint` |
| `400 Invalid JSON: missing field 'parameters'` from `/v1/sql` | JSON body without `parameters` | Send raw SQL, or add `"parameters": []` |
| Unknown field or invalid parameter at startup | Runtime older than the recipe | `spice upgrade`, or a recipe within the runtime's version |
| Schema mismatch after re-running a recipe | Stale acceleration files | Delete `<recipe>/.spice/` and restart |
| `Cannot connect to the Docker daemon` | Docker isn't running | Start Docker Desktop, OrbStack, or colima |
Expand Down
2 changes: 1 addition & 1 deletion skills/cookbook/evals/evals.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
{
"id": 2,
"prompt": "I'm running the cookbook's ai recipe. OPENAI_API_KEY is exported in my shell, but the gpt-4o-mini model still fails to authenticate. Why?",
"expected_output": "The recipe reads ${secrets:SPICE_OPENAI_API_KEY}, which resolves SPICE_OPENAI_API_KEY, not OPENAI_API_KEY; set SPICE_OPENAI_API_KEY in .env.local or export it",
"expected_output": "The recipe reads ${ secrets:SPICE_OPENAI_API_KEY }, which resolves SPICE_OPENAI_API_KEY, not OPENAI_API_KEY; set SPICE_OPENAI_API_KEY in .env.local or export it",
"files": [],
"assertions": [
{
Expand Down
15 changes: 14 additions & 1 deletion skills/datasets/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ datasets:
name: customers
params:
pg_host: db.example.com
pg_user: ${secrets:PG_USER}
pg_user: ${ secrets:PG_USER }
- from: s3://bucket/orders/
name: orders
params:
Expand Down Expand Up @@ -363,6 +363,19 @@ params:
pg_pass: ${ secrets:PG_PASSWORD }
```

## Verify

Check each source on its own before debugging a federated query, view, or write:

```bash
curl -s http://127.0.0.1:8090/v1/ready # "ready" once every component has loaded
curl -s 'http://127.0.0.1:8090/v1/datasets?status=true' # every dataset "status": "Ready"
curl -s -X POST http://127.0.0.1:8090/v1/sql -H 'Content-Type: text/plain' -d 'SELECT * FROM orders LIMIT 1'
```

Then run the join or view. A dataset with `"status": "Error"` reports why in `error_message`.
setup's `spice-local.sh verify <dir> --dataset orders --dataset customers` checks several at once.

## Documentation

- [Data Connectors](https://spiceai.org/docs/components/data-connectors)
Expand Down
6 changes: 4 additions & 2 deletions skills/secrets/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ secrets:

## Referencing Secrets

Use `${ store_name:KEY_NAME }` syntax in component parameters:
Use `${ store_name:KEY_NAME }` syntax in component parameters. Spaces inside the braces are optional —
`${secrets:KEY}` and `${ secrets:KEY }` resolve the same, so don't rewrite a user's working references;
these skills use the spaced form.

```yaml
datasets:
Expand All @@ -84,7 +86,7 @@ Also works within strings:

```yaml
params:
mysql_connection_string: mysql://${env:USER}:${env:PASSWORD}@localhost:3306/db
mysql_connection_string: mysql://${ env:USER }:${ env:PASSWORD }@localhost:3306/db
```

## Searching All Stores
Expand Down
Loading
Loading