Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
23802ec
Add a generic agent-skills host with an access-aware preflight
kumo-isaac Oct 20, 2026
14a51ec
Generic host: bare file table names; write path destinations exactly
kumo-isaac Oct 20, 2026
8caea0e
Generic host: stage a file population with TIMESTAMP, in a created di…
kumo-isaac Oct 21, 2026
5a15087
Generic host: a timestamped entity's population must carry TIMESTAMP
kumo-isaac Oct 21, 2026
7ed8896
Generic host: stage a Databricks population through the statement API
kumo-isaac Oct 21, 2026
76cd6f7
Generic host: cast a population's TIMESTAMP to a timestamp
kumo-isaac Oct 21, 2026
feefa6d
Generic host: no region or profile placeholder for S3 and GCS
kumo-isaac Oct 21, 2026
ad5d748
S3Connector: region is optional and normally omitted
kumo-isaac Oct 21, 2026
e6df3db
Router: show the later-destination example as text, not a python block
kumo-isaac Oct 21, 2026
e35d691
SDK reference: threshold and top-k belong to predict, never to Predic…
kumo-isaac Oct 21, 2026
b5d5245
Address review on the generic host
kumo-isaac Oct 23, 2026
f163844
agent-skills: address remaining quick review comments
kumo-isaac Oct 24, 2026
79d5f45
agent-skills: CSV time column is Dtype.date in the connector notes
kumo-isaac Oct 26, 2026
bac10d9
agent-skills: stage a scoring population in the source's system
kumo-isaac Oct 26, 2026
e1ce213
agent-skills: stage a BigQuery scoring population through the BigQuer…
kumo-isaac Oct 26, 2026
d1cf34e
agent-skills: pick the population connector from the population path
kumo-isaac Oct 26, 2026
5ba5655
Merge branch 'main' into igutierrez/agent-skills-generic-host
kumo-isaac Oct 26, 2026
4f974c5
agent-skills: generic BigQuery connectors name kumo.BigQueryIdentity()
kumo-isaac Oct 26, 2026
25c5c4e
agent-skills: generic BigQuery bills to project_id unless the user na…
kumo-isaac Oct 27, 2026
1178a6d
agent-skills: generic BigQuery project_id is the confirmed scope's pr…
kumo-isaac Oct 27, 2026
23dae04
agent-skills: generic config cell has no billing constant for BigQuery
kumo-isaac Oct 27, 2026
6f3cdab
Merge branch 'main' into igutierrez/agent-skills-generic-host
kumo-isaac Oct 27, 2026
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
16 changes: 16 additions & 0 deletions agent-skills/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,21 @@ rules; this is why they exist.
| Predict in notebook | one submission call, no execution | the predict call is part of the artifact (router Step 2) | user decision 2026-09-23 |
| Snowflake ML Jobs | no scheduling | the artifact may run as an ML Job on request; a recurring run is proposed and created only on explicit confirmation (`hosts/snowflake-coco/ml_job.md`) | spec feature 7 (2026-10-13). How Kumo reaches the job container is pending; the skill names it only as host values (`adapter.md` §10) |

| Preflight source | read-only SQL against the user's source | on the generic host, whatever read tool the agent has; with none, the structure the user pastes (`preflight.md` §0) | added 2026-10-20 with the generic host. A coding agent beside the user often has no warehouse session; asking for access or details keeps the gate instead of guessing |

Accommodation, not deviation: the spec has the user select the table mode. Nobody does, so it
defaults to `all-connected` and is confirmed at Node 1c.

## Hosts and the access check

The core says *what* intake and code generation need; a host says *how* in its `adapter.md`
(intake) and `runtime.md` (Step 2). A package ships one host, so the agent never weighs another
host's rules, and the core names it only as `hosts/<host>/` (`tests/test_package_skill.py`).

