Skip to content
Draft
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
23 changes: 16 additions & 7 deletions rust/crates/sift_cli/assets/skills/sift/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,11 @@ Sift-entity request always wins.

- **None:** lookups, explanations, how-to answers, and one-off numbers or
short analysis. Do not wrap a chat-sized answer in a file.
- **Explore links:** plots and timeseries the user wants to inspect. Use native
Sift app visualizations instead of creating an intermediate image or HTML.
- **Declarative charts:** plots, charts, and timeseries the user wants to see.
Build or pass a spec to `create_declarative_chart`.
- **Explore links:** quick deep-links to specific assets, runs, or channels the
user wants to inspect in the Sift web app. Use native Sift app
visualizations instead of creating an intermediate image or HTML.
- **Calculated channels:** reusable CEL transforms (unit conversions, rolling
windows, derived signals, and simple filters) that should be plottable or
usable by rules on later runs. List existing calculated channels first to
Expand Down Expand Up @@ -109,6 +112,7 @@ tool.
to enable them, then restart the MCP client.
- **Data:** `get_data` writes channel data to a Parquet file. `sql` queries
Parquet files. `upload_dataset` streams a Parquet dataset into Sift.
- **Charts:** `create_declarative_chart`.
- **Links:** `explore_url`.
- **Docs:** `search_docs`.
- **Writes:** `create_rule`, `update_rule`, `archive_rule`, `unarchive_rule`,
Expand Down Expand Up @@ -224,8 +228,10 @@ tool.
listings without deleting its versions, links, or files. Find archived
artifacts with `list_artifacts` and `include_archived=true`, then restore one
with `unarchive_artifact`. Both writes need `--allow-destructive`.
- **Produce a chart.** Build a link with `explore_url`. When the user wants a
chart and numbers, do both and give the user both.
- **Produce a chart.** Use `create_declarative_chart` with a spec (see
references/declarative-charts.md). For quick links to Sift Explore, use
`explore_url` instead. When the user wants a chart and numbers, do both and
give the user both.
- **Answer a question about how Sift works.** Call `search_docs`. Do not answer
from memory, and cite the page you used.
- **Create an asset.** There is no `create_asset` MCP tool because Sift creates
Expand Down Expand Up @@ -254,9 +260,11 @@ tool.
- **Stop on empty list results.** If any `list_*` tool returns no items, tell
the user that nothing matched and ask how to proceed. Do not make subsequent
tool calls using an empty or placeholder name or id from the missing result.
- **Surface URLs as plain text, in full.** The link from `explore_url` and the
- **Surface tool-returned URLs; never invent one.** The link from `explore_url` and the
`View in Sift:` line from `sift-cli import` are deliverables. Never invent a
URL that a tool did not return.
URL that a tool did not return. Chart links from `create_declarative_chart`
follow the tool's `next_step` (render as a clickable markdown link with
descriptive text, mentioned once).
- **Confirm every write before you run it.** Show the user the proposed change
and its target, then wait for approval.
- **Write tools are off by default.** Read-only is the default access mode.
Expand Down Expand Up @@ -291,6 +299,7 @@ Read the file that matches the task in front of you. Do not read them all.
| When the task is | Read |
|---|---|
| any `sift-cli` invocation: import, export, config | [references/cli.md](references/cli.md) |
| a chart, a plot, or an Explore link | [references/explore-links.md](references/explore-links.md) |
| a declarative chart spec | [references/declarative-charts.md](references/declarative-charts.md) |
| a quick Explore link | [references/explore-links.md](references/explore-links.md) |
| install, update, or diagnose the Sift integration | [references/agent-setup.md](references/agent-setup.md) |
| code written against Sift's libraries or REST API | [references/integration-code.md](references/integration-code.md) |
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Declarative charts

Use `create_declarative_chart` to validate a complete version 0 YAML or JSON spec and get a Sift link that opens it.
One chart is recommended: a spec with exactly one chart displays inline in Sift agent chat.
Specs with several charts or a top-level `layout` are allowed and still return a working Explore link.

A valid result includes `exploreUrl`. Render it once as a clickable markdown link with descriptive text, such as what the chart plots. Do not paste the spec into your reply.

## User supplies a spec

If the user pastes or attaches a complete spec, pass it to `create_declarative_chart` verbatim. When it returns `invalid_spec` with reported paths, fix each path (or ask the user when the fix needs their intent) and resend the full spec. Repeat until valid or 3 attempts are exhausted, then explain the remaining issues to the user.

## Plain-language request

1. Resolve runs with Sift MCP `list_runs` and channels with `list_channels`. Resolve calculated channels with `list_calculated_channels` and bind them with `calculatedChannelId`, not `channel`. Never invent IDs or channel names.
2. Write a complete version 0 spec with `dataSources` and one `chart`. Prefer YAML. Use one chart unless the user asked for several.
3. Call `create_declarative_chart` with the full spec.
4. On `invalid_spec`, fix every reported path and resend the full corrected spec.
5. After 3 failed attempts, stop and summarize the remaining validation problems instead of retrying.
6. To edit a chart, resend the full edited spec. Each valid call returns a new `exploreUrl`.

