--- name: internal-marketplace-org-listing description: > Create organizational listings to share data products via Internal Marketplace. Triggers: create data product, share to internal marketplace, publish to internal marketplace, share to other accounts, share with other accounts, organization listing, org listing, share across accounts, internal marketplace, cross-account sharing, share my agent to other accounts. WHEN TO USE THIS SKILL: - User wants to share with OTHER ACCOUNTS → Use this skill - User mentions "internal marketplace" or "data product" (even for same account) → Use this skill WHEN TO USE RBAC INSTEAD (not this skill): - User wants to share with roles in SAME account only - User does NOT mention "internal marketplace" or "data product" or "listing" - Example: "share this table with ANALYST role" → Use GRANT, not this skill WHEN NOT TO USE THIS SKILL: - User wants to migrate an EXISTING direct share to an org listing → Use the direct-share-to-org-listing-migration skill instead - User wants to migrate an EXISTING personalized listing to an org listing → Use the personalized-listing-to-org-listing-migration skill instead - User wants to migrate an EXISTING private data exchange (PDX) listing to an org listing → Use the pdx-listing-to-org-listing-migration skill instead KEY: If user says "share via internal marketplace" or "as a data product" even for same-account roles, use this skill. Otherwise, same-account = regular RBAC grants. --- # Organizational Listing Provider Skill Create and publish organizational listings to share data products across accounts within your Snowflake organization via Internal Marketplace. ## When to Use **USE THIS SKILL when:** - Sharing objects with **OTHER ACCOUNTS** in the organization - User mentions **"internal marketplace"** or **"data product"** (even for same account) - Creating internal marketplace listings as a data provider - Publishing data products to internal consumers - Cross-region auto-fulfillment setup **USE RBAC (not this skill) when:** - User wants to share with roles in the **SAME account only** - User does NOT mention "internal marketplace" or "data product" - Example: "grant access to ANALYST role" → Use `GRANT` command, not this skill **DO NOT USE THIS SKILL when:** - User wants to migrate an **existing direct share** to an org listing → Use the `direct-share-to-org-listing-migration` skill instead - User wants to migrate an **existing personalized listing** to an org listing → Use the `personalized-listing-to-org-listing-migration` skill instead - User wants to migrate an **existing private data exchange (PDX) listing** to an org listing → Use the `pdx-listing-to-org-listing-migration` skill instead **Common triggers**: "share to internal marketplace", "create a data product", "share with other accounts", "publish to internal marketplace" **Documentation**: [Organization Listing Docs](https://docs.snowflake.com/en/user-guide/collaboration/listings/organizational/org-listing-create) ## Quick Flow (Minimal Input) When user says something like **"share my agent to internal marketplace"** or **"share this object internally"**: 1. **Identify the object(s)** the user wants to share 2. **Ask for required info**: ``` To create the listing, I need: 1. Who should have access? (all accounts / specific accounts / access must be requested) 2. What email should I use for support and approver contacts? ``` 3. **Check for required custom attributes** — run `SHOW AVAILABLE INTERNAL MARKETPLACE CONFIGS` and filter for `props = custom_attribute_type`. If any have `is_required: true`, collect their values using `ask_user_question` before proceeding. 4. **Auto-generate** listing with minimal fields: - Title: create a meaningful title that describes the data product and all objects included - Description: auto-generated a helpful description on what this data product can do, what objects it includes, and what use cases it can help address - Discovery/Access: based on user's input - Contacts: use the email provided by the user for both support and approver if only one email is provided, otherwise use the email to the specific contact field specified by the user. - Request approval flow: Include `request_approval_type: "REQUEST_AND_APPROVE_IN_SNOWFLAKE"` automatically when access must be requested (access field omitted), or when user explicitly specifies how approvals should be handled - Data Dictionary: Add data dictionary for all tables and views added in the data product 5. **Skip data dictionary** for non-table objects (agents, semantic views, functions) 6. **Create and publish** immediately after confirmation **⚠️ Note**: Data dictionary and usage examples are **only applicable for tables/views**. Skip these for agents, semantic views, functions, and other non-queryable objects. **⚠️ Cortex Agent Sharing Limitations**: Cortex Agents CANNOT be shared if they: - Use a custom warehouse in agent spec or tools - Have tools in different databases - Have custom `query_timeout` settings - Have an invalid agent spec If agent sharing fails, suggest sharing the underlying tables instead. ## Prerequisites 1. **Organization Setup**: - Account must be part of a Snowflake organization with `ORGADMIN` role - Know your organization's account names (`SHOW ORGANIZATION ACCOUNTS`) 2. **Required Privileges**: - `CREATE SHARE` on ACCOUNT - `CREATE ORGANIZATION LISTING` on ACCOUNT - `USAGE WITH GRANT OPTION` on database/schema to share - `MANAGE LISTING AUTO FULFILLMENT` on ACCOUNT (if cross-region) **Verify with:** ```sql SELECT CURRENT_ROLE(); SHOW GRANTS TO ROLE ; ``` ## Workflow ``` Start → Step 1: Gather → Step 2: Create Share → Step 3: Create Listing → Step 4: Verify → Done ↑ ↑ ⚠️ STOP ⚠️ STOP ``` ### Step 1: Gather Requirements **Goal:** Collect all information needed to create the share and listing. **Actions:** 1. **Ask** the user: ``` To create your organizational listing, please provide: 1. **Objects to share**: Which database/schema/tables/views/semantic views? (Please list the EXACT objects - only these will be added to the share) 2. **Access**: Who should have access? - All internal accounts (or user already said "share with all accounts") - Specific accounts only (please list them) 3. **Contact email**: What email should be used for support and approver contacts? 4. **Organization profile** Which organization profile should be used for this listing? - The system-generated default INTERNAL profile - An available custom profile in your organization (please specify the name) ``` 2. **Auto-generate** (do not ask user for these): - **Title**: Create a meaningful title that describes the data product and all objects included - **Description**: Generate a helpful description explaining what this data product offers, what objects it includes, and what use cases it can address - **Data Dictionary**: Add data dictionary for all tables and views in the data product - **Support & Approver contacts**: - If the user provides TWO distinct emails with labels (e.g., "Support Contact: email1" and "Approver Contact: email2"), map each email to its corresponding field (support_contact = email1, approver_contact = email2) - If the user provides only ONE email, use it for BOTH support_contact and approver_contact fields **⚠️ CRITICAL**: Only share objects the user explicitly lists. Never add: - INFORMATION_SCHEMA - System schemas or tables - Objects not explicitly requested by the user 3. **If user asks to share "all objects in a schema"**, discover them: ```sql -- Get all tables SHOW TABLES IN SCHEMA .; -- Get all views SHOW VIEWS IN SCHEMA .; -- Get all semantic views (NOT included in SHOW VIEWS) SHOW SEMANTIC VIEWS IN SCHEMA .; ``` Compile the list from all three commands, then confirm with user before proceeding. 4. **If user mentions sharing to accounts or targeting accounts, or if user mentions targeting/sharing to regions** **Step A**: Verify whether a specified account is a valid account in the organization: Fetch all the accounts in the organization by running: ```sql SHOW ACCOUNTS; -- record query id ``` **⚠️ CRITICAL**: DO NOT run `SHOW ORGANIZATION ACCOUNTS` to fetch the accounts. **⚠️ CRITICAL**: `SHOW ACCOUNTS` output may be truncated in large organizations. If the result indicates truncation (e.g., "N row(s) shown but more may have been returned"), always use `RESULT_SCAN` with a WHERE filter to search for specific accounts in the response of `SHOW ACCOUNTS` rather than scanning the raw output visually: ```sql -- use the returned `account_name` and `snowflake_region` for the following steps. SELECT "account_name", "account_locator", "snowflake_region" FROM TABLE(RESULT_SCAN()) WHERE UPPER("account_name") = '' OR UPPER("account_locator") = ''; ``` If the user specified the account name in the format of ".", use the account alias as the account name for account name verification and following steps if the organization name is the same as the current account. ALWAYS use `account_name` instead of `account_locator` in the following steps even when the user specified the account locator. **Step B**: Use the exact account name in `organization_targets`: **⚠️ CRITICAL - Account Name Format:** - Use ONLY the `account_name` from `SHOW ACCOUNTS` - **NEVER** append region names - **NEVER** use account locators ```yaml organization_targets: discovery: - account: "HR" # Use exact account_name from SHOW ACCOUNTS access: - account: "HR" ``` **⚠️ OPTIMIZATION - For "current account" or "same account":** When instruction mentions "**current account**", "**same account**", or "roles in this account", you can use `CURRENT_ACCOUNT_NAME()` directly without needing to query `SHOW ACCOUNTS`: ```sql SELECT CURRENT_ACCOUNT_NAME() as account_name; ``` Use the returned value directly in `organization_targets`: ```yaml organization_targets: access: - account: "PM_AWS_US_WEST_2" # From CURRENT_ACCOUNT_NAME() roles: ['ACCOUNTADMIN', 'SYSADMIN'] ``` 5. **Verify the specified organization profile**: Find all the organization profiles available in this organization: ```sql SHOW AVAILABLE ORGANIZATION PROFILES; -- Convert the user-specified organization profile name to all uppercase if needed and look for the exact organization profile name from the 'name' column. ``` **⚠️ CRITICAL**: An organization profile is only available for publishing listings when the exact name matches with the uppercase format of the user-specified name, and the 'can_publish_listings_with_profile' column for this organization profile is true. If the specified organization profile is not found, list the names of the available organization profiles with the 'can_publish_listings_with_profile' column as true and ask the user to choose from one of these options. 6. **Check for required custom attributes**: Run: ```sql SHOW AVAILABLE INTERNAL MARKETPLACE CONFIGS; ``` - Filter to only rows where `props` = `custom_attribute_type` — ignore rows with other types (e.g., `notification_integration_name`) - If no filtered rows have `is_required: true` → **skip silently**, do not mention custom attributes to the user - If any rows have `is_required: true` → use the `ask_user_question` tool to collect values. Present each required attribute as its own individual question (up to 4 per call): - **Single/multi-select attributes** (predefined options exist): use `options` with each option's `display_name` as the label. Use `multiSelect: true` if the attribute allows multiple values. - **Free-text attributes** (no predefined options): use a text input with a sensible `defaultValue` if one can be inferred - If there are more than 4 required attributes, batch them in groups of up to 4 per `ask_user_question` call - **List ALL valid options** from the result for constrained attributes — do not summarize or truncate - When writing values to the manifest, use the `display_name` field (not `value`) for each selected option - **Do not ask about optional attributes** (`is_required: false`) unless the user explicitly requests them - **⚠️ MANDATORY STOPPING POINT**: Do NOT proceed to generate the manifest until all required custom attribute values have been successfully collected from the user 7. **Get current region** (needed for locations): ```sql SELECT CURRENT_REGION(); ``` **⚠️ MANDATORY STOPPING POINT**: Do NOT proceed until user provides all required information. --- ### Step 2: Create the Share **Goal:** Create the underlying share with correct privilege grants. ``` ╔══════════════════════════════════════════════════════════════════════════════╗ ║ ⚠️ CRITICAL: GRANT ORDER MATTERS - FOLLOW EXACTLY OR SHARE WILL FAIL ║ ║ ║ ║ 1. FIRST: GRANT USAGE ON DATABASE ← Must be first! ║ ║ 2. SECOND: GRANT USAGE ON SCHEMA ║ ║ 3. LAST: GRANT SELECT ON TABLE/VIEW/SEMANTIC VIEW ║ ║ ║ ║ Error "Share does not currently have a database" = Wrong order! ║ ╚══════════════════════════════════════════════════════════════════════════════╝ ``` **⚠️ CRITICAL**: Only add objects the user explicitly specifies to the share. - Do NOT add INFORMATION_SCHEMA - Do NOT add system schemas - Do NOT add objects the user didn't request - Ask user to confirm the exact list of objects before creating the share **Actions:** 1. **Create share**: ```sql CREATE SHARE IF NOT EXISTS COMMENT = ''; ``` 2. **Grant privileges** (in order!): ```sql -- FIRST: Database GRANT USAGE ON DATABASE TO SHARE ; -- SECOND: Schema GRANT USAGE ON SCHEMA . TO SHARE ; -- LAST: Tables/Views/Semantic Views -- For tables: GRANT SELECT ON TABLE .. TO SHARE ; -- Or for all tables: GRANT SELECT ON ALL TABLES IN SCHEMA . TO SHARE ; -- ⚠️ VIEWS: Must grant individually (bulk grant on views is restricted) GRANT SELECT ON VIEW .. TO SHARE ; -- NOTE: "GRANT SELECT ON ALL VIEWS" is NOT supported for shares -- ⚠️ SEMANTIC VIEWS: Use SELECT (not USAGE) GRANT SELECT ON SEMANTIC VIEW .. TO SHARE ; ``` **⚠️ Finding Semantic Views**: Use `SHOW SEMANTIC VIEWS` (not `SHOW VIEWS`): ```sql SHOW SEMANTIC VIEWS IN SCHEMA .; ``` **If error "Non-secure object can only be granted to shares with "secure_objects_only" property set to false." happens when granting any of the tables, views, or functions to the share** → List all the options and ask the user to confirm how they want to proceed with the share creation: - Option 1: Alter the share to allow sharing non-secure objects. Show a bold warning with this option that a share cannot set secure_objects_only to true once it's set to false, execute ```sql ALTER SHARE SET SECURE_OBJECTS_ONLY = FALSE; ``` - Option 2: Convert this object to a secure object. Show a bold warning with this option that users should weigh the trade-off between data privacy/security and query performance before proceeding. If the user chooses option 2, execute: ```sql ALTER VIEW .. SET SECURE; ``` - Option 3: Skip granting this non-secure object to the share. 3. **Verify share contents**: ```sql DESCRIBE SHARE ; ``` **Output:** Share created with all requested objects granted. **If error "Share does not currently have a database"** → Check grant order (database must be first). **⚠️ Metadata Visibility Note**: Granting `USAGE ON DATABASE` makes all schema names visible to consumers in metadata, even if they can't query objects in those schemas. --- ### Step 3: Create the Listing **Goal:** Create organizational listing with YAML manifest including data dictionary. **Actions:** 0. **Organization Targets - Discovery & Access**: **⚠️ CRITICAL - How to handle discovery and access targets:** - If instruction says "**Do not** allow anyone to discover" or "**No discovery**" → **OMIT the `discovery` field entirely** from `organization_targets`: ```yaml organization_targets: access: - account: "ACCOUNT_NAME" # NO discovery field when discovery is disabled ``` - If instruction says "**access must be requested**" or "**no automatic access**" or "**accessible to no one**" or "**discovery-only**" → **OMIT the `access` field entirely** from `organization_targets`. **Discovery targets must still be specified** based on the user's instruction. Also include `request_approval_type: "REQUEST_AND_APPROVE_IN_SNOWFLAKE"` so consumers have a mechanism to request access: ```yaml organization_targets: discovery: - all_internal_accounts: true # or specific accounts — based on user instruction # NO access field when access must be requested request_approval_type: "REQUEST_AND_APPROVE_IN_SNOWFLAKE" # top-level field, not nested ``` - If instruction says "**all accounts** in the organization" for discovery or access → use `all_internal_accounts: true`: ```yaml organization_targets: discovery: - all_internal_accounts: true access: - all_internal_accounts: true ``` - If instruction specifies specific accounts for discovery or access → list them: ```yaml organization_targets: discovery: - account: "ACCOUNT_1" access: - account: "ACCOUNT_1" ``` **⚠️ CRITICAL - Role-based access:** - If instruction mentions roles (e.g., "ACCOUNTADMIN role in PM_SHARING" or "ACCOUNTADMIN and SYSADMIN roles") → include `roles` field in the following format: ```yaml organization_targets: access: - account: "PM_SHARING" roles: ['ACCOUNTADMIN', 'SYSADMIN'] ``` 1. **Access Regions**: **⚠️ The listing owner can specify any access regions they want. This is independent of auto-fulfillment.** **How to choose access regions:** - **If instruction explicitly says "all regions" or "target all regions":** - Use the literal value `ALL`: - **If instruction specifies specific regions:** - Use those specific regions (e.g., `PUBLIC.AWS_US_WEST_2`, `PUBLIC.AWS_US_EAST_1`) - **If instruction doesn't specify regions:** - Default to the current account's region (e.g., `PUBLIC.AWS_US_WEST_2`) **Note:** Access region choice does NOT determine auto-fulfillment. See section 5 below for auto-fulfillment logic. When using specific access regions: - If user requests targeting specific regions, or mentions targeting only the target accounts' regions or locations, or mentions targeting the minimal set of regions possible, add the access region names to the manifest. Each access region name should be in the format of ".", e.g., "PUBLIC.AWS_US_WEST_2". If the user specified a set of regions, use the specified region list; otherwise add the regions of all targeted accounts without duplication. If the region group is not specified for any snowflake regions, run: ```sql SHOW REGIONS IN DATA EXCHANGE SNOWFLAKE_DATA_MARKETPLACE; ``` and use the values in the `region_group` field in the response for the corresponding `snowflake_regions` of the accounts. If any of the target accounts are outside the access regions, list the following options and ask user for supplemental information: - Skip this target account that is not in any of the specified access regions. - Add the access region "." to the access regions Add the access regions to the manifest in the following format: ```yaml locations: access_regions: - name: "" - name: "" ``` 2. **Auto-select tables for data dictionary** (up to 5): **⚠️ SKIP this step if sharing non-table objects** (agents, semantic views, functions). Data dictionary is only supported for tables and views. - Query the share to identify objects: ```sql DESCRIBE SHARE ; ``` - **Prioritize** (select up to 5 most relevant): - Main fact tables (transactions, events, orders) - Key dimension tables (customers, products) - Commonly queried views - Aggregated/summary tables - **Exclude**: staging tables, internal/system tables, rarely used lookups - **Auto-detect PII fields** in selected objects (tables only): ```sql -- Check column names for PII patterns DESCRIBE TABLE ..
; -- If available, check Snowflake classification tags SELECT * FROM TABLE( INFORMATION_SCHEMA.TAG_REFERENCES('..
', 'TABLE') ); ``` - **Common PII patterns to detect**: - Names: `first_name`, `last_name`, `full_name`, `customer_name` - Contact: `email`, `phone`, `mobile`, `address`, `zip`, `postal` - IDs: `ssn`, `social_security`, `tax_id`, `passport`, `driver_license` - Financial: `credit_card`, `account_number`, `bank_account` - Health: `dob`, `date_of_birth`, `medical_id`, `patient_id` - **Note PII fields in description** for consumer awareness 3. **Auto-generate SQL usage examples** (tables/views only): **⚠️ SKIP if no tables/views in the data product** (e.g., only agents or functions). ``` ╔══════════════════════════════════════════════════════════════════════════╗ ║ ⚠️ MANDATORY: Run DESCRIBE TABLE for EACH table BEFORE writing queries ║ ║ ║ ║ NEVER assume column names! Get the ACTUAL column names first. ║ ╚══════════════════════════════════════════════════════════════════════════╝ ``` **Step 0: Get ACTUAL column names (MANDATORY)** ```sql -- Run this for EACH table before writing any usage examples DESCRIBE TABLE ..
; ``` Use ONLY the column names returned by DESCRIBE. Never guess or assume. **Step 2: Think about what questions users would ask this data** Based on the table/column names, deduce what the data represents and what insights users would want: | Data Type | Example Tables | Questions Users Would Ask | Query Pattern | |-----------|----------------|---------------------------|---------------| | **Sales/Orders** | orders, transactions, sales | "What's the revenue by region?" "Top customers?" | GROUP BY with SUM, ranking | | **Customer/User** | customers, users, accounts | "How many active users?" "Customer segments?" | COUNT, segmentation, cohorts | | **Events/Logs** | events, logs, activity | "What happened last 7 days?" "Error rate?" | Time filters, COUNT by type | | **Product/Inventory** | products, inventory, catalog | "What's in stock?" "Top products?" | JOINs, availability checks | | **Financial** | invoices, payments, budgets | "Monthly spend?" "Outstanding balance?" | SUM, date aggregations | **Step 3: Generate 2-3 meaningful queries** **Rules:** - **ALWAYS use fully qualified table names**: `DATABASE.SCHEMA.TABLE` - **NEVER use `SELECT *`** - select specific, useful columns - **Include aggregations** (SUM, COUNT, AVG) with GROUP BY - **Include JOINs** if multiple related tables exist - **Include date filters** for time-series data - Validate SQL compiles before adding to manifest **Example - For a CALLS table with columns (call_id, agent_id, duration_seconds, created_at, status):** ```sql -- Example 1: Call volume and average duration by day SELECT DATE_TRUNC('day', created_at) as call_date, COUNT(*) as total_calls, AVG(duration_seconds) as avg_duration_sec, SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed_calls FROM MYDB.MYSCHEMA.CALLS WHERE created_at >= DATEADD('day', -30, CURRENT_DATE) GROUP BY 1 ORDER BY 1 DESC; -- Example 2: Top agents by call volume SELECT agent_id, COUNT(*) as total_calls, SUM(duration_seconds) as total_duration, AVG(duration_seconds) as avg_call_duration FROM MYDB.MYSCHEMA.CALLS GROUP BY agent_id ORDER BY total_calls DESC LIMIT 10; ``` 4. **Request approval flow** **How to interpret user instructions:** - If instruction says "Request approvals are handled inside Snowflake" → **include** `request_approval_type: "REQUEST_AND_APPROVE_IN_SNOWFLAKE"` - If instruction says "Request approvals are handled outside Snowflake" → **include** `request_approval_type: "REQUEST_AND_APPROVE_OUTSIDE_SNOWFLAKE"` - If user does not specify how approvals are handled → **omit** the field (defaults to `REQUEST_AND_APPROVE_OUTSIDE_SNOWFLAKE`) Example when approvals are handled inside Snowflake: ```yaml request_approval_type: "REQUEST_AND_APPROVE_IN_SNOWFLAKE" ``` 5. **Auto-fulfillment**: **⚠️ When auto-fulfillment is REQUIRED (include it when ANY of these apply):** - Targeting an account in a different region than the current account, OR - Targeting all accounts in the organization (which may include accounts in different regions), OR - Using a remote access region (an access region different from the current account's region) **⚠️ When auto-fulfillment is NOT required (omit it):** - Targeting only the current account (same region) - Targeting only accounts in the same region as the current account AND using only that region as access region Add auto-fulfillment setting to the manifest in this format **ONLY when required**: ```yaml auto_fulfillment: refresh_type: "SUB_DATABASE" refresh_schedule: "10 MINUTE" # Check existing listings on same DB for schedule ``` 6. **Generate the manifest** and present to user: ```sql CREATE ORGANIZATION LISTING SHARE AS $$ title: "" description: | organization_profile: "" organization_targets: discovery: # Targeting all accounts in the organization - all_internal_accounts: true # OR for specific accounts (use singular "account:" NOT "accounts:"): # - account: "ACCOUNT_1" # - account: "ACCOUNT_2" # OR omit discovery field entirely if user says "Do not allow discovery" access: # Targeting all accounts in the organization - all_internal_accounts: true # OR for specific accounts: # - account: "ACCOUNT_1" # - account: "ACCOUNT_2" # ⚠️ Use ONLY account_name from SHOW ACCOUNTS # ⚠️ Omit this entire access block if user says "access must be requested" support_contact: "" # Use user's support contact email approver_contact: "" # Use user's approver contact email, always include # Include request_approval_type if user specifies approval handling method # Examples: # request_approval_type: "REQUEST_AND_APPROVE_IN_SNOWFLAKE" # When "handled inside Snowflake" # request_approval_type: "REQUEST_AND_APPROVE_OUTSIDE_SNOWFLAKE" # When "handled outside Snowflake" # Omit if not specified (defaults to REQUEST_AND_APPROVE_OUTSIDE_SNOWFLAKE) # Always include data_dictionary for discoverability (up to 5 objects) # ⚠️ Use UNQUOTED identifiers for database, schema, and object names data_dictionary: featured: database: DATABASE_NAME # No quotes! objects: - schema: SCHEMA_NAME # No quotes! name: TABLE_1 # No quotes! domain: TABLE - schema: SCHEMA_NAME name: TABLE_2 domain: TABLE # Auto-select up to 5 most relevant tables/views # Always include usage_examples to help consumers (2-3 examples) # ⚠️ ALWAYS use fully qualified table names: DATABASE.SCHEMA.TABLE usage_examples: - title: "" description: "" query: | SELECT col1, col2 FROM DATABASE.SCHEMA.TABLE WHERE condition - title: "" description: "" query: | SELECT * FROM DATABASE.SCHEMA.TABLE LIMIT 10 # Access regions: Can be ALL, specific regions, or current region based on instruction # Examples: # - "all regions" instruction → ALL # - "specific regions" → PUBLIC.AWS_US_WEST_2, PUBLIC.AWS_US_EAST_1 # - No mention → current region (e.g., PUBLIC.AWS_US_WEST_2) locations: access_regions: - name: "PUBLIC.AWS_US_WEST_2" # Default: current region if not specified # Include auto_fulfillment ONLY when: # - Targeting accounts in different region, OR # - Targeting all accounts, OR # - Using remote access region (different from current region) # auto_fulfillment: # refresh_type: "SUB_DATABASE" # refresh_schedule: "10 MINUTE" # Check existing listings on same DB for schedule # Include custom_attributes ONLY when required attributes were found in SHOW AVAILABLE INTERNAL MARKETPLACE CONFIGS # Omit this block entirely if no required custom attributes exist # custom_attributes: # - name: # values: # - # - # include multiple values if the attribute accepts them $$ PUBLISH = ; ``` **⚠️ CRITICAL - PUBLISH flag:** - If instruction says "Create a **draft** listing" → use `PUBLISH = FALSE` - If instruction says "Create and **publish**" or just "Create" → use `PUBLISH = TRUE` - Default to `TRUE` unless explicitly told to create a draft **⚠️ CRITICAL - Auto-fulfillment:** Include `auto_fulfillment` when ANY of these apply: - Targeting accounts in different region than current account - Targeting all accounts in the organization - Using remote access region (different from current account's region) **⚠️ Refresh Schedule**: If other listings exist on the same database, the refresh_schedule MUST match. Query existing listings to check. **⚠️ CRITICAL**: Do NOT use CREATE LISTING syntax to create organizational listing **⚠️ MANDATORY STOPPING POINT**: Present complete manifest to user for confirmation before executing. Show summary: ``` Summary: - Share name: - Objects included: - Featured in data dictionary: - PII detected: - Usage examples: - Discovery: - Access: - Regions: ALL (default) Does this look correct? (Yes/No) ``` **Only execute after user confirms.** --- ### Step 4: Verify and Notify **Goal:** Confirm listing created and provide user with access information. **Actions:** 1. **Verify listing**: ```sql SHOW LISTINGS; DESCRIBE LISTING ; ``` 2. **Notify user** (always show listing TITLE, not internal name): - To get the listing global name, run: ```sql DESCRIBE LISTING ``` and use the exact name from the 'global_name' column. ``` ✅ Your data product "" has been created successfully! **Listing Title:** ← Always show title to user **Share Name:** **State:** PUBLISHED (automatic for org listings) **Listing URL:** https://app.snowflake.com/marketplace/internal/listing/ **To view your listing:** 1. Go to Snowsight: https://app.snowflake.com 2. Navigate: Data Sharing → Internal Sharing → Listings tab 3. Find your listing: "" ``` **⚠️ Always display the listing TITLE** (e.g., "Customer Analytics Data"), not the internal listing name (e.g., CUSTOMER_ANALYTICS_LISTING) **Output:** Published organizational listing accessible to target accounts. --- ### Step 5: Manage Listing (Optional) **If user wants to update the listing:** **Add objects to share:** ```sql GRANT SELECT ON TABLE .. TO SHARE ; DESCRIBE SHARE ; ``` **Update manifest:** ```sql -- ⚠️ NOTE: Use "AS" without "SET" when updating manifest content -- ⚠️ NOTE: "CREATE OR REPLACE" is NOT supported for org listings - use ALTER ALTER LISTING AS $$ title: "Updated Title" -- ... updated manifest fields $$; ``` **Publish listing** (if not auto-published): ```sql -- ⚠️ Use ALTER LISTING ... PUBLISH (not SET STATE = PUBLISHED) ALTER LISTING PUBLISH; ``` **Unpublish listing:** ```sql ALTER LISTING UNPUBLISH; ``` **Delete listing:** ```sql DROP LISTING ; DROP SHARE ; -- Optional ``` **Handle access requests** (if using `REQUEST_AND_APPROVE_IN_SNOWFLAKE`): ```sql -- View pending requests SELECT * FROM SNOWFLAKE.DATA_SHARING_USAGE.LISTING_ACCESS_REQUESTS WHERE LISTING_NAME = '' AND REQUEST_STATUS = 'PENDING'; -- Approve/deny CALL SYSTEM$APPROVE_LISTING_REQUEST(''); CALL SYSTEM$DENY_LISTING_REQUEST('', 'Reason'); ``` --- ## Organization Targets Quick Reference **⚠️ SYNTAX WARNING**: Use singular `account:` NOT plural `accounts:` **All accounts discover & access:** ```yaml organization_targets: discovery: - all_internal_accounts: true access: - all_internal_accounts: true ``` **Specific accounts for discovery AND access:** ```yaml # ⚠️ Use singular "account:" - NOT "accounts:" organization_targets: discovery: - account: "ACCOUNT_1" # ← singular "account:" - account: "ACCOUNT_2" access: - account: "ACCOUNT_1" - account: "ACCOUNT_2" ``` **Specific accounts with roles:** ```yaml organization_targets: discovery: - all_internal_accounts: true access: - account: 'finance_account' # ← singular "account:" roles: ['analyst', 'manager'] - account: 'analytics_account' ``` --- ## Stopping Points - ✋ **Step 1**: After gathering requirements (confirm all inputs before proceeding) - ✋ **Step 3**: After generating manifest (confirm YAML before execution) **Resume rule:** Upon user approval, proceed directly to next step without re-asking. ## Output - Published organizational listing in Internal Marketplace - Share containing specified database objects - Snowsight URL for listing management - ULL (Uniform Listing Locator) for referencing the listing ## Common Errors Quick Reference | Error | Cause | Fix | |-------|-------|-----| | "Share does not currently have a database" | Wrong grant order | Grant DATABASE first, then SCHEMA, then TABLES | | "invalid identifier 'column_name'" | Wrong column name in usage_examples | Run `DESCRIBE TABLE` first, use actual column names | | YAML syntax error with `accounts:` | Used plural | Use singular `account:` not `accounts:` | | "Semantic view not found" | Used `SHOW VIEWS` | Use `SHOW SEMANTIC VIEWS` instead | | "USAGE not supported for semantic view" | Wrong privilege | Use `GRANT SELECT ON SEMANTIC VIEW` | | "Missing approver contact" | Field required | Always include `approver_contact` | ## References For detailed information, **load** these files: - `references/manifest-reference.md`: All manifest fields, data attributes, data dictionary config, access control setup - `references/templates.md`: Quick copy-paste templates for common scenarios - `references/errors.md`: Common errors and troubleshooting guide ## Known Limitations - Each share can be attached to **one listing only** - Reader accounts not supported with organizational listings - Native App listings don't support target roles - Multiple regions require auto-fulfillment configuration - Provider studio analytics not supported for org listings