Preflight §0 asks the agent to prove it can read the source before inferring anything from it.
CoCo always can — its SQL is the read tool — so §0 only adds the grant-or-details ask-back for an
unreadable scope. A coding agent may have an authenticated CLI, a tool server, Python with Kumo,
or nothing. Without the check it falls back on its priors, the failure seen when CoCo read an
empty skill tree. The agent's access is never the artifact's: the generated code authenticates
where it runs, so §0 changes no gate and no generated line. Credentials stay with the user —
the agent may ask them to authenticate a tool, never for a value.
16 changes: 13 additions & 3 deletions agent-skills/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
# Agent skills: `kumo-data-science`

Agent skill for building, training, and running inference with Kumo models. One shared source tree
serves every host; host-specific behavior lives under `skills/hosts/`. Currently shipped to
Snowflake Cortex Code (CoCo).
serves every host; host-specific behavior lives under `skills/hosts/`. Two hosts:

| Host | Package | For |
|---|---|---|
| `hosts/snowflake-coco/` | `coco` | Snowflake Cortex Code (CoCo), inside Snowflake |
| `hosts/generic/` | `generic` | a coding agent beside the user — Claude Code, Codex — generating code for any of the six Kumo connectors |

This directory is deliberately not under `.agents/skills/` or `.claude/skills/`: Codex, Claude Code
and the CoCo CLI load those for repo developers, and this skill triggers on "kumo" and "train a
Expand All @@ -19,7 +23,7 @@ are sub-skills and references it loads:
|---|---|
| `kumo-data-science/` | Router: intake, validation, preflight, notebook generation |
| `kumoai-reference/` | SDK reference the generated code is checked against |
| `hosts/` | Host-specific behavior (currently Snowflake CoCo) |
| `hosts/` | Host-specific behavior: access, source and destination forms, preflight, connect step |
| `kumo-model-explanations/` | Explaining predictions |
| `kumo-training-diagnostics/` | Diagnosing training runs |
| `kumo-model-persistence/` | Saving and reloading trained models |
Expand All @@ -34,9 +38,15 @@ path. Build a host package with:

```bash
python3 agent-skills/scripts/package_skill.py coco # -> agent-skills/dist/coco/
python3 agent-skills/scripts/package_skill.py generic # -> agent-skills/dist/generic/skills/
python3 agent-skills/scripts/package_skill.py --check # build every host, verify references
```

A package carries exactly one host, and the core reaches it only as `hosts/<host>/`; tests fail if
a core file names a host. To use the `generic` package, copy
`dist/generic/skills/kumo-data-science/` into the agent's user-level skills directory (for Claude
Code, `~/.claude/skills/`) — not into this repository, for the reason above.

The build stamps the router's `SKILL-BUILD` marker with the source commit
(`<commit date>-<short sha>`, `-dirty` for uncommitted edits); never edit it by hand. Every build
fails if a markdown link or a backticked package path does not resolve inside the
Expand Down
6 changes: 6 additions & 0 deletions agent-skills/scripts/package_skill.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""Build the kumo-data-science skill package for one host and check that it resolves.

python3 agent-skills/scripts/package_skill.py coco # build into agent-skills/dist/
python3 agent-skills/scripts/package_skill.py generic # Claude Code, Codex, other agents
python3 agent-skills/scripts/package_skill.py coco --out DIR # build somewhere else
python3 agent-skills/scripts/package_skill.py --check # build every host in a temp dir

Expand Down Expand Up @@ -49,6 +50,11 @@
hosts=['snowflake-coco/adapter.md', 'snowflake-coco/runtime.md',
'snowflake-coco/ml_job.md'],
capability=True),
# A coding agent outside any data platform. The package root holds the one skill directory,
# ready to copy into the agent's skills directory.
'generic': dict(prefix='skills',
hosts=['generic/adapter.md', 'generic/runtime.md'],
capability=True),
}

MARKER = re.compile(r'SKILL-BUILD: [^`*\s]+')
Expand Down
143 changes: 143 additions & 0 deletions agent-skills/skills/hosts/generic/adapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Host Adapter — Generic coding agent

