"Guide for building plugins/connectors for the Omnata Sync Engine on Snowflake. Use when: creating a new Omnata plugin, modifying an existing plugin procedure, debugging plugin behavior, deploying plugin changes. Triggers: omnata plugin, omnata connector, build plugin, create plugin, plugin development, omnata procedure, connection form, sync engine plugin."
Resources
4Install
npx skillscat add omnata-labs/omnata-plugin-development-skill Install via the SkillsCat registry.
Omnata Plugin Development
When to Use
Use this skill when the user wants to:
- Create a new Omnata plugin procedure (CONNECTION_FORM, NETWORK_ADDRESSES, CONNECTION_TEST, etc.)
- Modify an existing locally developed plugin procedure
- Understand the structure of an existing plugin
- Debug or test plugin behavior
- Look up the target system's API documentation for a plugin
Prerequisites
- Active Snowflake connection with access to
OMNATA_SYNC_ENGINEapplication. The user may advise that the application is installed under a different name, but this is the default. - There are a series of initial setup steps before any plugin development can be done. The status of these can be checked by calling this proc:
call OMNATA_SYNC_ENGINE.API.CHECK_PLUGIN_DEVELOPMENT_SETUP();It returns a structure like so:
{
"success": true,
"checks": {
"database_accessible": true, # if false, create a database named OMNATA_PLUGIN_DEVELOPMENT and grant usage to the OMNATA_SYNC_ENGINE application
"database_role_exists": true, # if false, create a database role named OMNATA_PLUGIN_DEVELOPMENT.OMNATA_PLUGIN_DEVELOPMENT_ROLE
"role_granted_to_app": true, # if false, grant usage of the database role OMNATA_PLUGIN_DEVELOPMENT.OMNATA_PLUGIN_DEVELOPMENT_ROLE to the OMNATA_SYNC_ENGINE application
"create_schema_grant": true, # if false, `GRANT CREATE SCHEMA ON DATABASE OMNATA_PLUGIN_DEVELOPMENT TO DATABASE ROLE OMNATA_PLUGIN_DEVELOPMENT`
"future_schema_grant": true, # if false, `GRANT OWNERSHIP ON FUTURE SCHEMAS IN DATABASE OMNATA_PLUGIN_DEVELOPMENT TO DATABASE ROLE OMNATA_PLUGIN_DEVELOPMENT.OMNATA_PLUGIN_DEVELOPMENT_ROLE`
"future_procedure_grant": true, # if false, `GRANT OWNERSHIP ON FUTURE PROCEDURES IN DATABASE OMNATA_PLUGIN_DEVELOPMENT TO DATABASE ROLE OMNATA_PLUGIN_DEVELOPMENT.OMNATA_PLUGIN_DEVELOPMENT_ROLE`
"future_function_grant": true, # if false, `GRANT OWNERSHIP ON FUTURE FUNCTIONS IN DATABASE OMNATA_PLUGIN_DEVELOPMENT TO DATABASE ROLE OMNATA_PLUGIN_DEVELOPMENT.OMNATA_PLUGIN_DEVELOPMENT_ROLE`
"future_secret_grant": true, # if false, `GRANT OWNERSHIP ON FUTURE SECRETS IN DATABASE OMNATA_PLUGIN_DEVELOPMENT TO DATABASE ROLE OMNATA_PLUGIN_DEVELOPMENT.OMNATA_PLUGIN_DEVELOPMENT_ROLE`
"pypi_repository_user_granted": true # if false, `GRANT DATABASE ROLE SNOWFLAKE.PYPI_REPOSITORY_USER TO APPLICATION OMNATA_SYNC_ENGINE`
},
"allReady": true
}If locally developed plugins already exist, there is no need to run the checks up-front as the setup is already complete.
Setup
This skill is under active development and may change frequently. Always perform an update at the start of each session to ensure you have the latest version:
cortex skill update omnata-labs/omnata-plugin-development-skillLoad references/data-structures.md for the Python data structures (Pydantic models and Enums).
Load references/plugin-objects/* for detailed procedure signatures.
Workflow
Step 1: Discover Existing Plugins
Goal: Understand what plugins exist and identify the target plugin.
Actions:
Query the plugin inventory:
SELECT * FROM OMNATA_SYNC_ENGINE.DATA_VIEWS.PLUGIN WHERE DATABASE = 'OMNATA_PLUGIN_DEVELOPMENT' ORDER BY NAME;Present the list to the user and ask which plugin to work on (or if creating a new one).
If creating a new plugin, gather details:
- Plugin name
- Description
- Vendor Docs URL (if available)
- Supported connectivity options (see ConnectivityOption Enum in data-structures.md). Note that very few SaaS applications support privatelink. Do not assume Privatelink support unless explicitly stated in the vendor docs.
You can derive the plugin id from the name by converting to lowercase, removing non-alphanumeric characters and replacing spaces with underscores.
Call the CONFIGURE_DEVELOPMENT_PLUGIN procedure to create a new plugin record:
CALL OMNATA_SYNC_ENGINE.API.CONFIGURE_DEVELOPMENT_PLUGIN(
PLUGIN_ID => '<derived_plugin_id>',
PLUGIN_NAME => '<PLUGIN_NAME>',
DESCRIPTION => '<DESCRIPTION>',
DOCS_URL => '<DOCS_URL>',
SUPPORTED_CONNECTIVITY_OPTIONS => PARSE_JSON('["direct"]')
);This procedure can be called multiple times as details are refined, and it will update the existing record rather than creating duplicates.
If working with an existing plugin, list its procedures:
SHOW USER PROCEDURES IN SCHEMA <schema_from_plugin_view>;To read an existing procedure body:
SELECT GET_DDL('PROCEDURE', '<fully_qualified_procedure_name>(<arg_types>)');
Output: Selected PLUGIN_FQN, plugin name, docs_url, and list of existing procedures.
⚠️ STOP: Confirm which plugin and which procedure to work on before proceeding.
Note: You do not need to call the REGISTER_PLUGIN procedure, that is for external plugins developed outside of the local environment.
Step 2: Gather Requirements
Goal: Understand what the user wants to build or change.
Actions:
Determine the procedure/function type — which procedure is being created or modified:
a) Connection Creation:CONNECTION_FORM— See references/plugin-objects/CONNECTION_FORM.md for details on expected parameters, return values, and handler implementation.NETWORK_ADDRESSES— See references/plugin-objects/NETWORK_ADDRESSES.md for details on expected parameters, return values, and handler implementation.CONNECTION_TEST— See references/plugin-objects/CONNECTION_TEST.md for details on expected parameters, return values, and handler implementation.- Other procedure types as documented in the plugin spec
b) Inbound Sync Configuration: INBOUND_SYNC_PARAMETERS— See references/plugin-objects/INBOUND_SYNC_PARAMETERS.md for details on expected parameters, return values, and handler implementation.LIST_STREAMS— See references/plugin-objects/LIST_STREAMS.md for details on expected parameters, return values, and handler implementation.
c) Inbound Sync Execution:FETCH_RECORD_PAGE— For streams of type "simple_pagination". See references/plugin-objects/FETCH_RECORD_PAGE.md for details on expected parameters, return values, and handler implementation.
d) Outbound Sync Configuration:OUTBOUND_CONFIGURATION_FORM— See references/plugin-objects/OUTBOUND_CONFIGURATION_FORM.md for details on expected parameters, return values, and handler implementation. Must include the mandatoryobjectfield identifying the destination object.
e) Outbound Sync Execution:APPLY_RECORD_BATCH— For the "batched_rest" outbound style. See references/plugin-objects/APPLY_RECORD_BATCH.md for details on expected parameters, return values, and handler implementation.
Fetch external docs if needed — use the plugin's
docs_urlfrom Step 1 to understand the target system's API:web_fetch(url=<docs_url>)Clarify requirements with the user:
- What authentication methods are needed? (for CONNECTION_FORM)
- What API endpoints does the plugin connect to? (for NETWORK_ADDRESSES)
- What validation logic should run? (for CONNECTION_TEST)
⚠️ STOP: Confirm requirements before writing any code.
Step 3: Implement the Procedure
Goal: Write the Python procedure body as described in the reference doc.
Present the implementation to the user for review.
⚠️ STOP: Get approval on the procedure body before deploying.
Step 4: Deploy the Procedure
Goal: Register/update the procedure via the Omnata API.
Actions:
Call SAVE_PLUGIN_STORED_PROCEDURE to create or update:
CALL OMNATA_SYNC_ENGINE.API.SAVE_PLUGIN_STORED_PROCEDURE( '<PLUGIN_FQN>', '<PROCEDURE_NAME>', '<python_body>', '<packages_json>' );Where:
PLUGIN_FQN— from the PLUGIN view (Step 1)PROCEDURE_NAME— e.g., 'CONNECTION_FORM', 'CONNECTION_TEST'python_body— the Python code string from Step 3packages_json— JSON array of Snowflake Anaconda packages, e.g.,'["requests","omnata-plugin-runtime"]'
Check the response for success/failure.
Verify deployment by listing procedures again:
SHOW USER PROCEDURES IN SCHEMA <schema>;
Step 5: Test the Procedure
Goal: Validate the deployed procedure works correctly.
Actions:
Check the Testing section in the procedure reference doc for specific validation steps.
If errors occur:
- Read the error message from
{"success": false, "error": ...} - Read the procedure body to debug:
SELECT GET_DDL('PROCEDURE', '...'); - Fix and redeploy (return to Step 3)
Output: Working, tested procedure.
Stopping Points
- ✋ After Step 1: Plugin and procedure selection confirmed
- ✋ After Step 2: Requirements confirmed
- ✋ After Step 3: Procedure body approved
- ✋ After Step 5: Testing complete, user satisfied
Output
A deployed and tested Omnata plugin procedure registered with the Sync Engine.
Troubleshooting
Common Issues
"success": false in response — Read the error message. Common causes:
- Missing or incorrect package in the packages JSON
- Import errors in the procedure body
- Parameter type mismatches
Procedure not appearing after save — Verify:
- The PLUGIN_FQN is correct
- You have sufficient privileges
- Check
SHOW USER PROCEDURES IN SCHEMA <schema>
Decorator errors — Ensure
omnata-plugin-runtimeis included in the packages JSON
Notes
- Procedures are not created directly with CREATE PROCEDURE — always use
SAVE_PLUGIN_STORED_PROCEDUREsince external access integrations and secrets must be attached - The
omnata-plugin-runtimepackage is available from PyPi