## Minimal spec

Replace the illustrative ID and channel with values from Sift MCP.

```yaml
version: 0
dataSources:
flight: { run: { id: 7f3a2b10-0000-4000-8000-000000000001 } }
chart:
type: timeseries
series: [{ channel: pressure, source: flight, axis: L1 }]
```

## Checklist

- [ ] IDs and channel names came from Sift MCP results.
- [ ] The complete version 0 spec has one chart unless the user asked for several or a `layout`.
- [ ] Each channel series has exactly one of `channel`, `channelId`, `calculatedChannelId`, or `match`.
- [ ] Encoding series have every required coordinate role.
- [ ] Asset-only charts include an explicit `timeInterval`.
- [ ] Every reported path is fixed before resending the full spec.
- [ ] After 3 failed attempts, explain the remaining problems instead of retrying.
- [ ] Optional `sampling`, `maxGap`, and axis `min`/`max` are omitted unless the user asked for them.

## Schema reference

Validation errors are the source of truth for allowed keys and constraints. When keys fail validation, read the reported paths and messages to understand what is allowed. The tool accepts `version: 0` YAML or JSON. A single chart uses `chart` or one entry under `charts` and displays inline in Sift agent chat. Several charts or a top-level `layout` are accepted and return an Explore link.

## Run and inline expression example

```yaml
version: 0
dataSources:
flight: { run: { id: 7f3a2b10-0000-4000-8000-000000000001 } }
transforms:
power:
expr: '$1 * $2'
inputs:
$1: { channel: voltage }
$2: { channel: current }
unit: W
chart:
type: timeseries
title: Electrical power
sources: [flight]
timeMode: absolute
yAxis:
L1: { label: Power, scale: value }
series:
- channel: power
source: flight
axis: L1
style: { line: { color: ruby } }
```

## Asset and explicit interval example

```yaml
version: 0
dataSources:
pad: { asset: { id: 5d10c4a0-0000-4000-8000-000000000002 } }
timeInterval:
start: '2024-06-01T00:00:00Z'
end: '2024-06-01T00:10:00Z'
chart:
type: timeseries
title: Pad temperature
timeMode: absolute
series:
- match: { name: { matches: '^temp_.*' } }
source: pad
axis: R1
yAxis:
R1: { label: Temperature, scale: value }
```

## Calculated channel series example

```yaml
version: 0
dataSources:
flight: { run: { id: 7f3a2b10-0000-4000-8000-000000000001 } }
chart:
type: timeseries
series:
- calculatedChannelId: 1a2b3c4d-0000-4000-8000-000000000002
source: flight
axis: L1
label: Filtered pressure
```
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Sift Explore links

To plot, chart, graph, or visualize data, use `create_declarative_chart` with a spec (see [references/declarative-charts.md](declarative-charts.md)). Use `explore_url` to build a quick deep-link that opens specific assets, runs, or channels.

Build the link with `explore_url`, then surface the URL to the user as plain
text, in full.

Expand Down
5 changes: 4 additions & 1 deletion rust/crates/sift_mcp/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub(crate) const BASE_INSTRUCTIONS: &str = concat!(
use crate::service::{
annotations::AnnotationService, artifacts::ArtifactService, assets::AssetService,
calculated_channels::CalculatedChannelService, channels::ChannelService, data::DataService,
docs::DocsService, ingest::IngestService, ping::PingService,
declarative::DeclarativeService, docs::DocsService, ingest::IngestService, ping::PingService,
report_templates::ReportTemplateService, reports::ReportService,
rule_evaluation::RuleEvaluationService, rules::RuleService, runs::RunService,
test_reports::TestReportService, url::UrlService,
Expand All @@ -66,6 +66,7 @@ pub struct SiftMcpServer {
pub calculated_channel_service: CalculatedChannelService,
pub channel_service: ChannelService,
pub data_service: DataService,
pub declarative_service: DeclarativeService,
pub url_service: UrlService,
pub ingest_service: IngestService,
pub ping_service: PingService,
Expand Down Expand Up @@ -273,6 +274,7 @@ impl SiftMcpServer {

let annotation_service = AnnotationService::new(channel.clone(), retry_policy.clone());
let mut artifact_service = ArtifactService::new(channel.clone(), retry_policy.clone());
let declarative_service = DeclarativeService::new(rest_config.clone(), &cli_version);
if let Some(rest_config) = rest_config {
artifact_service = artifact_service.with_uploader(
crate::service::remote_files::RemoteFileUploader::new(rest_config, &cli_version),
Expand Down Expand Up @@ -306,6 +308,7 @@ impl SiftMcpServer {
calculated_channel_service,
channel_service,
data_service,
declarative_service,
url_service,
ingest_service,
ping_service,
Expand Down
Loading
Loading