For a coding agent working beside the user — Claude Code, Codex, or any agent with a shell and
file tools — rather than inside a data platform. The agent produces code that runs in **any**
Python environment where Kumo is present, against whichever of the six Kumo connectors the data
calls for. The agent does not know where that code will run; the user does.

Kumo is already present in the environment that runs the artifact; never raise environment setup
with the user. Generating the artifact — connect step, credentials, destinations and read-back —
is in `runtime.md` in this directory; read it at Step 2.

This host has no job file: it does not submit, schedule or monitor jobs. When asked for one, say
so and offer the notebook or script.

---

## 1. Source scope

`source_scope` names a system and a location in it. Map it to its connector
(`kumoai-reference/references/kumo_finetuning_sdk.md` §3, §3.4):

| The user names | Connector |
|---|---|
| A local directory of CSV or Parquet files | `FileConnector` |
| `s3://bucket/prefix` | `S3Connector` |
| `gs://bucket/prefix` | `GCSConnector` |
| A BigQuery project and dataset | `BigQueryConnector` |
| A Databricks catalog and schema | `DatabricksConnector` |
| A Snowflake database and schema | `SnowflakeConnector` |

- A dotted name with no system named (`SALES.EVENTS`) fits Snowflake, BigQuery and Databricks
alike. Ask which system holds it — that one question, nothing else. A system already named in
any turn, or evident from the user's tools or files, settles it.
- A connector name on its own is not a location on this host, which keeps no registry of named
connectors. Ask what system and location it points at.
- A Snowflake semantic view resolves through `kumo-data-science/accept/semantic_view.md`, which
needs Snowflake SQL (§2). Without it, the §2 details are the view's base tables, their keys and
its relationships.
- Values only the runtime needs — a Snowflake warehouse, a Databricks SQL warehouse or cluster, a
`connections.toml` entry — are not part of `source_scope` and are never asked for at intake.
`runtime.md` §1 handles them.

ADLS has no Kumo connector. Data there is outside this host's reach: say so.

---

## 2. Access

Implements `kumo-data-science/accept/preflight.md` §0. Check, in this order, and stop at the
first that reads the **columns and types** inside `source_scope`. A listing of object names
(`aws s3 ls`, `gcloud storage ls`) proves access, not structure: keep going down the list for a
reader, and if none is found, send the ask-back below with **Details** as the way forward.

1. **A tool in this session** that reads the system — a server or connector tool for that
warehouse or storage. Use only its read operations.
2. **A command-line tool on the `PATH`** that is already authenticated (table below). Find it
with `command -v <tool>`, then run its check command against `source_scope` itself — a
general "who am I" call proves the login, not access to the data.
3. **Python in this session** in which `import kumo.engine` works and the provider's ambient
credentials resolve. Build the connector exactly as the artifact would (`runtime.md` §2) and
read `connector.table_names()` and `connector['<table>'].columns`, which gives each column's
name and source type. Catalog reads only: no `Table`, `Graph` or snapshot.

| Source | Tool | Check, inside `source_scope` | Columns and types | Declared keys | §3 probe |
|---|---|---|---|---|---|
| Local files | your file tools; `duckdb`, or Python with `pyarrow` | list the directory | CSV header line; Parquet schema (`duckdb -c "DESCRIBE SELECT * FROM '<file>'"`) | none | `duckdb`, or `pyarrow` |
| S3 | `aws` | `aws s3 ls s3://<bucket>/<prefix>/` | file names only — not enough on its own; for columns, a reader of `s3://` with the same credentials (`duckdb`, or check 3), else the ask-back | none | the same reader, else skip |
| GCS | `gcloud` | `gcloud storage ls gs://<bucket>/<prefix>/` | as S3, with `gs://` | none | as S3 |
| BigQuery | `bq` | `bq ls <project>:<dataset>` | `bq show --schema --format=prettyjson <project>:<dataset>.<table>` | `INFORMATION_SCHEMA.TABLE_CONSTRAINTS` and `KEY_COLUMN_USAGE` of the dataset | `bq query --nouse_legacy_sql` |
| Databricks | `databricks` | `databricks tables list <catalog> <schema>` | `databricks tables get <catalog>.<schema>.<table>` | the same output's table constraints | only through a SQL warehouse the user named; else skip |
| Snowflake | `snow` | `snow sql -q "<the preflight §1 scope query>"` | the preflight §2 query | `SHOW PRIMARY KEYS` / `SHOW IMPORTED KEYS IN SCHEMA <DB>.<schema>` | `snow sql -q` |

