Create a free account

Continue with Google

An account on the spot, no request needed.

or sign up with your email

No password: the link signs you in.

By continuing, you agree to our Terms of Service and Privacy Policy.

Already have an account? Sign in

Docs

KASPR Predict for Snowflake

Reference for the KASPR Predict Snowflake Native App: what it answers, how to install it and grant it, every procedure with its parameters and results, the managed MCP servers, pipeline gating, entitlements and usage, limits, errors and privacy.

Spec 0.5 · updated 3 October 2026 · beta · private preview · Product page · MCP server documentation

Overview

KASPR Predict for Snowflake is a Snowflake Native App: a timing planner for work that depends on the network, installed in your own account. It offers the same two capabilities as the hosted KASPR Predict MCP, as stored procedures in two schemas, each with a Snowflake-managed MCP server.

The TIMING schema answers one question for calls, live streams, big uploads, agent batches and fixed live events: given a task at a proposed time and place, is there a materially better time? It answers in fixed wording, in every participant’s local time, and says nothing when nothing is better. It never blocks the time you proposed. Its decision code is shared with the MCP server, and both pass the same test cases.

The PREDICT schema ranks the hours between now and a deadline for batch jobs, agent loops and transfers: run now with timeout, retry and cache tuning for the hour, wait, or no good window. It can hold a chosen window and re-score it until it starts.

Both read the same model: KASPR’s typical week for every country, region and district, 168 hourly values of how usually rough the connection is, from a frozen data vintage named in every answer. Neither is a live measurement of the network. The examples below call the app KASPR_PREDICT; use the name you gave it at installation.

ObjectKindWho can use itFor
TIMING.CHECK_TIMINGprocedureAPP_PUBLICis there a materially better time?
TIMING.BEST_WINDOWprocedureAPP_PUBLICthe steadiest hour in a window
TIMING.EXPLAIN_LAST_VERDICTprocedureAPP_PUBLICwhy the last verdict said what it said
TIMING.TIMING_WINDOWSprocedure returning a tableAPP_PUBLICbands per hour for one place
TIMING.GET_ENTITLEMENTprocedureAPP_PUBLICyour account, tier and caps
TIMING.KASPR_TIMINGmanaged MCP serverAPP_PUBLICcheck_timing, best_window, explain_last_verdict
TIMING.SET_DAILY_CAP · TIMING.RUN_GOLDEN · TIMING.V_TIMING_USAGEprocedures, viewAPP_ADMINa per-user cap, the shared self-test, every call
PREDICT.*procedures, views, managed MCP server KASPR_PREDICTAPP_PUBLICjobs with a deadline

Quick start

1. Get access

During the private preview the app is shared with your account as a private listing. Ask through the contact page with your account locator and cloud region, then install it from Snowsight (Data Products → Apps).

2. Grant it

Give the application role to the roles that call the app. The two task privileges are optional; they let PREDICT re-score held windows on a schedule. Grant them in Snowsight: open the app (Data Products → Apps), go to the Permissions tab and grant both.

GRANT APPLICATION ROLE KASPR_PREDICT.APP_PUBLIC TO ROLE ANALYST;
GRANT APPLICATION ROLE KASPR_PREDICT.APP_ADMIN  TO ROLE SYSADMIN;

3. Ask

Procedures run on the caller’s warehouse; an X-Small warehouse is enough. Object and array arguments are JSON strings.

CALL KASPR_PREDICT.TIMING.CHECK_TIMING('live_call',
  '[{"label": "me", "query": "Melbourne"}, {"label": "Tim", "query": "Nairobi, KE"}]',
  '2026-10-06T21:00:00+03:00',
  '{"start": "2026-10-06T18:00:00+03:00", "end": "2026-10-07T00:00:00+03:00"}',
  '{"local_hours": [0, 24]}',
  'Australia/Melbourne');

4. Check the installation

An admin can run the shared test cases inside your account; every case should pass.

CALL KASPR_PREDICT.TIMING.RUN_GOLDEN();   -- {"cases": 29, "failed": 0, "resolution_cases": 18, "resolution_failed": 0, ...}

Roles and grants

APP_PUBLIC calls every procedure in TIMING and PREDICT, reads the PREDICT views and uses both managed MCP servers. APP_ADMIN is for administrators and adds three things: a per-user daily cap, every timing call in TIMING.V_TIMING_USAGE, and the shared self-test; grant it together with APP_PUBLIC.

