Install the Native App for Snowflake
Follow these steps to install and set up the RelationalAI (RAI) Native App for Snowflake.
Review Snowflake Permissions
Section titled “Review Snowflake Permissions”The RelationalAI (RAI) Native App requires several Snowflake privileges to function correctly. You may also grant optional privileges for additional features.
These privileges are described in the tables below.
Required Privileges
Section titled “Required Privileges”These privileges are automatically granted during app installation and cannot be revoked after installation:
| Privilege | Purpose |
|---|---|
EXECUTE TASK, EXECUTE MANAGED TASK | Required to enable the RAI Native App to process and share data from your Snowflake account, including Change Data Capture (CDC) and other automated workflows. |
CREATE WAREHOUSE | Allows the app to automatically create and manage a dedicated Snowflake warehouse (RELATIONAL_AI_ERP_WAREHOUSE) for running queries and integrating with Snowflake features. |
CREATE COMPUTE POOL | Lets the app provision and manage compute pools, which are needed to run reasoners that execute PyRel semantic models and process data within your Snowflake account. |
BIND SERVICE ENDPOINT | Required for Direct Access to Snowpark Container Services from the RAI Native App, which enables lower latency connections for resources. |
Optional Privileges
Section titled “Optional Privileges”These privileges are not required for basic operation of the RAI Native App but are needed for certain features:
| Privilege | Purpose |
|---|---|
IMPORTED PRIVILEGES ON SNOWFLAKE DB | Required for upcoming features that integrate with Snowflake Cortex. |
What installation creates in your account
Section titled “What installation creates in your account”Installing the RAI Native App creates the app’s application database in your Snowflake account. Starting the app then provisions the managed compute resources that the app requires.
App Database
Section titled “App Database”Snowflake installs the RAI Native App as an application database named RELATIONALAI.
This is the database name used in examples such as CALL RELATIONALAI.APP.ACTIVATE().
View the app database schema and contents.
| Schema Name | Description |
|---|---|
APP | Contains the SQL procedures for managing the app. See the API reference for more details. |
APP_STATE | Stores internal app state, service metadata, and task state used by the Native App. |
API | Contains the SQL procedures that provide direct access to RAI services and features, like reasoners and jobs. See the API reference for more details. |
BILLING | Contains billing views, procedures, and billing event records. |
CONSUMPTION | Contains consumption records and views for consumption-based billing. |
DEBUG | Contains internal debugging procedures. |
LOGGING | Contains internal application logs. |
OBSERVABILITY | Contains internal observability objects. |
OBSERVABILITY_PREVIEW | Contains observability views for reasoner CPU, memory, and demand metrics. |
RAI_ENGINE | Contains internal objects used to manage reasoner engine services. |
RAI_ML | Contains internal objects used by predictive and machine learning services. |
RAI_MODELER | Contains internal objects used by modeler services. |
RAI_SOLVER | Contains internal objects used to manage prescriptive solver services. |
SPCS | Contains internal Snowpark Container Services objects and procedures used to operate the app service layer. |
UTIL | Contains internal helper functions and procedures used by the app. |
App Warehouse
Section titled “App Warehouse”The RAI Native App uses an X-SMALL Snowflake warehouse for Snowflake interoperability.
This warehouse is named RELATIONAL_AI_ERP_WAREHOUSE and is fully managed by the native app.
It is automatically provisioned when you start the app and suspended when you shut down the app.
Compute Pools
Section titled “Compute Pools”Snowflake compute pools are collections of compute resources managed as a shared pool. The RAI Native App uses them for internal services and to host the reasoners that process queries from PyRel semantic models.
These compute pools are provisioned or resumed when you start the app. They are suspended when you shut down the app, and some shutdown modes can drop them entirely.
The RAI Native App manages the following compute pools for internal operations and reasoners:
| Name | Snowflake Instance Family | Supported Cloud Platforms | Description |
|---|---|---|---|
RELATIONAL_AI_ERP_COMPUTE_POOL | CPU_X64_XS | AWS, Azure | Used for internal app operations. |
RELATIONAL_AI_COMPILE_CACHE_SPCS | HIGHMEM_X64_M | AWS, Azure | Used for internal app operations. |
RELATIONAL_AI_HIGHMEM_X64_S | HIGHMEM_X64_S | AWS, Azure | Runs logic, prescriptive, and predictive reasoners that execute queries from semantic models. |
RELATIONAL_AI_HIGHMEM_X64_M | HIGHMEM_X64_M | AWS, Azure | Runs logic, prescriptive, and predictive reasoners that execute queries from semantic models. |
RELATIONAL_AI_HIGHMEM_X64_L | HIGHMEM_X64_L | AWS only | Runs logic and predictive reasoners that execute queries from semantic models. |
RELATIONAL_AI_HIGHMEM_X64_SL | HIGHMEM_X64_SL | Azure only | Runs logic reasoners that execute queries from semantic models. |
RELATIONAL_AI_GPU_NV_S | GPU_NV_S | AWS only | Runs GPU-backed predictive reasoners that execute queries from semantic models. |
RELATIONAL_AI_GPU_NV_SM | GPU_NV_SM | Azure only | Runs GPU-backed predictive reasoners that execute queries from semantic models. |
RELATIONAL_AI_CPU_X64_S | CPU_X64_S | AWS, Azure | Reserved for future use. |
RELATIONAL_AI_CPU_X64_M | CPU_X64_M | AWS, Azure | Reserved for future use. |
If a pool has no reserved nodes and no running reasoners, it does not incur compute charges. Reserved node capacity is billed even when no reasoners are running. See Understand and optimize costs for more information.
Request Access
Section titled “Request Access”-
Log in to the Snowflake web interface (Snowsight) as an
ORGADMINorACCOUNTADMIN. -
View the RelationalAI marketplace listing and fill out the access request form.
-
A RelationalAI representative will notify you when access is enabled for your account.
Install the App
Section titled “Install the App”Once access is enabled, navigate to Catalog > Apps in the left-hand sidebar of the Snowflake web interface. You should see RelationalAI under Recently shared with you.
-
Click Buy to open a dialogue box with pricing details. Click the Buy button in the dialogue box to proceed. Click “View your apps” in the resulting modal to go back to the Catalog > Apps page. You should see RelationalAI listed under Installed Apps.
-
You may see a spinner in the INSTALLED column, indicating that the app is still being installed. Wait until installation completes, at which point you’ll see a message like “1 minute ago” in that column.
-
Click on the name of the application to open the app.
-
Click Activate to activate the application.
Set Up the App
Section titled “Set Up the App”To finalize the installation, you need to execute a few SQL commands to set up and configure the app. You can do this in a Snowflake notebook, a SQL worksheet, or using the SnowSQL command-line client.
To complete the steps in this section:
- Download the installation notebook.
View a preview of the installation notebook.
RelationalAI Native App Setup Guide
🚨 Note that the
ACCOUNTADMINrole is used in this guide. This role is needed for Step 1 and for creating the network rule in Step 4. To manage roles specific the RelationalAI Native App, see Appendix 2 at the bottom of this notebook.USE ROLE ACCOUNTADMIN;Step 1 - Activate the RAI Native App
Execute the following three cells to create the RAI service (this usually takes between 5 and 15 minutes):
import sysimport timeimport jsonimport itertoolsfrom snowflake.snowpark.context import get_active_sessionsession = get_active_session()def poll(f):last_message = ""dots = itertools.cycle(["⠧", "⠏", "⠛", "⠹", "⠼", "⠶"])def status(message):spaces = " " * (len("⠿ " + last_message) - len(message))sys.stdout.write("\r" + message + spaces)sys.stdout.flush()for ctr in itertools.count():if ctr % 10 == 0:result = f()if isinstance(result, str):message = next(dots) + " " + resultstatus(message)last_message = resultif result is True:status("⠿ Done!")returnelse:message = next(dots) + " " + last_messagestatus(message)time.sleep(0.5)def activate():try:session.sql("CALL RELATIONALAI.APP.ACTIVATE();").collect()return Trueexcept Exception as e:if "Unknown user-defined function" in str(e):return "Waiting for app installation to complete..."else:raise epoll(activate)def check():result = session.sql("CALL RELATIONALAI.APP.SERVICE_STATUS();").collect()status = json.loads(result[0]["SERVICE_STATUS"])[0]["message"]if status is None:status = ""elif status.startswith("UNKNOWN"):status = "Working"elif status.startswith("Readiness probe"):status = "Almost done"elif status == "Running":return Trueelse:return status + "..."poll(check)🚨 Note: Please review the documentation on upgrades for details about the weekly automatic upgrade schedule.
Step 2 - Setting up Change Data Capture
Streams share Snowflake data with the RAI Native App using change data capture (CDC) to capture source table and view changes once every minute.
To enable CDC, run the following command:
CALL RELATIONALAI.APP.RESUME_CDC();Step 3 - Creating user roles
The RAI Native App comes with a set of Snowflake application roles for managing access to the app. Application roles can’t be granted to users directly, and must be granted to Snowflake database roles instead.
The following SQL creates two database roles:
rai_adminandrai_developer. Therai_adminrole is for full admin access to the RAI Native App, while therai_developerrole is for developers who need access to the RAI Python API:-- Create a rai_admin role for full admin access to the RAI Native App.CREATE ROLE rai_admin;-- Link the app's `all_admin` role to the created role.GRANT APPLICATION ROLE relationalai.all_admin TO ROLE rai_admin;-- Create a role for developers who need access to the RAI Python API.CREATE ROLE rai_developer;-- Link the app's `rai_user` role to the created role.GRANT APPLICATION ROLE relationalai.rai_user TO ROLE rai_developer;Users granted the
rai_developerrole can:- Use the RAI Native App.
- Create, use, and delete RAI reasoners.
- Create, manage, and delete data streams.
- Enable and disable the CDC service.
You can grant the
rai_developerrole to users in your Snowflake account using theGRANT ROLE rai_developer TO USER "username";command. For example, to grant therai_developerrole to yourself, run the following cell:# optional: grant the rai_developer role to yourselfsession = get_active_session()current_user = session.sql("SELECT CURRENT_USER() AS USERNAME;").collect()[0]["USERNAME"]session.sql(f'GRANT ROLE rai_developer TO USER "{current_user}"').collect()Our Simple Start template uses a table called
RAI_DEMO.SIMPLE_START.CONNECTIONS. If you want to be able to run that notebook, either grant permissions to therai_developerrole or run the following SQL to create the table now. You can clean up this database when you’re done with the demo notebook by runningDROP DATABASE RAI_DEMO CASCADE;CREATE DATABASE IF NOT EXISTS RAI_DEMO;CREATE SCHEMA IF NOT EXISTS RAI_DEMO.SIMPLE_START;CREATE OR REPLACE TABLE RAI_DEMO.SIMPLE_START.CONNECTIONS (STATION_1 INT,STATION_2 INT);INSERT INTO RAI_DEMO.SIMPLE_START.CONNECTIONS (STATION_1, STATION_2) VALUES(1, 2),(1, 3),(3, 4),(1, 4),(4, 5),(5, 7),(6, 7),(6, 8),(7, 8);GRANT USAGE ON DATABASE RAI_DEMO TO ROLE rai_developer;GRANT USAGE ON SCHEMA RAI_DEMO.SIMPLE_START TO ROLE rai_developer;GRANT SELECT ON TABLE RAI_DEMO.SIMPLE_START.CONNECTIONS TO ROLE rai_developer;ALTER TABLE RAI_DEMO.SIMPLE_START.CONNECTIONS SET CHANGE_TRACKING = TRUE;-- optional: give rai_developer more extensive permissions in the RAI_DEMO database-- this step is necessary for the user to be able to run all the demo notebooksGRANT CREATE SCHEMA ON DATABASE RAI_DEMO TO ROLE rai_developer;GRANT CREATE TABLE ON SCHEMA RAI_DEMO.SIMPLE_START TO ROLE rai_developer;GRANT CREATE TABLE ON FUTURE SCHEMAS IN DATABASE RAI_DEMO TO ROLE rai_developer;GRANT SELECT ON ALL TABLES IN SCHEMA RAI_DEMO.SIMPLE_START TO ROLE rai_developer;GRANT SELECT ON FUTURE TABLES IN DATABASE RAI_DEMO TO ROLE rai_developer;Step 4 — Set Up Snowflake Notebooks
Snowflake has two notebook experiences: Notebooks in Workspaces and Legacy Notebooks. We recommend Notebooks in Workspaces for all new work. This step sets up Notebooks in Workspaces, and it also includes setup for Legacy Notebooks in case your account still needs them.
🚨 Note: Snowflake renamed the original notebook experience to Legacy Notebooks. New accounts created after April 2026 can’t create Legacy Notebooks, and Snowflake will turn off creation for all other accounts on September 1, 2026. Use Notebooks in Workspaces for new work.
First, give RelationalAI access to Snowflake stage storage. RelationalAI moves some data through Snowflake stages, which are Snowflake’s built-in storage locations for files. The code below creates an External Access Integration — the network setup that lets RelationalAI reach those stages. Several RelationalAI features rely on this access, and a Legacy Notebook that runs on a warehouse needs it to return query results. It reads the stage hosts Snowflake lists for your account with
SYSTEM$ALLOWLIST(), then allows traffic only to those hosts and to no other internet destination. Whether traffic to those hosts stays on a private network depends on your account’s Snowflake network settings.Run this code to create the integration:
session = get_active_session()system_allowlist = session.sql("""SELECT value:host AS URLFROM TABLE(FLATTEN(input=>parse_json(SYSTEM$ALLOWLIST())))WHERE value:type = 'STAGE'""").collect()if system_allowlist:urls = ", ".join(row.URL.replace('"', "'") for row in system_allowlist)egress_rule_commands = [f"""CREATE OR REPLACE NETWORK RULE S3_RAI_INTERNAL_BUCKET_EGRESSMODE = EGRESSTYPE = HOST_PORTVALUE_LIST = ({urls});""","""CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION S3_RAI_INTERNAL_BUCKET_EGRESS_INTEGRATIONALLOWED_NETWORK_RULES = (S3_RAI_INTERNAL_BUCKET_EGRESS)ENABLED = true;""","""GRANT USAGE ON INTEGRATION S3_RAI_INTERNAL_BUCKET_EGRESS_INTEGRATION TO ROLE rai_developer;"""]for command in egress_rule_commands:session.sql(command).collect()print("Network rule set up successfully.")Notebooks in Workspaces
A Workspaces notebook uses two Snowflake compute resources:
- A compute pool runs the notebook’s Python code.
- A query warehouse runs the SQL queries and other Snowflake compute the notebook triggers.
Run the following SQL to create a warehouse and compute pool for your notebooks, then give the
rai_developerrole access to both:CREATE WAREHOUSE notebooks_wh;CREATE COMPUTE POOL NOTEBOOK_CPU_XSMIN_NODES = 1MAX_NODES = 15INSTANCE_FAMILY = CPU_X64_XSAUTO_RESUME = trueAUTO_SUSPEND_SECS = 1800COMMENT = "Pool for Snowflake Notebooks in Workspaces";GRANT USAGE ON WAREHOUSE notebooks_wh TO ROLE rai_developer;GRANT USAGE ON COMPUTE POOL NOTEBOOK_CPU_XS TO ROLE rai_developer;Now anyone with the
rai_developerrole can create a notebook in Projects > Workspaces. When they open the notebook, they connect it to a notebook service — the container that runs the notebook’s Python — and point that service at theNOTEBOOK_CPU_XScompute pool. They also select therai_developerrole and theNOTEBOOKS_WHwarehouse in the role and warehouse picker at the top left.The setup worked if
NOTEBOOK_CPU_XSandNOTEBOOKS_WHappear as options and the notebook connects.Workspaces notebooks can install the
relationalaipackage from Snowflake’s built-in package repository, which is available to all roles by default. You only need extra network setup to install packages from outside Snowflake or to reach other external services.Legacy Notebooks
Legacy Notebooks are Snowflake’s classic notebook experience, which you open from Projects > Notebooks. Snowflake is retiring Legacy Notebooks, and these instructions will be removed after Snowflake disables Legacy Notebook creation on September 1, 2026. Set one up only if your account already depends on it, and skip this subsection if you use Notebooks in Workspaces.
A Legacy Notebook runs on one of two runtimes:
- Container Runtime runs the notebook’s Python on a compute pool, the same way Notebooks in Workspaces do.
- Warehouse Runtime runs the notebook’s Python on a warehouse.
Both runtimes store the notebook in a database and need permission to create notebooks, which the SQL below sets up. A Container Runtime notebook runs its Python on the
NOTEBOOK_CPU_XScompute pool and its SQL on theNOTEBOOKS_WHwarehouse you created above. It also needs permission to create services and — to install packages from PyPI — its own External Access Integration. A Warehouse Runtime notebook runs on theNOTEBOOKS_WHwarehouse you created above and relies on the stage integration you created at the start of this step to return query results.If you use Legacy Notebooks, uncomment and run the SQL below:
-- Set up resources for Legacy Notebooks. Uncomment these statements only if you use Legacy Notebooks.-- CREATE DATABASE IF NOT EXISTS rai_notebooks;-- GRANT USAGE ON DATABASE rai_notebooks TO ROLE rai_developer;-- GRANT USAGE ON SCHEMA rai_notebooks.public TO ROLE rai_developer;-- GRANT CREATE NOTEBOOK ON SCHEMA rai_notebooks.public TO ROLE rai_developer;-- GRANT CREATE SERVICE ON SCHEMA rai_notebooks.public TO ROLE rai_developer;-- Allow Container Runtime notebooks to install packages from PyPI.-- CREATE OR REPLACE NETWORK RULE pypi_network_rule-- MODE = EGRESS-- TYPE = HOST_PORT-- VALUE_LIST = ('pypi.org', 'pypi.python.org', 'pythonhosted.org', 'files.pythonhosted.org');-- CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION pypi_access_integration-- ALLOWED_NETWORK_RULES = (pypi_network_rule)-- ENABLED = true;-- GRANT USAGE ON INTEGRATION pypi_access_integration TO ROLE rai_developer;Step 5 - Set Up Direct Access
By default, Python API calls are routed through Snowflake Service Functions, which adds some extra overhead to every request. Direct Access allows connections straight to the RAI Native App’s secure web address, skipping the middleman and reducing latency—often by about 500ms.
🚨 Note: Snowflake notebooks can’t use Direct Access because of network restrictions in those environments. This applies to both Notebooks in Workspaces and Legacy Notebooks. If you only plan to use RelationalAI from a Snowflake notebook, and not from a local Python environment, you can skip this step.
Currently, Direct Access only supports three authentication methods: OAuth, Personal Access Token (PAT), and key-pair. We recommend creating an OAuth security integration for Direct Access now so that users can authenticate interactively in their local development environments. PAT or key-pair authentication can be set up later for applications and automation.
To create an OAuth security integration, execute the following SQL:
-- Create a public OAuth client for Direct Access.CREATE SECURITY INTEGRATION RAI_SECURITY_INTEGRATIONTYPE = OAUTHENABLED = TRUEOAUTH_CLIENT = CUSTOMOAUTH_CLIENT_TYPE = 'PUBLIC' -- or 'CONFIDENTIAL' if neededOAUTH_ALLOW_NON_TLS_REDIRECT_URI = TRUEOAUTH_REDIRECT_URI = 'http://localhost:8001/snowflake/oauth-redirect'OAUTH_ISSUE_REFRESH_TOKENS = TRUEOAUTH_REFRESH_TOKEN_VALIDITY = 86400; -- Time in secondsNote that the redirect URI can be any localhost URI, but the port must be open on the user’s machine. Now, run the following SQL to retrieve the client ID:
-- Inspect the created integration. Change the integration name if you used-- a different one in step 1.DESC SECURITY INTEGRATION RAI_SECURITY_INTEGRATION;Share the client ID, client secret (if applicable), and redirect URI with users so they can configure their Direct Access connection locally.
Step 6 - Enable Warm Reasoners (Optional)
Warm reasoners are pre-provisioned RAI reasoners that can reduce latency for workloads that require quick startup times.
We recommend enabling a warm
logicreasoner for at least one reasoner size to get the best performance when using the RAI Native App. To enable a warmlogicreasoner of sizeHIGHMEM_X64_S, run the following SQL command:-- Note: Warm reasoners incur additional costs. If you want to enable warm reasoners,-- uncomment the line below and run it.-- CALL RELATIONALAI.APP.ENABLE_WARM_REASONER('logic', 'HIGHMEM_X64_S');See the Warm Reasoners documentation for more information on warm reasoners and how to manage them.
Congratulations! Your RelationalAI app is now ready to use.
Next Steps
To get up and running with RelationalAI, download the Simple Start template, extract the files,and follow the instructions in the
READMEfile and thesimple-start.ipynbnotebook.For a more detailed example and more information about the RelationalAI Python library, check out the documentation.
Links:
- Simple Start Notebook: https://relational.ai/build/templates/simple-start
- All templates: https://docs.relational.ai/build/templates
- Docs: https://docs.relational.ai
APPENDIX 1 - Deactivate the RAI Native App
To reduce costs when you are not using the RAI Native App, suspend CDC, and delete all reasoners.
🚨 Note that this task requires the
app_adminapplication role.session = get_active_session()# note: the use of `skip_appendix` in the Appendices makes the notebook's# "Run All" action skip these cellsskip_appendix = True# Deactivate the appif not skip_appendix:session.sql("CALL RELATIONALAI.APP.DEACTIVATE();").collect()# To re-activate the app:# session.sql("CALL RELATIONALAI.APP.ACTIVATE();").collect()APPENDIX 2 - App Upgrades
Your RAI Native App is automatically upgraded every Monday at 10:00 UTC. During upgrades, the application cannot process RAI transactions.
If you prefer to schedule upgrades for a different day and time, use the
schedule_upgrade()procedure:if not skip_appendix:# Schedule upgrades for Wednesdays at 15:00 UTC. Times are in 24-hour format.session.sql("CALL relationalai.app.schedule_upgrade('WEDNESDAY', '15:00');").collect() - Go to https://app.snowflake.com and select Projects > Workspaces.
- Open a workspace, select + next to the destination folder, and select Upload Files. If this is your first workspace, select + Add New first.
- Upload and open
relationalai-installation.ipynb. - Connect the notebook to a notebook service backed by a CPU compute pool that
ACCOUNTADMINcan use. A notebook service is a container that runs the notebook’s Python code. Snowflake’sSYSTEM_COMPUTE_POOL_CPUworks, or pick another compute pool set up for notebooks. - In the role and warehouse picker, select
ACCOUNTADMINand an existing query warehouse. - Select Run all, or run the cells one at a time.
If you prefer not to use a Snowflake notebook, you can instead complete the app installation by copying the code block below and pasting it into a Snowflake SQL worksheet to run it.
/*Before running this worksheet, replace <db> and <schema> below with adatabase name and schema name from your account.This schema will be used by the worksheet to store temporary storedprocedures which are dropped immediately after they are called.Note also that some of the operations in the worksheet requireaccountadmin privileges*/
USE DATABASE <db>;USE SCHEMA <schema>;
/*# RelationalAI Native App Setup Guide*/
/*> 🚨 Note that the `ACCOUNTADMIN` role is used in this guide. This role isneeded for Step 1 and for creating the network rule in Step 4. To manageroles specific the RelationalAI Native App, see Appendix 2 at the bottomof this notebook.*/
USE ROLE ACCOUNTADMIN;
/*## Step 1 - Activate the RAI Native App*/
/*Execute the following three cells to create the RAI service (this usuallytakes between 5 and 15 minutes):*/
BEGIN
CREATE OR REPLACE PROCEDURE rai_installation_step()RETURNS STRINGLANGUAGE PYTHONRUNTIME_VERSION = '3.10'PACKAGES = ('snowflake-snowpark-python')HANDLER = 'main'EXECUTE AS CALLERAS$$def main(session):
import sys import time import json import itertools from snowflake.snowpark.context import get_active_session
def poll(f):
last_message = "" dots = itertools.cycle([".", ".", ".", ".", ".", "."])
def status(message): spaces = " " * (len(". " + last_message) - len(message)) sys.stdout.write("\r" + message + spaces) sys.stdout.flush()
for ctr in itertools.count(): if ctr % 10 == 0: result = f() if isinstance(result, str): message = next(dots) + " " + result status(message) last_message = result if result is True: status(". Done!") return else: message = next(dots) + " " + last_message status(message) time.sleep(0.5)
def activate(): try: session.sql("CALL RELATIONALAI.APP.ACTIVATE();").collect() return True except Exception as e: if "Unknown user-defined function" in str(e): return "Waiting for app installation to complete..." else: raise e
poll(activate)
return "Step completed"$$;
CALL rai_installation_step();
DROP PROCEDURE rai_installation_step();
RETURN 'Step completed';END;
BEGIN
CREATE OR REPLACE PROCEDURE rai_installation_step()RETURNS STRINGLANGUAGE PYTHONRUNTIME_VERSION = '3.10'PACKAGES = ('snowflake-snowpark-python')HANDLER = 'main'EXECUTE AS CALLERAS$$def main(session):
import sys import time import json import itertools from snowflake.snowpark.context import get_active_session
def poll(f):
last_message = "" dots = itertools.cycle([".", ".", ".", ".", ".", "."])
def status(message): spaces = " " * (len(". " + last_message) - len(message)) sys.stdout.write("\r" + message + spaces) sys.stdout.flush()
for ctr in itertools.count(): if ctr % 10 == 0: result = f() if isinstance(result, str): message = next(dots) + " " + result status(message) last_message = result if result is True: status(". Done!") return else: message = next(dots) + " " + last_message status(message) time.sleep(0.5)
def check(): result = session.sql("CALL RELATIONALAI.APP.SERVICE_STATUS();").collect() status = json.loads(result[0]["SERVICE_STATUS"])[0]["message"] if status is None: status = "" elif status.startswith("UNKNOWN"): status = "Working" elif status.startswith("Readiness probe"): status = "Almost done" elif status == "Running": return True else: return status + "..."
poll(check)
return "Step completed"$$;
CALL rai_installation_step();
DROP PROCEDURE rai_installation_step();
RETURN 'Step completed';END;
/*> 🚨 Note: Please review the documentation on upgrades for details aboutthe weekly automatic upgrade schedule.*/
/*## Step 2 - Setting up Change Data Capture*/
/*Streams share Snowflake data with the RAI Native App using change datacapture (CDC) to capture source table and view changes once every minute.*/
/*To enable CDC, run the following command:*/
CALL RELATIONALAI.APP.RESUME_CDC();
/*## Step 3 - Creating user roles*/
/*The RAI Native App comes with a set of Snowflake application roles formanaging access to the app. Application roles can't be granted to usersdirectly, and must be granted to Snowflake database roles instead.*/
/*The following SQL creates two database roles: `rai_admin` and`rai_developer`. The `rai_admin` role is for full admin access to the RAINative App, while the `rai_developer` role is for developers who needaccess to the RAI Python API:*/
-- Create a rai_admin role for full admin access to the RAI Native App.CREATE ROLE rai_admin;-- Link the app's `all_admin` role to the created role.GRANT APPLICATION ROLE relationalai.all_admin TO ROLE rai_admin;
-- Create a role for developers who need access to the RAI Python API.CREATE ROLE rai_developer;-- Link the app's `rai_user` role to the created role.GRANT APPLICATION ROLE relationalai.rai_user TO ROLE rai_developer;
/*Users granted the `rai_developer` role can:*/
/*- Use the RAI Native App. - Create, use, and delete RAI reasoners. -Create, manage, and delete data streams. - Enable and disable the CDCservice.*/
/*You can grant the `rai_developer` role to users in your Snowflake accountusing the `GRANT ROLE rai_developer TO USER "username";` command. Forexample, to grant the `rai_developer` role to yourself, run the followingcell:*/
BEGIN
CREATE OR REPLACE PROCEDURE rai_installation_step()RETURNS STRINGLANGUAGE PYTHONRUNTIME_VERSION = '3.10'PACKAGES = ('snowflake-snowpark-python')HANDLER = 'main'EXECUTE AS CALLERAS$$def main(session):
# optional: grant the rai_developer role to yourself current_user = session.sql("SELECT CURRENT_USER() AS USERNAME;").collect()[0]["USERNAME"]
session.sql(f'GRANT ROLE rai_developer TO USER "{current_user}"').collect()
return "Step completed"$$;
CALL rai_installation_step();
DROP PROCEDURE rai_installation_step();
RETURN 'Step completed';END;
/*Our Simple Start template uses a table called`RAI_DEMO.SIMPLE_START.CONNECTIONS`. If you want to be able to run thatnotebook, either grant permissions to the `rai_developer` role or run thefollowing SQL to create the table now. You can clean up this database whenyou're done with the demo notebook by running `DROP DATABASE RAI_DEMOCASCADE;`*/
CREATE DATABASE IF NOT EXISTS RAI_DEMO;CREATE SCHEMA IF NOT EXISTS RAI_DEMO.SIMPLE_START;
CREATE OR REPLACE TABLE RAI_DEMO.SIMPLE_START.CONNECTIONS ( STATION_1 INT, STATION_2 INT);
INSERT INTO RAI_DEMO.SIMPLE_START.CONNECTIONS (STATION_1, STATION_2) VALUES(1, 2),(1, 3),(3, 4),(1, 4),(4, 5),(5, 7),(6, 7),(6, 8),(7, 8);
GRANT USAGE ON DATABASE RAI_DEMO TO ROLE rai_developer;GRANT USAGE ON SCHEMA RAI_DEMO.SIMPLE_START TO ROLE rai_developer;GRANT SELECT ON TABLE RAI_DEMO.SIMPLE_START.CONNECTIONS TO ROLE rai_developer;ALTER TABLE RAI_DEMO.SIMPLE_START.CONNECTIONS SET CHANGE_TRACKING = TRUE;
-- optional: give rai_developer more extensive permissions in the RAI_DEMO database-- this step is necessary for the user to be able to run all the demo notebooksGRANT CREATE SCHEMA ON DATABASE RAI_DEMO TO ROLE rai_developer;GRANT CREATE TABLE ON SCHEMA RAI_DEMO.SIMPLE_START TO ROLE rai_developer;GRANT CREATE TABLE ON FUTURE SCHEMAS IN DATABASE RAI_DEMO TO ROLE rai_developer;GRANT SELECT ON ALL TABLES IN SCHEMA RAI_DEMO.SIMPLE_START TO ROLE rai_developer;GRANT SELECT ON FUTURE TABLES IN DATABASE RAI_DEMO TO ROLE rai_developer;
/*## Step 4 — Set Up Snowflake Notebooks*/
/*Snowflake has two notebook experiences: *Notebooks in Workspaces* and*Legacy Notebooks*. We recommend Notebooks in Workspaces for all new work.This step sets up Notebooks in Workspaces, and it also includes setup forLegacy Notebooks in case your account still needs them.*/
/*> 🚨 Note: Snowflake renamed the original notebook experience to *LegacyNotebooks*. > New accounts created after April 2026 can't create LegacyNotebooks, and Snowflake will turn off creation for all other accounts onSeptember 1, 2026. > Use Notebooks in Workspaces for new work.*/
/*First, give RelationalAI access to Snowflake stage storage. RelationalAImoves some data through *Snowflake stages*, which are Snowflake's built-instorage locations for files. The code below creates an External AccessIntegration — the network setup that lets RelationalAI reach those stages.Several RelationalAI features rely on this access, and a Legacy Notebookthat runs on a warehouse needs it to return query results. It reads thestage hosts Snowflake lists for your account with `SYSTEM$ALLOWLIST()`,then allows traffic only to those hosts and to no other internetdestination. Whether traffic to those hosts stays on a private networkdepends on your account's Snowflake network settings.*/
/*Run this code to create the integration:*/
BEGIN
CREATE OR REPLACE PROCEDURE rai_installation_step()RETURNS STRINGLANGUAGE PYTHONRUNTIME_VERSION = '3.10'PACKAGES = ('snowflake-snowpark-python')HANDLER = 'main'EXECUTE AS CALLERAS$$def main(session):
system_allowlist = session.sql(""" SELECT value:host AS URL FROM TABLE(FLATTEN(input=>parse_json(SYSTEM$ALLOWLIST()))) WHERE value:type = 'STAGE' """).collect()
if system_allowlist: urls = ", ".join(row.URL.replace('"', "'") for row in system_allowlist) egress_rule_commands = [ f""" CREATE OR REPLACE NETWORK RULE S3_RAI_INTERNAL_BUCKET_EGRESS MODE = EGRESS TYPE = HOST_PORT VALUE_LIST = ({urls}); """, """ CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION S3_RAI_INTERNAL_BUCKET_EGRESS_INTEGRATION ALLOWED_NETWORK_RULES = (S3_RAI_INTERNAL_BUCKET_EGRESS) ENABLED = true; """, """ GRANT USAGE ON INTEGRATION S3_RAI_INTERNAL_BUCKET_EGRESS_INTEGRATION TO ROLE rai_developer; """ ]
for command in egress_rule_commands: session.sql(command).collect()
print("Network rule set up successfully.")
return "Step completed"$$;
CALL rai_installation_step();
DROP PROCEDURE rai_installation_step();
RETURN 'Step completed';END;
/*### Notebooks in Workspaces*/
/*A Workspaces notebook uses two Snowflake compute resources:*/
/*- A *compute pool* runs the notebook's Python code. - A *query warehouse*runs the SQL queries and other Snowflake compute the notebook triggers.*/
/*Run the following SQL to create a warehouse and compute pool for yournotebooks, then give the `rai_developer` role access to both:*/
CREATE WAREHOUSE notebooks_wh;
CREATE COMPUTE POOL NOTEBOOK_CPU_XS MIN_NODES = 1 MAX_NODES = 15 INSTANCE_FAMILY = CPU_X64_XS AUTO_RESUME = true AUTO_SUSPEND_SECS = 1800 COMMENT = "Pool for Snowflake Notebooks in Workspaces";
GRANT USAGE ON WAREHOUSE notebooks_wh TO ROLE rai_developer;GRANT USAGE ON COMPUTE POOL NOTEBOOK_CPU_XS TO ROLE rai_developer;
/*Now anyone with the `rai_developer` role can create a notebook in**Projects > Workspaces**. When they open the notebook, they connect it toa *notebook service* — the container that runs the notebook's Python — andpoint that service at the `NOTEBOOK_CPU_XS` compute pool. They also selectthe `rai_developer` role and the `NOTEBOOKS_WH` warehouse in the role andwarehouse picker at the top left.*/
/*The setup worked if `NOTEBOOK_CPU_XS` and `NOTEBOOKS_WH` appear as optionsand the notebook connects.*/
/*Workspaces notebooks can install the `relationalai` package fromSnowflake's built-in package repository, which is available to all rolesby default. You only need extra network setup to install packages fromoutside Snowflake or to reach other external services.*/
/*### Legacy Notebooks*/
/*Legacy Notebooks are Snowflake's classic notebook experience, which youopen from **Projects > Notebooks**. Snowflake is retiring LegacyNotebooks, and these instructions will be removed after Snowflake disablesLegacy Notebook creation on September 1, 2026. Set one up only if youraccount already depends on it, and skip this subsection if you useNotebooks in Workspaces.*/
/*A Legacy Notebook runs on one of two runtimes:*/
/*- *Container Runtime* runs the notebook's Python on a compute pool, thesame way Notebooks in Workspaces do. - *Warehouse Runtime* runs thenotebook's Python on a warehouse.*/
/*Both runtimes store the notebook in a database and need permission tocreate notebooks, which the SQL below sets up. A Container Runtimenotebook runs its Python on the `NOTEBOOK_CPU_XS` compute pool and its SQLon the `NOTEBOOKS_WH` warehouse you created above. It also needspermission to create services and — to install packages from PyPI — itsown External Access Integration. A Warehouse Runtime notebook runs on the`NOTEBOOKS_WH` warehouse you created above and relies on the stageintegration you created at the start of this step to return query results.*/
/*If you use Legacy Notebooks, uncomment and run the SQL below:*/
-- Set up resources for Legacy Notebooks. Uncomment these statements only if you use Legacy Notebooks.
-- CREATE DATABASE IF NOT EXISTS rai_notebooks;-- GRANT USAGE ON DATABASE rai_notebooks TO ROLE rai_developer;-- GRANT USAGE ON SCHEMA rai_notebooks.public TO ROLE rai_developer;-- GRANT CREATE NOTEBOOK ON SCHEMA rai_notebooks.public TO ROLE rai_developer;-- GRANT CREATE SERVICE ON SCHEMA rai_notebooks.public TO ROLE rai_developer;
-- Allow Container Runtime notebooks to install packages from PyPI.-- CREATE OR REPLACE NETWORK RULE pypi_network_rule-- MODE = EGRESS-- TYPE = HOST_PORT-- VALUE_LIST = ('pypi.org', 'pypi.python.org', 'pythonhosted.org', 'files.pythonhosted.org');-- CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION pypi_access_integration-- ALLOWED_NETWORK_RULES = (pypi_network_rule)-- ENABLED = true;-- GRANT USAGE ON INTEGRATION pypi_access_integration TO ROLE rai_developer;
/*## Step 5 - Set Up Direct Access*/
/*By default, Python API calls are routed through Snowflake ServiceFunctions, which adds some extra overhead to every request. Direct Accessallows connections straight to the RAI Native App’s secure web address,skipping the middleman and reducing latency—often by about 500ms.*/
/*> 🚨 Note: Snowflake notebooks can't use Direct Access because of networkrestrictions in those environments. > This applies to both Notebooks inWorkspaces and Legacy Notebooks. > If you only plan to use RelationalAIfrom a Snowflake notebook, and not from a local Python environment, youcan skip this step.*/
/*Currently, Direct Access only supports three authentication methods:OAuth, Personal Access Token (PAT), and key-pair. We recommend creating anOAuth security integration for Direct Access now so that users canauthenticate interactively in their local development environments. PAT orkey-pair authentication can be set up later for applications andautomation.*/
/*To create an OAuth security integration, execute the following SQL:*/
-- Create a public OAuth client for Direct Access.CREATE SECURITY INTEGRATION RAI_SECURITY_INTEGRATION TYPE = OAUTH ENABLED = TRUE OAUTH_CLIENT = CUSTOM OAUTH_CLIENT_TYPE = 'PUBLIC' -- or 'CONFIDENTIAL' if needed OAUTH_ALLOW_NON_TLS_REDIRECT_URI = TRUE OAUTH_REDIRECT_URI = 'http://localhost:8001/snowflake/oauth-redirect' OAUTH_ISSUE_REFRESH_TOKENS = TRUE OAUTH_REFRESH_TOKEN_VALIDITY = 86400; -- Time in seconds
/*Note that the redirect URI can be any localhost URI, but the port must beopen on the user's machine. Now, run the following SQL to retrieve theclient ID:*/
-- Inspect the created integration. Change the integration name if you used-- a different one in step 1.DESC SECURITY INTEGRATION RAI_SECURITY_INTEGRATION;
/*Share the client ID, client secret (if applicable), and redirect URI withusers so they can configure their Direct Access connection locally.*/
/*## Step 6 - Enable Warm Reasoners (Optional)*/
/*Warm reasoners are pre-provisioned RAI reasoners that can reduce latencyfor workloads that require quick startup times.*/
/*We recommend enabling a warm `logic` reasoner for at least one reasonersize to get the best performance when using the RAI Native App. To enablea warm `logic` reasoner of size `HIGHMEM_X64_S`, run the following SQLcommand:*/
-- Note: Warm reasoners incur additional costs. If you want to enable warm reasoners,-- uncomment the line below and run it.-- CALL RELATIONALAI.APP.ENABLE_WARM_REASONER('logic', 'HIGHMEM_X64_S');
/*See the Warm Reasoners documentation for more information on warmreasoners and how to manage them.*/
/*## Congratulations! Your RelationalAI app is now ready to use.*/
/*# Next Steps*/
/*To get up and running with RelationalAI, download the Simple Starttemplate, extract the files,and follow the instructions in the `README`file and the `simple-start.ipynb` notebook.*/
/*For a more detailed example and more information about the RelationalAIPython library, check out the documentation.*/
/*Links:*/
/*- Simple Start Notebook:https://relational.ai/build/templates/simple-start - All templates:https://docs.relational.ai/build/templates - Docs:https://docs.relational.ai*/
/*## APPENDIX 1 - Deactivate the RAI Native App*/
/*To reduce costs when you are not using the RAI Native App, suspend CDC,and delete all reasoners.*/
/*> 🚨 Note that this task requires the `app_admin` application role.*/
/*## APPENDIX 2 - App Upgrades*/
/*Your RAI Native App is automatically upgraded every Monday at 10:00 UTC.During upgrades, the application cannot process RAI transactions.*/
/*If you prefer to schedule upgrades for a different day and time, use the`schedule_upgrade()` procedure:*/
BEGIN
CREATE OR REPLACE PROCEDURE rai_installation_step()RETURNS STRINGLANGUAGE PYTHONRUNTIME_VERSION = '3.10'PACKAGES = ('snowflake-snowpark-python')HANDLER = 'main'EXECUTE AS CALLERAS$$def main(session):
skip_appendix = True
if not skip_appendix: # Schedule upgrades for Wednesdays at 15:00 UTC. Times are in 24-hour format. session.sql("CALL relationalai.app.schedule_upgrade('WEDNESDAY', '15:00');").collect()
return "Step completed"$$;
CALL rai_installation_step();
DROP PROCEDURE rai_installation_step();
RETURN 'Step completed';END;SnowSQL, the Snowflake command-line client, does not correctly parse some of the Snowflake SQL constructs used in the SQL Worksheet. Therefore, if you prefer to use the command line client, you should instead copy the contents of the code block below and paste it into a file to run it.
/*Before running this worksheet, replace <db> and <schema> below with adatabase name and schema name from your account.This schema will be used by the worksheet to store temporary storedprocedures which are dropped immediately after they are called.Note also that some of the operations in the worksheet requireaccountadmin privileges*/
USE DATABASE <db>;USE SCHEMA <schema>;
/*# RelationalAI Native App Setup Guide*/
/*> 🚨 Note that the `ACCOUNTADMIN` role is used in this guide. This role isneeded for Step 1 and for creating the network rule in Step 4. To manageroles specific the RelationalAI Native App, see Appendix 2 at the bottomof this notebook.*/
USE ROLE ACCOUNTADMIN;
/*## Step 1 - Activate the RAI Native App*/
/*Execute the following three cells to create the RAI service (this usuallytakes between 5 and 15 minutes):*/
CREATE OR REPLACE PROCEDURE rai_installation_step()RETURNS STRINGLANGUAGE PYTHONRUNTIME_VERSION = '3.10'PACKAGES = ('snowflake-snowpark-python')HANDLER = 'main'EXECUTE AS CALLERAS$$def main(session):
import sys import time import json import itertools from snowflake.snowpark.context import get_active_session
def poll(f):
last_message = "" dots = itertools.cycle([".", ".", ".", ".", ".", "."])
def status(message): spaces = " " * (len(". " + last_message) - len(message)) sys.stdout.write("\r" + message + spaces) sys.stdout.flush()
for ctr in itertools.count(): if ctr % 10 == 0: result = f() if isinstance(result, str): message = next(dots) + " " + result status(message) last_message = result if result is True: status(". Done!") return else: message = next(dots) + " " + last_message status(message) time.sleep(0.5)
def activate(): try: session.sql("CALL RELATIONALAI.APP.ACTIVATE();").collect() return True except Exception as e: if "Unknown user-defined function" in str(e): return "Waiting for app installation to complete..." else: raise e
poll(activate)
return "Step completed"$$;
CALL rai_installation_step();
DROP PROCEDURE rai_installation_step();
CREATE OR REPLACE PROCEDURE rai_installation_step()RETURNS STRINGLANGUAGE PYTHONRUNTIME_VERSION = '3.10'PACKAGES = ('snowflake-snowpark-python')HANDLER = 'main'EXECUTE AS CALLERAS$$def main(session):
import sys import time import json import itertools from snowflake.snowpark.context import get_active_session
def poll(f):
last_message = "" dots = itertools.cycle([".", ".", ".", ".", ".", "."])
def status(message): spaces = " " * (len(". " + last_message) - len(message)) sys.stdout.write("\r" + message + spaces) sys.stdout.flush()
for ctr in itertools.count(): if ctr % 10 == 0: result = f() if isinstance(result, str): message = next(dots) + " " + result status(message) last_message = result if result is True: status(". Done!") return else: message = next(dots) + " " + last_message status(message) time.sleep(0.5)
def check(): result = session.sql("CALL RELATIONALAI.APP.SERVICE_STATUS();").collect() status = json.loads(result[0]["SERVICE_STATUS"])[0]["message"] if status is None: status = "" elif status.startswith("UNKNOWN"): status = "Working" elif status.startswith("Readiness probe"): status = "Almost done" elif status == "Running": return True else: return status + "..."
poll(check)
return "Step completed"$$;
CALL rai_installation_step();
DROP PROCEDURE rai_installation_step();
/*> 🚨 Note: Please review the documentation on upgrades for details aboutthe weekly automatic upgrade schedule.*/
/*## Step 2 - Setting up Change Data Capture*/
/*Streams share Snowflake data with the RAI Native App using change datacapture (CDC) to capture source table and view changes once every minute.*/
/*To enable CDC, run the following command:*/
CALL RELATIONALAI.APP.RESUME_CDC();
/*## Step 3 - Creating user roles*/
/*The RAI Native App comes with a set of Snowflake application roles formanaging access to the app. Application roles can't be granted to usersdirectly, and must be granted to Snowflake database roles instead.*/
/*The following SQL creates two database roles: `rai_admin` and`rai_developer`. The `rai_admin` role is for full admin access to the RAINative App, while the `rai_developer` role is for developers who needaccess to the RAI Python API:*/
-- Create a rai_admin role for full admin access to the RAI Native App.CREATE ROLE rai_admin;-- Link the app's `all_admin` role to the created role.GRANT APPLICATION ROLE relationalai.all_admin TO ROLE rai_admin;
-- Create a role for developers who need access to the RAI Python API.CREATE ROLE rai_developer;-- Link the app's `rai_user` role to the created role.GRANT APPLICATION ROLE relationalai.rai_user TO ROLE rai_developer;
/*Users granted the `rai_developer` role can:*/
/*- Use the RAI Native App. - Create, use, and delete RAI reasoners. -Create, manage, and delete data streams. - Enable and disable the CDCservice.*/
/*You can grant the `rai_developer` role to users in your Snowflake accountusing the `GRANT ROLE rai_developer TO USER "username";` command. Forexample, to grant the `rai_developer` role to yourself, run the followingcell:*/
CREATE OR REPLACE PROCEDURE rai_installation_step()RETURNS STRINGLANGUAGE PYTHONRUNTIME_VERSION = '3.10'PACKAGES = ('snowflake-snowpark-python')HANDLER = 'main'EXECUTE AS CALLERAS$$def main(session):
# optional: grant the rai_developer role to yourself current_user = session.sql("SELECT CURRENT_USER() AS USERNAME;").collect()[0]["USERNAME"]
session.sql(f'GRANT ROLE rai_developer TO USER "{current_user}"').collect()
return "Step completed"$$;
CALL rai_installation_step();
DROP PROCEDURE rai_installation_step();
/*Our Simple Start template uses a table called`RAI_DEMO.SIMPLE_START.CONNECTIONS`. If you want to be able to run thatnotebook, either grant permissions to the `rai_developer` role or run thefollowing SQL to create the table now. You can clean up this database whenyou're done with the demo notebook by running `DROP DATABASE RAI_DEMOCASCADE;`*/
CREATE DATABASE IF NOT EXISTS RAI_DEMO;CREATE SCHEMA IF NOT EXISTS RAI_DEMO.SIMPLE_START;
CREATE OR REPLACE TABLE RAI_DEMO.SIMPLE_START.CONNECTIONS ( STATION_1 INT, STATION_2 INT);
INSERT INTO RAI_DEMO.SIMPLE_START.CONNECTIONS (STATION_1, STATION_2) VALUES(1, 2),(1, 3),(3, 4),(1, 4),(4, 5),(5, 7),(6, 7),(6, 8),(7, 8);
GRANT USAGE ON DATABASE RAI_DEMO TO ROLE rai_developer;GRANT USAGE ON SCHEMA RAI_DEMO.SIMPLE_START TO ROLE rai_developer;GRANT SELECT ON TABLE RAI_DEMO.SIMPLE_START.CONNECTIONS TO ROLE rai_developer;ALTER TABLE RAI_DEMO.SIMPLE_START.CONNECTIONS SET CHANGE_TRACKING = TRUE;
-- optional: give rai_developer more extensive permissions in the RAI_DEMO database-- this step is necessary for the user to be able to run all the demo notebooksGRANT CREATE SCHEMA ON DATABASE RAI_DEMO TO ROLE rai_developer;GRANT CREATE TABLE ON SCHEMA RAI_DEMO.SIMPLE_START TO ROLE rai_developer;GRANT CREATE TABLE ON FUTURE SCHEMAS IN DATABASE RAI_DEMO TO ROLE rai_developer;GRANT SELECT ON ALL TABLES IN SCHEMA RAI_DEMO.SIMPLE_START TO ROLE rai_developer;GRANT SELECT ON FUTURE TABLES IN DATABASE RAI_DEMO TO ROLE rai_developer;
/*## Step 4 — Set Up Snowflake Notebooks*/
/*Snowflake has two notebook experiences: *Notebooks in Workspaces* and*Legacy Notebooks*. We recommend Notebooks in Workspaces for all new work.This step sets up Notebooks in Workspaces, and it also includes setup forLegacy Notebooks in case your account still needs them.*/
/*> 🚨 Note: Snowflake renamed the original notebook experience to *LegacyNotebooks*. > New accounts created after April 2026 can't create LegacyNotebooks, and Snowflake will turn off creation for all other accounts onSeptember 1, 2026. > Use Notebooks in Workspaces for new work.*/
/*First, give RelationalAI access to Snowflake stage storage. RelationalAImoves some data through *Snowflake stages*, which are Snowflake's built-instorage locations for files. The code below creates an External AccessIntegration — the network setup that lets RelationalAI reach those stages.Several RelationalAI features rely on this access, and a Legacy Notebookthat runs on a warehouse needs it to return query results. It reads thestage hosts Snowflake lists for your account with `SYSTEM$ALLOWLIST()`,then allows traffic only to those hosts and to no other internetdestination. Whether traffic to those hosts stays on a private networkdepends on your account's Snowflake network settings.*/
/*Run this code to create the integration:*/
CREATE OR REPLACE PROCEDURE rai_installation_step()RETURNS STRINGLANGUAGE PYTHONRUNTIME_VERSION = '3.10'PACKAGES = ('snowflake-snowpark-python')HANDLER = 'main'EXECUTE AS CALLERAS$$def main(session):
system_allowlist = session.sql(""" SELECT value:host AS URL FROM TABLE(FLATTEN(input=>parse_json(SYSTEM$ALLOWLIST()))) WHERE value:type = 'STAGE' """).collect()
if system_allowlist: urls = ", ".join(row.URL.replace('"', "'") for row in system_allowlist) egress_rule_commands = [ f""" CREATE OR REPLACE NETWORK RULE S3_RAI_INTERNAL_BUCKET_EGRESS MODE = EGRESS TYPE = HOST_PORT VALUE_LIST = ({urls}); """, """ CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION S3_RAI_INTERNAL_BUCKET_EGRESS_INTEGRATION ALLOWED_NETWORK_RULES = (S3_RAI_INTERNAL_BUCKET_EGRESS) ENABLED = true; """, """ GRANT USAGE ON INTEGRATION S3_RAI_INTERNAL_BUCKET_EGRESS_INTEGRATION TO ROLE rai_developer; """ ]
for command in egress_rule_commands: session.sql(command).collect()
print("Network rule set up successfully.")
return "Step completed"$$;
CALL rai_installation_step();
DROP PROCEDURE rai_installation_step();
/*### Notebooks in Workspaces*/
/*A Workspaces notebook uses two Snowflake compute resources:*/
/*- A *compute pool* runs the notebook's Python code. - A *query warehouse*runs the SQL queries and other Snowflake compute the notebook triggers.*/
/*Run the following SQL to create a warehouse and compute pool for yournotebooks, then give the `rai_developer` role access to both:*/
CREATE WAREHOUSE notebooks_wh;
CREATE COMPUTE POOL NOTEBOOK_CPU_XS MIN_NODES = 1 MAX_NODES = 15 INSTANCE_FAMILY = CPU_X64_XS AUTO_RESUME = true AUTO_SUSPEND_SECS = 1800 COMMENT = "Pool for Snowflake Notebooks in Workspaces";
GRANT USAGE ON WAREHOUSE notebooks_wh TO ROLE rai_developer;GRANT USAGE ON COMPUTE POOL NOTEBOOK_CPU_XS TO ROLE rai_developer;
/*Now anyone with the `rai_developer` role can create a notebook in**Projects > Workspaces**. When they open the notebook, they connect it toa *notebook service* — the container that runs the notebook's Python — andpoint that service at the `NOTEBOOK_CPU_XS` compute pool. They also selectthe `rai_developer` role and the `NOTEBOOKS_WH` warehouse in the role andwarehouse picker at the top left.*/
/*The setup worked if `NOTEBOOK_CPU_XS` and `NOTEBOOKS_WH` appear as optionsand the notebook connects.*/
/*Workspaces notebooks can install the `relationalai` package fromSnowflake's built-in package repository, which is available to all rolesby default. You only need extra network setup to install packages fromoutside Snowflake or to reach other external services.*/
/*### Legacy Notebooks*/
/*Legacy Notebooks are Snowflake's classic notebook experience, which youopen from **Projects > Notebooks**. Snowflake is retiring LegacyNotebooks, and these instructions will be removed after Snowflake disablesLegacy Notebook creation on September 1, 2026. Set one up only if youraccount already depends on it, and skip this subsection if you useNotebooks in Workspaces.*/
/*A Legacy Notebook runs on one of two runtimes:*/
/*- *Container Runtime* runs the notebook's Python on a compute pool, thesame way Notebooks in Workspaces do. - *Warehouse Runtime* runs thenotebook's Python on a warehouse.*/
/*Both runtimes store the notebook in a database and need permission tocreate notebooks, which the SQL below sets up. A Container Runtimenotebook runs its Python on the `NOTEBOOK_CPU_XS` compute pool and its SQLon the `NOTEBOOKS_WH` warehouse you created above. It also needspermission to create services and — to install packages from PyPI — itsown External Access Integration. A Warehouse Runtime notebook runs on the`NOTEBOOKS_WH` warehouse you created above and relies on the stageintegration you created at the start of this step to return query results.*/
/*If you use Legacy Notebooks, uncomment and run the SQL below:*/
-- Set up resources for Legacy Notebooks. Uncomment these statements only if you use Legacy Notebooks.
-- CREATE DATABASE IF NOT EXISTS rai_notebooks;-- GRANT USAGE ON DATABASE rai_notebooks TO ROLE rai_developer;-- GRANT USAGE ON SCHEMA rai_notebooks.public TO ROLE rai_developer;-- GRANT CREATE NOTEBOOK ON SCHEMA rai_notebooks.public TO ROLE rai_developer;-- GRANT CREATE SERVICE ON SCHEMA rai_notebooks.public TO ROLE rai_developer;
-- Allow Container Runtime notebooks to install packages from PyPI.-- CREATE OR REPLACE NETWORK RULE pypi_network_rule-- MODE = EGRESS-- TYPE = HOST_PORT-- VALUE_LIST = ('pypi.org', 'pypi.python.org', 'pythonhosted.org', 'files.pythonhosted.org');-- CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION pypi_access_integration-- ALLOWED_NETWORK_RULES = (pypi_network_rule)-- ENABLED = true;-- GRANT USAGE ON INTEGRATION pypi_access_integration TO ROLE rai_developer;
/*## Step 5 - Set Up Direct Access*/
/*By default, Python API calls are routed through Snowflake ServiceFunctions, which adds some extra overhead to every request. Direct Accessallows connections straight to the RAI Native App’s secure web address,skipping the middleman and reducing latency—often by about 500ms.*/
/*> 🚨 Note: Snowflake notebooks can't use Direct Access because of networkrestrictions in those environments. > This applies to both Notebooks inWorkspaces and Legacy Notebooks. > If you only plan to use RelationalAIfrom a Snowflake notebook, and not from a local Python environment, youcan skip this step.*/
/*Currently, Direct Access only supports three authentication methods:OAuth, Personal Access Token (PAT), and key-pair. We recommend creating anOAuth security integration for Direct Access now so that users canauthenticate interactively in their local development environments. PAT orkey-pair authentication can be set up later for applications andautomation.*/
/*To create an OAuth security integration, execute the following SQL:*/
-- Create a public OAuth client for Direct Access.CREATE SECURITY INTEGRATION RAI_SECURITY_INTEGRATION TYPE = OAUTH ENABLED = TRUE OAUTH_CLIENT = CUSTOM OAUTH_CLIENT_TYPE = 'PUBLIC' -- or 'CONFIDENTIAL' if needed OAUTH_ALLOW_NON_TLS_REDIRECT_URI = TRUE OAUTH_REDIRECT_URI = 'http://localhost:8001/snowflake/oauth-redirect' OAUTH_ISSUE_REFRESH_TOKENS = TRUE OAUTH_REFRESH_TOKEN_VALIDITY = 86400; -- Time in seconds
/*Note that the redirect URI can be any localhost URI, but the port must beopen on the user's machine. Now, run the following SQL to retrieve theclient ID:*/
-- Inspect the created integration. Change the integration name if you used-- a different one in step 1.DESC SECURITY INTEGRATION RAI_SECURITY_INTEGRATION;
/*Share the client ID, client secret (if applicable), and redirect URI withusers so they can configure their Direct Access connection locally.*/
/*## Step 6 - Enable Warm Reasoners (Optional)*/
/*Warm reasoners are pre-provisioned RAI reasoners that can reduce latencyfor workloads that require quick startup times.*/
/*We recommend enabling a warm `logic` reasoner for at least one reasonersize to get the best performance when using the RAI Native App. To enablea warm `logic` reasoner of size `HIGHMEM_X64_S`, run the following SQLcommand:*/
-- Note: Warm reasoners incur additional costs. If you want to enable warm reasoners,-- uncomment the line below and run it.-- CALL RELATIONALAI.APP.ENABLE_WARM_REASONER('logic', 'HIGHMEM_X64_S');
/*See the Warm Reasoners documentation for more information on warmreasoners and how to manage them.*/
/*## Congratulations! Your RelationalAI app is now ready to use.*/
/*# Next Steps*/
/*To get up and running with RelationalAI, download the Simple Starttemplate, extract the files,and follow the instructions in the `README`file and the `simple-start.ipynb` notebook.*/
/*For a more detailed example and more information about the RelationalAIPython library, check out the documentation.*/
/*Links:*/
/*- Simple Start Notebook:https://relational.ai/build/templates/simple-start - All templates:https://docs.relational.ai/build/templates - Docs:https://docs.relational.ai*/
/*## APPENDIX 1 - Deactivate the RAI Native App*/
/*To reduce costs when you are not using the RAI Native App, suspend CDC,and delete all reasoners.*/
/*> 🚨 Note that this task requires the `app_admin` application role.*/
/*## APPENDIX 2 - App Upgrades*/
/*Your RAI Native App is automatically upgraded every Monday at 10:00 UTC.During upgrades, the application cannot process RAI transactions.*/
/*If you prefer to schedule upgrades for a different day and time, use the`schedule_upgrade()` procedure:*/
CREATE OR REPLACE PROCEDURE rai_installation_step()RETURNS STRINGLANGUAGE PYTHONRUNTIME_VERSION = '3.10'PACKAGES = ('snowflake-snowpark-python')HANDLER = 'main'EXECUTE AS CALLERAS$$def main(session):
skip_appendix = True
if not skip_appendix: # Schedule upgrades for Wednesdays at 15:00 UTC. Times are in 24-hour format. session.sql("CALL relationalai.app.schedule_upgrade('WEDNESDAY', '15:00');").collect()
return "Step completed"$$;
CALL rai_installation_step();
DROP PROCEDURE rai_installation_step();Try the Simple Start Template (Optional)
Section titled “Try the Simple Start Template (Optional)”If you want a first post-install example, start with the Simple Start template.
Download the template files, follow the template README, and run the simple-start.ipynb notebook.
Install the RAI CLI (Optional)
Section titled “Install the RAI CLI (Optional)”Although you may manage the RAI Native App using SQL procedures, the RAI command-line interface (CLI) provides a more streamlined experience for common management tasks.
The RAI CLI is included in the relationalai Python package,
which supports Python 3.10, 3.11, 3.12, and 3.13.
Besides the CLI, the relationalai package serves as the main interface for
creating and managing models in RAI and accessing the advanced features of the RAI Native App.
To install the package, follow the installation instructions.