A skipped probe leaves its candidates `[inferred, unverified]`, as preflight §0 says. A BigQuery
probe is billed by the bytes it scans; probe only the candidate columns.

**What a check may do.** Read catalog metadata and run the preflight §3 probe — nothing else.
Never run a command that writes, creates, copies or exports data; never sign in, switch a
profile or account, or edit a tool's configuration; never add or update software to get a
reader. Tool permission prompts are the user's to answer; a refused prompt means that path is
unavailable.

**When nothing reads the source's columns**, send the preflight §0 ask-back. State what you checked and
what happened — "no BigQuery tool in this session; `bq ls my-proj:sales` returned `Access
Denied`" — then offer:

1. **Access**: authenticate the named command-line tool as an identity that can read the scope,
or connect a tool for that system to this session, and tell you when it is done. The user
does this; you never handle the credential.
2. **Details**: paste the structure. No rows are needed. Useful forms: DDL, `DESCRIBE` output,
`bq show --schema` JSON, a Parquet schema, CSV header lines — with any declared keys.

---

## 3. Preflight

Answer `kumo-data-science/accept/preflight.md` §1-§6 with the tool §2 found. Write table and
column names exactly as that tool returns them; the artifact must use the same spelling
(`kumoai-reference/references/kumo_finetuning_sdk.md` §3.2). Probe results are evidence for the
proposal only: never written, never saved to a file, never fed to the artifact.

For files and object stores, a table is a file or a directory of parts in one format, below the
source location. **Name it without its file suffix**: `accounts.parquet` is the table `accounts`.
The connector finds the file from the bare name, and the name you pass becomes the table's name
in the graph, the edges and the PQL, where a suffix's dot does not parse. Show the bare names in
the proposal.

---

## 4. Destinations

Any destination a Kumo connector writes
(`kumoai-reference/references/kumo_finetuning_sdk.md` §9.2): a table in Snowflake, BigQuery or
Databricks, or a path in a local directory, S3 or GCS. The destination may be in a different
system from the source; it gets its own connector. Not destinations here: ADLS, and BigQuery for
anything but predictions and embeddings.

A path destination ends in `/` (a directory) or in `.parquet` / `.csv` (one file). The sink adds
`.parquet` to any other path, so the file would not be where the user said. When the user gives
a path with neither, restate it with a trailing `/` at Node 1d and let them confirm or correct it.

---

## 5. Runtime column constraints

None known for this host. Do not exclude text columns pre-emptively. If a run fails while loading
a text encoder, report the error and the column; that finding belongs at Node 1c.

---

## 6. Capability skills

The capability skills were written for, and measured on, Snowflake. Their Kumo calls hold for
every connector. Where a step names a Snowflake registry, stage, session or table, follow it only
when the source or destination is Snowflake. For any other connector, say that the step is not
covered on this host; do not adapt it.

---

## 7. Other deployment modes — out of scope

Hosted Kumo — `kumo.init(...)`, an API key, `KUMO_API_KEY` / `KUMO_API_ENDPOINT`, Kumo Studio — and
the Snowflake Native App are not this SDK. If the user is on one of them, say so and stop. Never
blend their setup into generated code.
Loading
Loading