Skip to content

Native App Setup Guide

This guide walks through setting up and launching the RelationalAI Rel Agent. By the end, you’ll have a running engine and access to the Rel Agent UI in your browser.

  • Rel Agent preview access enabled for your account.
  • The RAI Native App installed in your Snowflake account.
  • A Snowflake account with ACCOUNTADMIN privileges (or equivalent).
  • A warehouse for the Rel Agent service to use.

The script below walks you through the following steps:

  1. Set configuration variables. Define the engine name, secrets location, service user, role, warehouse, and Native App name — all in one place so the rest of the script can reference them automatically.

  2. Enable Cortex. Ensure cross-region Cortex is active on your account so the Rel Agent can call Snowflake’s LLM service.

  3. Create secrets. Store your Snowflake credentials and LLM token as Snowflake secrets, then grant the Native App read access to them.

  4. Configure network access. Create a network rule that allows outbound traffic from the Rel Agent service, wire it into an External Access Integration, and grant the Native App access to both.

  5. Verify role access and launch the engine. Confirm that your service role exists, is granted to the service user, has warehouse access, and holds a RAI application role — then start the Rel Agent engine.

  6. Access the Rel Agent UI. Retrieve the engine’s ingress URL and open it in your browser.

To run the script, you can use a Snowflake notebook, a SQL worksheet, or the SnowSQL command-line client.

  1. Download the Rel Agent setup notebook.
    View a preview of the setup notebook.

    Rel Agent Setup

    Step 1 — Set configuration variables

    Replace the placeholder values below with your own, then run this block.

    -- ============================================================
    -- Configuration — update these values for your environment
    -- ============================================================
    -- Engine
    SET engine_name = 'my_rel_agent'; -- name you choose for this engine
    SET engine_size = 'S'; -- compute size (S, M, L, etc.)
    -- Secrets location (FQNs are derived automatically)
    SET secret_db = 'modeler_setup'; -- database for secrets and network rule
    SET secret_schema = $secret_db || '.config'; -- schema for secrets and network rule
    SET cred_secret = $secret_schema || '.SNOWFLAKE_CREDENTIALS';
    SET llm_secret = $secret_schema || '.LLM_KEY';
    SET network_rule = $secret_schema || '.modeler_network_rule';
    -- Credentials
    SET service_user = '<your_service_user>'; -- Snowflake user for the Rel Agent
    -- Access
    SET eai_name = 'modeler_eai'; -- External Access Integration name
    SET service_role = '<role_with_warehouse_access>';
    SET warehouse = '<warehouse_name>';
    SET native_app = 'RELATIONALAI'; -- name of the installed Native App

    Step 2 — Enable Cortex

    Cortex must be enabled on your Snowflake account before the Rel Agent can use it for LLM access. LOOK FOR: CORTEX_ENABLED_CROSS_REGION should be set to ‘ANY_REGION’.

    SHOW PARAMETERS LIKE 'CORTEX_ENABLED_CROSS_REGION' IN ACCOUNT;
    -- Enable cross-region Cortex if not already set
    ALTER ACCOUNT SET CORTEX_ENABLED_CROSS_REGION = 'ANY_REGION';

    Step 3 — Create secrets

    The Rel Agent requires two secrets: one for Snowflake authentication and one for LLM access via Cortex. Replace <your_password_or_pat> and <your_llm_token> with real values before running. LOOK FOR: Both SNOWFLAKE_CREDENTIALS (type PASSWORD) and LLM_KEY (type GENERIC_STRING) should appear.

    -- Create a database and schema for your secrets (or use existing ones)
    CREATE DATABASE IF NOT EXISTS IDENTIFIER($secret_db);
    CREATE SCHEMA IF NOT EXISTS IDENTIFIER($secret_schema);
    -- Create the credentials secret (must be TYPE = PASSWORD)
    CREATE SECRET IF NOT EXISTS IDENTIFIER($cred_secret)
    TYPE = PASSWORD
    USERNAME = $service_user
    PASSWORD = '<your_password_or_pat>';
    -- Create the LLM key secret for Cortex access
    CREATE SECRET IF NOT EXISTS IDENTIFIER($llm_secret)
    TYPE = GENERIC_STRING
    SECRET_STRING = '<your_llm_token>';
    SHOW SECRETS IN SCHEMA IDENTIFIER($secret_schema);
    -- Grant the Native App access to the secrets
    GRANT USAGE ON DATABASE IDENTIFIER($secret_db) TO APPLICATION IDENTIFIER($native_app);
    GRANT USAGE ON SCHEMA IDENTIFIER($secret_schema) TO APPLICATION IDENTIFIER($native_app);
    GRANT READ ON SECRET IDENTIFIER($cred_secret) TO APPLICATION IDENTIFIER($native_app);
    GRANT READ ON SECRET IDENTIFIER($llm_secret) TO APPLICATION IDENTIFIER($native_app);
    -- LOOK FOR: USAGE on the database and schema, READ on both secrets, all granted to the native app.
    SHOW GRANTS ON DATABASE IDENTIFIER($secret_db);
    SHOW GRANTS ON SCHEMA IDENTIFIER($secret_schema);
    SHOW GRANTS ON SECRET IDENTIFIER($cred_secret);
    SHOW GRANTS ON SECRET IDENTIFIER($llm_secret);

    Step 4 — Configure network access

    The Rel Agent needs outbound network access to communicate with Snowflake’s auth gateway. The 0.0.0.0 rule allows general egress. You can tighten this to your account’s specific Snowflake endpoint(s) to limit access.

    Note: ALLOWED_NETWORK_RULES must be a literal name — session variables cannot be used here. If you changed $network_rule above, update the value in the CREATE EXTERNAL ACCESS INTEGRATION statement below to match.

    LOOK FOR: The network rule with MODE = EGRESS, the EAI with ENABLED = true, and USAGE privilege on both granted to the native app.

    CREATE OR REPLACE NETWORK RULE IDENTIFIER($network_rule)
    TYPE = HOST_PORT
    MODE = EGRESS
    VALUE_LIST = ('0.0.0.0')
    COMMENT = 'Allow outbound traffic for Rel Agent service to Snowflake endpoints';
    -- Note: ALLOWED_NETWORK_RULES must be a literal — update if you changed $network_rule.
    CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION IDENTIFIER($eai_name)
    ALLOWED_NETWORK_RULES = (modeler_setup.config.modeler_network_rule)
    ENABLED = TRUE;
    -- Grant the Native App access
    GRANT USAGE ON NETWORK RULE IDENTIFIER($network_rule) TO APPLICATION IDENTIFIER($native_app);
    GRANT USAGE ON INTEGRATION IDENTIFIER($eai_name) TO APPLICATION IDENTIFIER($native_app);
    SHOW NETWORK RULES IN SCHEMA IDENTIFIER($secret_schema);
    SHOW EXTERNAL ACCESS INTEGRATIONS;
    SHOW GRANTS ON NETWORK RULE IDENTIFIER($network_rule);
    SHOW GRANTS ON INTEGRATION IDENTIFIER($eai_name);

    If your service user is blocked by existing network policies, run the block below to create and assign one. Otherwise, skip to Step 5.

    CREATE NETWORK POLICY modeler_service_policy
    ALLOWED_IP_LIST = ('0.0.0.0/0');
    ALTER USER IDENTIFIER($service_user) SET NETWORK_POLICY = modeler_service_policy;

    Step 5 — Verify role access and launch the engine

    Before launching, confirm that $service_role exists, is granted to your service user, has warehouse access, and has a RAI application role. This is the most common source of setup failures. LOOK FOR: $service_role should appear in each result set. If the role is missing from any check, run the corresponding GRANT shown in the comments.

    -- Does the role exist?
    SHOW ROLES;
    SELECT "name" FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
    WHERE "name" = UPPER($service_role);
    -- Is it granted to the service user?
    SHOW GRANTS TO USER IDENTIFIER($service_user);
    SELECT "role" FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
    WHERE "role" = UPPER($service_role);
    -- If not: GRANT ROLE IDENTIFIER($service_role) TO USER IDENTIFIER($service_user);
    -- Does the role have USAGE on the warehouse?
    SHOW GRANTS TO ROLE IDENTIFIER($service_role);
    SELECT "privilege", "name" FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
    WHERE "privilege" = 'USAGE' AND "name" = UPPER($warehouse);
    -- If not: GRANT USAGE ON WAREHOUSE IDENTIFIER($warehouse) TO ROLE IDENTIFIER($service_role);
    -- Does the role have a RAI application role (e.g. RAI_USER or RAI_DEVELOPER)?
    SHOW GRANTS TO ROLE IDENTIFIER($service_role);
    SELECT "privilege", "granted_on", "grantee_name" FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
    WHERE "privilege" = 'USAGE' AND "granted_on" = 'APPLICATION_ROLE' and "grantee_name" = UPPER(($service_role));
    -- If not: GRANT APPLICATION ROLE RELATIONALAI.<rai_role> TO ROLE IDENTIFIER($service_role);

    Once the checks above pass, create the engine. LOOK FOR: STATUS = RUNNING. If GONE or FAILED, see the Troubleshooting section of the setup guide.

    CALL RELATIONALAI.api.create_reasoner_async(
    'modeler',
    $engine_name,
    $engine_size,
    PARSE_JSON(
    '{"settings":{"modeler":{' ||
    '"snowflake_credentials_secret":"' || $cred_secret || '",' ||
    '"llm_key_secret":"' || $llm_secret || '",' ||
    '"snowflake_role":"' || $service_role || '",' ||
    '"warehouse_name":"' || $warehouse || '",' ||
    '"external_access_integrations":["' || $eai_name || '"]' ||
    '}}}'
    )
    );
    -- LOOK FOR: STATUS = RUNNING. If GONE or FAILED, see "Getting service logs" in the Troubleshooting section.
    CALL RELATIONALAI.api.get_reasoner('modeler', $engine_name);

    Step 6 — Access the Rel Agent UI

    Once the engine is running, retrieve its ingress endpoint URL and open it in your browser. The SPCS ingress authenticates you automatically via your Snowflake account credentials.

    CALL RELATIONALAI.api.modeler_endpoints($engine_name);
  2. Go to https://app.snowflake.com and select + Create Projects > Notebook > Import .ipynb File at the top of the left sidebar.
  3. Upload the relationalai-rel-agent-setup.ipynb file.
  4. Choose a database and schema to save the notebook in.
    • Any database and schema will do — you can delete the notebook after setup.
    • If you don’t have any database available in the dropdown, you can create one by doing create database <name>; from a SQL worksheet.
  5. Choose Run on warehouse and click Create.
  6. Run the cells one at a time.