The app requests two optional account privileges, EXECUTE MANAGED TASK and EXECUTE TASK, which you grant on the app’s Permissions tab in Snowsight. With them, PREDICT.SCHEDULE_HOLD creates a serverless task that re-scores open holds every fifteen minutes and suspends itself when none are left. Without them holds are not re-scored and are not charged, and PREDICT.V_HOLDS still shows a hold as released once its latest start has passed.

The app references no tables of yours and requests no external access integration.

Timing procedures (schema TIMING)

Read-only answers. Every call returns a verdict object (next section) as a VARIANT, and every outcome is a verdict, never an error: a bad request is invalid_request, a cap is rate_limited, and a failure inside the app is a silent no_recommendation. JSON arguments may be passed as strings, as shown.

CHECK_TIMING

CHECK_TIMING(TASK_CLASS, LOCATIONS, CANDIDATE_TIME, WINDOW, FEASIBILITY, USER_TIMEZONE) RETURNS VARIANT

Is a proposed time a usually rough hour on the networks involved, and is there a materially steadier hour nearby? Show text when it is present; on no_recommendation say nothing about timing.

Parameters

NameTypeRequiredMeaning
TASK_CLASSVARCHARyeslive_call, broadcast, upload_transfer, agent_batch, fixed_realtime or generic. broadcast, upload_transfer and agent_batch take exactly one location.
LOCATIONSVARCHAR (JSON array of 1–2)yesEach with a label (1–40 characters: letters, digits, space, _ . ' -; labels come back in the answer, so nothing else is accepted) and either query (a place name, ≤ 80 characters, e.g. “Nairobi, KE”) or lat and lon. The location labelled me is the user’s own; otherwise the first one is.
CANDIDATE_TIMEVARCHARyesISO 8601 with offset; a time without an offset is read as UTC. Not earlier than one hour ago; no upper limit.
WINDOWVARCHAR (JSON object)no{ "start", "end" } with offsets, at most 12 hours, inside which an alternative may be proposed. Default: the candidate ± 3 hours.
FEASIBILITYVARCHAR (JSON object)no{ "local_hours": [from, to) } in whole hours, applied in each endpoint’s local time. Default [8, 20].
USER_TIMEZONEVARCHARnoIANA zone for the user’s clock, e.g. Australia/Melbourne. Default: the user endpoint’s zone.

Returns

  • — verdict: suggest_alternative, no_recommendation, advise_only, insufficient_data, invalid_request or rate_limited.
  • — candidate and alternative: each with time_local (every endpoint, the user last, with offsets), band, confidence and source; alternative also names the limiting_endpoint.
  • — reason_code (always), evidence_level, text (the one sentence to show, when present), explanation (for when someone asks why), data_vintage, spec_version, usage.

BEST_WINDOW

BEST_WINDOW(TASK_CLASS, LOCATIONS, WINDOW, FEASIBILITY, USER_TIMEZONE) RETURNS VARIANT

The steadiest feasible hour inside a window when no time has been proposed yet. A planning call: it returns no sentence to show except for insufficient_data and rate_limited. Separate from PREDICT.BEST_WINDOW, which ranks hours before a deadline.

Parameters

NameTypeRequiredMeaning
TASK_CLASSVARCHARyesAs for CHECK_TIMING.
LOCATIONSVARCHAR (JSON array of 1–2)yesAs for CHECK_TIMING.
WINDOWVARCHAR (JSON object)yes{ "start", "end" } with offsets, at most 12 hours; hours are stepped from start.
FEASIBILITYVARCHAR (JSON object)noAs for CHECK_TIMING.
USER_TIMEZONEVARCHARnoAs for CHECK_TIMING.

Returns

  • — verdict: best_window, no_recommendation, insufficient_data, invalid_request or rate_limited; best in place of candidate and alternative.
  • — reason_code: best_hour, window_uniform (best still reported), no_feasible_hour, insufficient_coverage, or a request or cap code.

EXPLAIN_LAST_VERDICT

EXPLAIN_LAST_VERDICT() RETURNS VARIANT

The calling user’s most recent CHECK_TIMING or BEST_WINDOW verdict within 24 hours, with its explanation; “No timing check has been made yet.” when there is none.

Returns

  • — { "spec_version", "verdict", "explanation" }.

TIMING_WINDOWS

TIMING_WINDOWS(TASK_CLASS, LOCATION, START_TS, END_TS) RETURNS TABLE (HOUR_UTC, BAND, CONFIDENCE)

One row per whole hour from START_TS to END_TS (at most 48 hours) for one place: the band and the confidence, nothing else. Bad input or an unknown place gives an empty table.

Parameters

NameTypeRequiredMeaning
TASK_CLASSVARCHARnoAccepted for symmetry with the other procedures; not used.
LOCATIONVARCHARyesA place name, or a JSON object with query or lat and lon.
START_TS, END_TSVARCHARyesISO 8601 times.

Returns

  • — HOUR_UTC (TIMESTAMP_TZ), BAND (steady, mixed, congested, or NULL where the hour has no data), CONFIDENCE (high or medium).

GET_ENTITLEMENT

GET_ENTITLEMENT() RETURNS VARIANT

Your account (organisation and account name, the key KASPR uses for entitlements), tier, daily and per-minute caps, counted verdicts today, and how many of today’s distinct places you have used.

Returns

  • — { "account", "tier", "daily_cap", "minute_cap", "verdicts_today", "places_today", "place_allowance", "spec_version", "engine" }.

Verdict semantics

Verdicts follow the shared timing-verdict specification, version 0.3, exactly as the hosted MCP server does: the same bands, rules, sentences and reason codes. Every hour of a place’s typical week is steady, mixed or congested relative to that place’s own week; a two-party call is judged by its worse side. A steadier time is suggested only when it is at least one band better and materially so, inside the window and the local hours allowed at every participant.

The full tables of verdict values, bands, sentences and reason codes are in the MCP documentation and apply here unchanged.

Verdict values, bands, sentences and reason codes →

Scheduling procedures (schema PREDICT)

The scheduling procedures mirror the MCP scheduling server’s tools: EXPOSURE_CLASS (a function) classifies a task; BEST_WINDOW ranks the hours between the earliest start and a deadline and decides run now, wait or no good window, with tuning; LATENCY_FORECAST returns the hourly curve for up to 20 places; SCHEDULE_HOLD holds a window and re-scores it every fifteen minutes; REPORT_OUTCOME records how a job went, job metrics only.

Their JSON arguments (the task profile, locations, metrics) are passed as strings, every error carries a fallback of run now, and PREDICT.V_USAGE and PREDICT.V_HOLDS show your calls and holds. The daily allowance of distinct places covers these procedures too (see Entitlements and usage).

Managed MCP servers

The app creates two Snowflake-managed MCP servers. TIMING.KASPR_TIMING offers check_timing, best_window and explain_last_verdict with the same descriptions as the hosted timing server; PREDICT.KASPR_PREDICT offers the five scheduling tools. Both use APP_PUBLIC.

Clients reach them at your account’s REST endpoint and sign in with your account’s own OAuth, through a security integration you create. Object and array arguments are JSON strings, because managed MCP servers pass only scalar arguments to procedures.

In the endpoint, <account> is <org>-<account_name> in lower case with every underscore replaced by a hyphen (for example myorg-my-account): Snowsight shows the underscore form, but a hostname with underscores fails TLS verification. <app> is the name you gave the app when you installed it.

https://<account>.snowflakecomputing.com/api/v2/databases/<app>/schemas/TIMING/mcp-servers/KASPR_TIMING
https://<account>.snowflakecomputing.com/api/v2/databases/<app>/schemas/PREDICT/mcp-servers/KASPR_PREDICT

Connect Claude Code (tested setup)

Run this once as ACCOUNTADMIN. It creates a role for everyday users and an OAuth client for Claude Code. Use a public client with PKCE, which has no secret: a confidential client fails at the token step with invalid_client.

Snowflake blocks ACCOUNTADMIN and SECURITYADMIN from OAuth sign-in, so sign in as a user whose default role is KASPR_USER. To create such a user without writing a password into SQL, create it without one and run ALTER USER <user> RESET PASSWORD; the user sets the password through the single-use link it returns.

CREATE ROLE IF NOT EXISTS KASPR_USER;
GRANT APPLICATION ROLE <app>.APP_PUBLIC TO ROLE KASPR_USER;
GRANT USAGE ON WAREHOUSE <warehouse> TO ROLE KASPR_USER;
GRANT ROLE KASPR_USER TO USER <user>;
ALTER USER <user> SET DEFAULT_ROLE = KASPR_USER DEFAULT_WAREHOUSE = <warehouse>;

CREATE SECURITY INTEGRATION KASPR_PREDICT_MCP
  TYPE = OAUTH OAUTH_CLIENT = CUSTOM OAUTH_CLIENT_TYPE = 'PUBLIC'
  OAUTH_REDIRECT_URI = 'http://localhost:33419/callback'
  OAUTH_ALLOW_NON_TLS_REDIRECT_URI = TRUE  -- the callback only reaches your own machine
  OAUTH_ENFORCE_PKCE = TRUE
  OAUTH_ISSUE_REFRESH_TOKENS = TRUE OAUTH_REFRESH_TOKEN_VALIDITY = 86400
  ENABLED = TRUE;
DESC SECURITY INTEGRATION KASPR_PREDICT_MCP;  -- copy OAUTH_CLIENT_ID
claude mcp add --transport http --scope user kaspr-timing \
  https://<account>.snowflakecomputing.com/api/v2/databases/<app>/schemas/TIMING/mcp-servers/KASPR_TIMING \
  --client-id '<OAUTH_CLIENT_ID>' --callback-port 33419

Start a new Claude Code session, run /mcp, choose kaspr-timing and Authenticate, and sign in. Add kaspr-predict the same way with schemas/PREDICT/mcp-servers/KASPR_PREDICT. Other MCP clients work the same way: register their callback URL as OAUTH_REDIRECT_URI.

Chat in Snowsight (Snowflake Intelligence)

Anyone with access can ask scheduling questions in plain words in Snowflake Intelligence, the chat in Snowsight that Snowflake now also calls CoWork. Examples: “When is the best time this Tuesday evening for a video call between me in Melbourne and Tim in Nairobi?” or “Is 8 PM on Wednesday a good time to stream from Vienna?”. The agent picks check_timing, best_window or explain_last_verdict, fills in the arguments, and answers in plain language; when it does not know a place or a time zone, it asks first.

The app does not ship the agent, because an agent inside an app would need a warehouse privilege. You create it in your own account with one script: it makes the agent KASPR_SCHEDULER in SNOWFLAKE_INTELLIGENCE.AGENTS, with the app’s three timing procedures as tools and the same tool descriptions as the managed MCP server, and lets the role KASPR_USER (see Managed MCP servers) chat with it.

Questions run the app’s procedures in your account on your warehouse, so nothing leaves the account; Snowflake bills the Cortex usage of the chat to you. Each person’s questions count against their own daily allowance of places.

  1. Download the script and replace <app> with the name you gave the app and <warehouse> with a warehouse KASPR_USER can use.
  2. Run it as ACCOUNTADMIN.
  3. Sign in as a KASPR_USER user, open AI & ML → Snowflake Intelligence (or ai.snowflake.com), choose KASPR Scheduler, and ask.

Download kaspr_cortex_agent.sql →

CREATE OR REPLACE AGENT SNOWFLAKE_INTELLIGENCE.AGENTS.KASPR_SCHEDULER
  PROFILE = '{"display_name": "KASPR Scheduler"}'
  FROM SPECIFICATION
$$
models:
  orchestration: auto
tools:
- tool_spec:
    type: generic
    name: check_timing
    ...
tool_resources:
  check_timing:
    type: procedure
    identifier: <app>.TIMING.CHECK_TIMING
    execution_environment: { type: warehouse, warehouse: <warehouse> }
  ...
$$;
GRANT USAGE ON AGENT SNOWFLAKE_INTELLIGENCE.AGENTS.KASPR_SCHEDULER TO ROLE KASPR_USER;
GRANT DATABASE ROLE SNOWFLAKE.CORTEX_USER TO ROLE KASPR_USER;

Pipeline gating

A pipeline asks CHECK_TIMING with task class agent_batch before a network-heavy job and defers, never skips: on suggest_alternative it records the suggested start (the user’s entry in alternative.time_local, listed last) and stops; the next scheduled run after that time runs the job without asking again. Every other verdict, an error, or no answer at all runs the job now.

Example from the app’s test account, for Vienna on a Monday afternoon: at 3 PM the gate defers to 6 PM (“Deferring to 6 PM Vienna (Mon): current window congested, alternative mixed, confidence high.”), at 4 PM it waits, at 6 PM it runs.

-- inside your gate procedure (Snowflake Scripting)
CALL KASPR_PREDICT.TIMING.CHECK_TIMING('agent_batch',
  '[{"label": "me", "query": "Vienna, AT"}]',
  TO_VARCHAR(CURRENT_TIMESTAMP(), 'YYYY-MM-DD"T"HH24:MI:SSTZH:TZM'),
  NULL, '{"local_hours": [0, 24]}', 'Europe/Vienna') INTO :v;
IF (v:verdict::STRING = 'suggest_alternative') THEN
  -- store v:alternative:time_local[last]:time as RUN_AFTER and stop
ELSE
  -- run the job now
END IF;

Entitlements and usage

Every installation starts on the beta tier of the preview, which has no daily or per-minute caps on the timing procedures. Two guardrails apply to every tier: more than 15 distinct places per user per hour answers rate_limited, and each user has a daily allowance of distinct places across every procedure (50 on the beta and free tiers, 500 on pro, 5,000 on platform; places already used that day are free). Over the allowance the timing procedures answer rate_limited (area_limit_reached), TIMING_WINDOWS returns no rows, PREDICT.LATENCY_FORECAST refuses with area_limit, and PREDICT.BEST_WINDOW keeps its decision but leaves out the per-place numbers. KASPR can change an account’s tier from its side without a new release; GET_ENTITLEMENT shows the current one.

Every timing call is recorded per user, as account and user name, in the app’s own state, whatever the tier. Admins read it in TIMING.V_TIMING_USAGE: time, user, task class, verdict, reason code, confidence and whether the call counted toward a cap. Only calls that reach a verdict about the hour count; invalid and rate-limited requests do not.

An admin can set a per-user daily cap with SET_DAILY_CAP(n), and remove it with SET_DAILY_CAP(NULL). It can only lower the tier’s cap, never raise it.

Limits

  • — At most two locations per call; one for broadcast, upload_transfer and agent_batch.
  • — Windows of at most twelve hours; candidate times not earlier than one hour ago, with no upper limit.
  • — TIMING_WINDOWS returns at most 48 hours per call.
  • — A daily allowance of distinct places per user across every procedure: 50 on the beta and free tiers; places already used that day are free. GET_ENTITLEMENT shows how many are used.
  • — A timing call takes a few seconds on an X-Small warehouse.
  • — The forecast is a typical week from a frozen data vintage (2026-07-16), named in every answer; it changes only with a new vintage.

Errors

The timing procedures do not raise errors for bad input or internal failures; they answer with a verdict. Fix the request when the verdict is invalid_request; the reason code says what was wrong.

reason_codeMeaning
missing_fieldA required argument is missing.
bad_task_classTASK_CLASS is not one of the six classes.
too_many_locationsMore than two locations, or more than one for a single-endpoint class.
bad_locationA location is malformed or matches no place.
bad_timeA time could not be read.
time_in_pastThe candidate or the window start is more than an hour ago.
window_too_longThe window is longer than twelve hours.
bad_timezoneUSER_TIMEZONE is not an IANA zone.
bad_feasibilitylocal_hours is not a pair of whole hours.
area_limitPREDICT.LATENCY_FORECAST only: the user’s daily allowance of distinct places is used up (the timing procedures answer rate_limited with reason area_limit_reached instead).
service_unavailableNot a request error: a failure inside the app, answered as a silent no_recommendation that does not count.

Data and privacy

  • — The app reads only its own forecast data, shared from KASPR inside the application package; it references no tables of yours.
  • — All computation runs in your account on your warehouse. The app requests no external access integration and makes no outbound calls.
  • — The places, times and task classes you send, the verdicts with their explanations, and the usage records stay in the app’s own state tables in your account; old records are pruned automatically. KASPR does not see any of it.
  • — Answers carry bands, times and a sentence: no measurements, no area identifiers, no observation counts.

Beta terms of use for the app →

Changelog

DateChange
4 Oct 2026Chat in Snowsight: a script creates the KASPR Scheduler agent for Snowflake Intelligence in your account. Tested Claude Code setup for the managed MCP servers (public OAuth client with PKCE). Free public beta: no billing events.
3 Oct 2026Spec 0.5: a daily allowance of distinct places per user across every procedure; plain-character labels (0.4); bounded place resolution (0.4). GET_ENTITLEMENT shows places_today and place_allowance.
3 Oct 2026Timing procedures (CHECK_TIMING, BEST_WINDOW, EXPLAIN_LAST_VERDICT, TIMING_WINDOWS, GET_ENTITLEMENT) and the managed MCP server KASPR_TIMING, on the shared timing-verdict spec 0.3; cross-checked against the hosted MCP server.
2 Oct 2026Scheduling procedures in PREDICT (EXPOSURE_CLASS, BEST_WINDOW, LATENCY_FORECAST, SCHEDULE_HOLD, REPORT_OUTCOME) and the managed MCP server KASPR_PREDICT; private preview.