The engine starts with the following configuration:

SettingDefault
LLM ProviderCortex (Snowflake internal)
Modelclaude-sonnet-4-5 (Claude 4.5 Sonnet)
AuthenticationOAuth via Snowflake credentials
Max tokens64,000
Temperature0.1
Request timeout45 seconds
Max concurrent requests5
Max retries3
”Modeler not enabled for your account”

The Rel Agent preview must be explicitly enabled for your Snowflake account. Contact your RelationalAI representative to request access. After it has been enabled, it can take 10–20 minutes to propagate to your account.

”Credentials not provided”

Your settings JSON is missing one or more required fields. Ensure all are present:

  • snowflake_credentials_secret
  • llm_key_secret
  • snowflake_role
  • warehouse_name
”Secret not found”
  • Verify the secret exists: SHOW SECRETS IN SCHEMA IDENTIFIER($secret_schema);
  • Ensure the name is fully qualified: database.schema.secret_name
”Invalid secret type”

The credentials secret must be TYPE = PASSWORD. Other types are not supported.

”Invalid secret name”

Secret names must:

  • Start with a letter.
  • Contain only letters, numbers, underscores, and periods.
  • Be 255 characters or fewer.
  • Be fully qualified (e.g., database.schema.secret_name).
”Role does not exist” or “Role not granted”

This is one of the most common setup issues. The snowflake_role specified in your engine settings must:

  • Actually exist in your Snowflake account.
  • Be granted to the service user specified in your credentials secret.
  • Have the necessary permissions (warehouse usage, database/schema access, RAI application role).

To diagnose:

-- Does the role exist?
SHOW ROLES;
SELECT "name" FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
WHERE "name" = UPPER($service_role);
-- Is it granted to your service user?
SHOW GRANTS TO USER IDENTIFIER($service_user);
-- What permissions does it have?
SHOW GRANTS TO ROLE IDENTIFIER($service_role);
-- Grant the role to the service user if missing
GRANT ROLE IDENTIFIER($service_role) TO USER IDENTIFIER($service_user);
-- Grant a RAI application role if missing
GRANT APPLICATION ROLE RELATIONALAI.<rai_role> TO ROLE IDENTIFIER($service_role);
“Insufficient privileges” or “Not authorized”
  • Confirm the app has READ on the secret and USAGE on the database and schema.
  • Check grants: SHOW GRANTS ON SECRET IDENTIFIER($cred_secret);
  • Verify the snowflake_role you specified has the right permissions.
  • Ensure the role has a RAI application role (e.g., RAI_USER, RAI_DEVELOPER) granted to it.
”External access not configured” or “Network error”
  • Confirm the EAI exists and is ENABLED = TRUE.
  • Confirm the integration is granted to the application.
  • Verify the integration name in your create_reasoner_async call matches exactly.
”Warehouse not found” or “Warehouse access denied”
  • Verify the warehouse exists: SHOW WAREHOUSES; and check that $warehouse appears.
  • Ensure the snowflake_role has USAGE on the warehouse:
    GRANT USAGE ON WAREHOUSE IDENTIFIER($warehouse) TO ROLE IDENTIFIER($service_role);
Models silently fail to build

If models appear to accept input but never finish building (no error, just stuck), the most likely cause is a missing, invalid, or unauthorized LLM token. Verify that:

  • llm_key_secret points to a valid secret.
  • The token is not expired or revoked.
  • The service user has been granted access to use Cortex.
Getting service logs

SPCS service logs are useful for diagnosing startup failures, unexpected behavior, or errors on a running engine.

  1. List all services:

    SHOW SERVICES IN ACCOUNT;
  2. Get the fully qualified service name, including its hash suffix:

    SELECT "database_name" || '.' || "schema_name" || '.' || "name" AS service_fqn
    FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
    WHERE "name" ILIKE '%' || $engine_name || '%';
  3. Fetch the logs using the fully qualified name:

    SELECT * FROM TABLE(<service_fqn>!SPCS_GET_LOGS());

The result is a table with columns TIMESTAMP, INSTANCE_ID, CONTAINER_NAME, LOG, and RECORD_ATTRIBUTES. A typical snippet looks like:

TIMESTAMPINSTANCE_IDCONTAINER_NAMELOGRECORD_ATTRIBUTES
2026-03-25 14:15:55.9030modelerserviceINFO: 10.16.186.15:48214 - "GET /ping HTTP/1.1" 200 OK{"log.iostream": "stdout", "snow.application.shared": true}
2026-03-25 14:15:55.9020modelerservice1ms ▸ HTTP::GET /ping{"log.iostream": "stdout", "snow.application.shared": true}
2026-03-25 14:15:55.9010modelerservice▸ HTTP::GET /ping 09d4352f-e7d5-45f4-bac5-6b68f6e766aa{"log.iostream": "stdout", "snow.application.shared": true}

The LOG column contains the message. Look for lines containing ERROR or WARN — these usually indicate the root cause. Logs are in reverse chronological order, so start from the top for the most recent entries.