{"templateName":"quickstart-page-template","cssClassNames":"page basicpage summit-page","allowedRenditionsWidth":["320","480","640","768","960","1200","1440","1920"],"canonicalLink":"https://www.snowflake.com/en/developers/guides/data-engineering-with-coco/","robotsTags":[],"language":"en","title":"Data Engineering with CoCo","analyticsPageType":"quickstart-page-template","analyticsCategory":"general","analyticsSubCategory":"","excludeFromAnalytics":false,":mappedPath":"/en/developers/guides/data-engineering-with-coco/",":type":"snowflake-site/components/structure/page",":items":{"root":{"columnCount":12,"columnClassNames":{"markup_editor_1950346551":"aem-GridColumn aem-GridColumn--default--12","experiencefragment-banner":"aem-GridColumn aem-GridColumn--default--12","experiencefragment-header":"aem-GridColumn aem-GridColumn--default--12","responsivegrid":"aem-GridColumn aem-GridColumn--default--12","experiencefragment-footer":"aem-GridColumn aem-GridColumn--default--12","modal_container":"aem-GridColumn aem-GridColumn--default--12","markup_editor":"aem-GridColumn aem-GridColumn--default--12"},"gridClassNames":"aem-Grid aem-Grid--12 aem-Grid--default--12",":items":{"experiencefragment-banner":{"id":"experiencefragment-c621f8bfab","localizedFragmentVariationPath":"/content/experience-fragments/snowflake-site/language-masters/en/site/pushdown-banner/master/jcr:content","configured":true,":type":"snowflake-site/components/experiencefragment","xfModelPath":"/content/experience-fragments/snowflake-site/language-masters/en/site/pushdown-banner/master.xfmodel.json"},"experiencefragment-header":{"id":"experiencefragment-4484d2d2f7","localizedFragmentVariationPath":"/content/experience-fragments/snowflake-site/language-masters/en/site/mega-nav-header/master/jcr:content","configured":true,":type":"snowflake-site/components/experiencefragment","xfModelPath":"/content/experience-fragments/snowflake-site/language-masters/en/site/mega-nav-header/master.xfmodel.json","languageNavPath":"/content/snowflake-site/global/en/developers/guides/data-engineering-with-coco.languagenav.json"},"markup_editor_1950346551":{"id":"markup-editor-5e610ad205","title":" ","cssContent":".snowflake-markdown-table code[class*=language-],.snowflake-markdown-table code[class*=language-],.snowflake-markdown .snowflake-text code[class*=language-],.snowflake-markdown .snowflake-text pre[class*=language-]{background-color:rgba(var(--ui-12-rgb),.5);color:var(--text-01);text-shadow:none;padding:var(--spacing-00);border-radius:var(--spacing-00);font-size:smaller}",":type":"snowflake-site/components/markup-editor","isGSAPEnabled":false},"responsivegrid":{"columnCount":12,"columnClassNames":{"quickstart_hero":"aem-GridColumn aem-GridColumn--default--12","flexible_column_cont":"aem-GridColumn aem-GridColumn--default--12","markup_editor":"aem-GridColumn aem-GridColumn--default--12"},"gridClassNames":"aem-Grid aem-Grid--12 aem-Grid--default--12",":items":{"quickstart_hero":{"id":"quickstart-hero-5fe73cb210","fragmentPath":"/content/dam/snowflake-site/en/content-fragments/quickstarts/data-engineering-with-coco",":type":"snowflake-site/components/quickstart/quickstart-hero","quickstartHeroFirstCertifiedTag":{"tagText":"Community Solution","tagColor":"#29B5E8","tagPath":"/content/cq:tags/snowflake-site/taxonomy/solution-center/certification/community-sourced","tagIcon":""},"isDeveloperGuidesPage":false,"quickstartHeroTitle":{"lines":["Data Engineering with CoCo"],"type":"heading2",":type":"snowflake-site/components/title-v2"},"quickstartHeroAuthor":"Jeremiah Hansen","quickstartHeroFirstSnowflakeFeatureTag":{"tagText":"Snowflake CoCo","tagColor":"#29B5E8","tagPath":"/content/cq:tags/snowflake-site/taxonomy/snowflake-feature/coco","tagIcon":""},"quickstartHeroForkRepoLink":{"id":"button-ec6a2e6cd8","showOutboundIcon":false,"buttonLink":{"valid":true,"attributes":{"target":"_blank"},"url":"https://github.com/Snowflake-Labs/sfguide-data-engineering-with-coco"},"linkTargetContentType":"GENERIC",":type":"snowflake-site/components/button","linkType":"SNOWFLAKE_EXTERNAL","text":"Fork Repo"},"quickstartHeroBreadcrumbs":[{"title":"Data Engineering with CoCo","url":"https://www.snowflake.com/content/snowflake-site/global/en/developers/guides/data-engineering-with-coco","currentPage":true},{"title":"Guides","url":"https://www.snowflake.com/content/snowflake-site/global/en/developers/guides","currentPage":false},{"title":"Snowflake for Developers","url":"https://www.snowflake.com/content/snowflake-site/global/en/developers","currentPage":false}]},"flexible_column_cont":{"id":"flexible-column-container-7e737ae541","propertiesId":"quickstart-template-main-flexible-container","type":"2-column-75-25","alignColumns":"top","containerMaxWidth":"extra-large","topPadding":"none","bottomPadding":"none","spaceBetween":"small","reverseOnMobile":false,"carouselOnMobile":false,"backgroundImageOption":"none","flexible_column_content_container_1":{"layout":"SIMPLE","id":"container-35539843b7",":type":"snowflake-site/components/flexible-column-container/flexible-column-content-container",":items":{"contentfragment":{"id":"contentfragment-a951855bbd","paragraphs":["&lt;!-- ------------------------ --&gt;\n","\u003Ch2\u003EOverview\u003C/h2\u003E\n","\u003Cp\u003E\u003Cimg src=\"https://www.snowflake.com/content/dam/snowflake-site/developers/guides/data-engineering-with-coco/coco_de_logo.png\" alt=\"CoCo DE Logo\"\u003E\u003C/p\u003E\n","\u003Cp\u003EAnyone can get an AI agent to produce a result. Professionals ensure the right result, every time.\u003C/p\u003E\n","\u003Cp\u003EAI coding agents are completely reshaping the data engineering landscape &mdash; and if you're not already using them regularly, I'd encourage you to start today. But here's the thing: the fact that an AI agent can generate code isn't actually that interesting anymore. What \u003Cem\u003Eis\u003C/em\u003E interesting is how professional data engineers should be thinking about and leveraging these tools to create repeatable, high-quality outcomes.\u003C/p\u003E\n","\u003Cp\u003EThat's exactly what this Guide is about. We're going to use Snowflake's AI coding agent &mdash; \u003Ca href=\"https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code\"\u003ECortex Code\u003C/a\u003E (or &quot;CoCo&quot;) &mdash; to build a real data engineering project. But more importantly, we're going to do it the \u003Cem\u003Eright way\u003C/em\u003E, by encoding our standards and conventions into reusable Skills and Plugins so that every member of your team gets consistent, professional results from the agent &mdash; not just you, and not just today.\u003C/p\u003E\n","\u003Ch3\u003EWhat You'll Learn\u003C/h3\u003E\n\u003Cul\u003E\u003Cli\u003EWhat Cortex Code is, how to install it, and why it's particularly powerful for Snowflake data engineers\u003C/li\u003E\u003Cli\u003EHow to use \u003Ccode\u003EAGENTS.md\u003C/code\u003E to give your AI coding agent project-level context and conventions\u003C/li\u003E\u003Cli\u003EWhat agent Skills are, how they're structured, and when to create custom ones vs. using bundled ones\u003C/li\u003E\u003Cli\u003EHow to create a custom skill that encodes your team's specific conventions\u003C/li\u003E\u003Cli\u003EWhat CoCo Plugins are, how all the pieces fit together, and why they're the right packaging unit for sharing agent capabilities\u003C/li\u003E\u003Cli\u003EHow to add a lifecycle hook to protect your production environment\u003C/li\u003E\u003Cli\u003EHow to define a subagent for autonomous, repeatable tasks\u003C/li\u003E\u003Cli\u003EHow to run a CoCo subagent from a GitHub Actions CI/CD pipeline\u003C/li\u003E\u003C/ul\u003E\n","\u003Ch3\u003EWhat You'll Build\u003C/h3\u003E\n\u003Cul\u003E\u003Cli\u003EAn \u003Ccode\u003EAGENTS.md\u003C/code\u003E file that gives CoCo project-level context for every session\u003C/li\u003E\u003Cli\u003EA custom agent Skill that encodes your team's dbt conventions\u003C/li\u003E\u003Cli\u003EA new dbt model built by CoCo using that custom skill\u003C/li\u003E\u003Cli\u003EA CoCo Plugin that bundles your skill, a production safety hook, and a dbt review subagent together into a single deployable unit\u003C/li\u003E\u003Cli\u003EA GitHub Actions CI/CD pipeline that automatically reviews dbt changes on every pull request using CoCo\u003C/li\u003E\u003C/ul\u003E\n","\u003Ch3\u003EPrerequisites\u003C/h3\u003E\n\u003Cul\u003E\u003Cli\u003EFamiliarity with dbt (models, sources, tests)\u003C/li\u003E\u003Cli\u003EFamiliarity with Snowflake\u003C/li\u003E\u003Cli\u003EFamiliarity with Git and GitHub\u003C/li\u003E\u003C/ul\u003E\n","\u003Ch3\u003EWhat You'll Need\u003C/h3\u003E\n\u003Cul\u003E\u003Cli\u003E\u003Cstrong\u003EA Snowflake Account\u003C/strong\u003E. If you don't already have a Snowflake account you can create a trial account for free. Visit the \u003Ca href=\"https://signup.snowflake.com/cortex-code\"\u003ESnowflake Trial Account for CoCo Sign Up\u003C/a\u003E page to get started.\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003EA GitHub account\u003C/strong\u003E. If you don't already have a GitHub account you can create one for free. Visit the \u003Ca href=\"https://github.com/signup\"\u003EJoin GitHub\u003C/a\u003E page to get started.\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003ECoCo Desktop\u003C/strong\u003E installed on your local machine. Visit the \u003Ca href=\"https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code-desktop/onboarding-and-authentication\"\u003ECoCo Desktop Installation\u003C/a\u003E page to get started.\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003Edbt Core\u003C/strong\u003E installed on your local machine. Visit the \u003Ca href=\"https://docs.getdbt.com/docs/core/installation-overview\"\u003Edbt Core Install\u003C/a\u003E page to get started.\u003C/li\u003E\u003C/ul\u003E\n&lt;!-- ------------------------ --&gt;\n","\u003Ch2\u003ESetup\u003C/h2\u003E\n","\u003Cp\u003EBefore we start building, let's get CoCo and the starter dbt project connected to your Snowflake account.\u003C/p\u003E\n","\u003Ch3\u003EFork and Clone the Guide Repository\u003C/h3\u003E\n","\u003Cp\u003EThis Guide uses a starter repository that includes a pre-built dbt project. The two existing models (\u003Ccode\u003Ecustomers\u003C/code\u003E and \u003Ccode\u003Eorders_summary\u003C/code\u003E) are there as a starting point &mdash; you'll add the third model yourself using a custom skill you create later on.\u003C/p\u003E\n","\u003Cp\u003EStart by forking the starter repository to your own GitHub account. Visit the \u003Ca href=\"https://github.com/Snowflake-Labs/sfguide-data-engineering-with-coco\"\u003EData Engineering with CoCo Guide Repository\u003C/a\u003E and click the \u003Cstrong\u003EFork\u003C/strong\u003E button near the top right. Complete any required fields and click \u003Cstrong\u003ECreate Fork\u003C/strong\u003E.\u003C/p\u003E\n","\u003Cp\u003EThen clone your fork to your local machine:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-bash\"\u003Egit clone https://github.com/&lt;YOUR_USERNAME&gt;/sfguide-data-engineering-with-coco\ncd sfguide-data-engineering-with-coco\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003ETake a moment to look at what's in the starter:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E├── dbt/\n│   ├── dbt_project.yml\n│   ├── profiles.yml.example\n│   └── models/\n│       ├── _sources.yml\n│       ├── customers.sql\n│       └── orders_summary.sql\n├── scripts/\n│   └── setup.sql\n├── .gitignore\n├── LICENSE\n├── README.md\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Ch3\u003EConfigure CoCo Desktop and Open the Project\u003C/h3\u003E\n","\u003Cp\u003EIf you haven't already installed CoCo Desktop, follow the \u003Ca href=\"https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code-desktop/onboarding-and-authentication\"\u003Einstallation instructions\u003C/a\u003E for your operating system.\u003C/p\u003E\n","\u003Cp\u003EOnce installed, open CoCo Desktop and configure your Snowflake connection. CoCo supports several authentication methods, for this Guide use Local OAuth authentication. See the \u003Ca href=\"https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code-desktop/onboarding-and-authentication#authentication-methods\"\u003ECoCo authentication documentation\u003C/a\u003E for all options.\u003C/p\u003E\n","\u003Cp\u003EFinally, use \u003Cstrong\u003EFile &rarr; Open Folder\u003C/strong\u003E to open the \u003Ccode\u003Esfguide-data-engineering-with-coco\u003C/code\u003E directory you cloned above. The first time you open the folder CoCo Desktop will ask you if you Trust the files, go ahead and Trust them. CoCo is context-aware: opening the project folder means the agent can see your files, read your code, and run commands in the right place.\u003C/p\u003E\n","\u003Ch3\u003ECreate the Snowflake Demo Environment\u003C/h3\u003E\n","\u003Cp\u003EThe dbt project is pointed at \u003Ccode\u003ESNOWFLAKE_SAMPLE_DATA.TPCH_SF1\u003C/code\u003E, which is available in every Snowflake account. There's nothing to load &mdash; the data is already there.\u003C/p\u003E\n\u003Cblockquote\u003E\n","\u003Cp\u003E\u003Cstrong\u003ENote\u003C/strong\u003E &mdash; The \u003Ccode\u003ESNOWFLAKE_SAMPLE_DATA\u003C/code\u003E sample database is created by default for newer accounts. If the database has not been created for your account and you want access to it follow the instructions on the \u003Ca href=\"https://docs.snowflake.com/en/user-guide/sample-data-using\"\u003EUse the sample database\u003C/a\u003E page.\u003C/p\u003E\n\u003C/blockquote\u003E\n","\u003Cp\u003EBut we need to create the demo environment in Snowflake so that dbt can write to it. The \u003Ccode\u003Escripts/setup.sql\u003C/code\u003E script contains all the code needed to create the role, warehouse, database and schema for the demo environment.\u003C/p\u003E\n","\u003Cp\u003EAnd the good part is you can run SQL scripts directly from CoCo Desktop by following these steps:\u003C/p\u003E\n\u003Cul\u003E\u003Cli\u003EOpen the \u003Ccode\u003Escripts/setup.sql\u003C/code\u003E script\u003C/li\u003E\u003Cli\u003ERun all of the SQL statements in this script by clicking on the down arrow and &quot;Run all&quot;, next to the blue play button at the top right of the script, or using the shortcut CMD/CTRL+Shift+Enter\u003C/li\u003E\u003C/ul\u003E\n","\u003Ch3\u003ECreate a Snowflake Personal Access Token\u003C/h3\u003E\n","\u003Cp\u003EIn order to connect to your Snowflake account from dbt and GitHub Actions, we will use a Snowflake Personal Access Token (or PAT). Please follow the steps in \u003Ca href=\"https://docs.snowflake.com/en/user-guide/programmatic-access-tokens#generating-a-programmatic-access-token\"\u003EGenerating a programmatic access token\u003C/a\u003E to create a Snowflake PAT for your user. Use these values when creating the PAT, in the &quot;New programmatic access token&quot; dialog:\u003C/p\u003E\n\u003Cul\u003E\u003Cli\u003E\u003Cstrong\u003EName\u003C/strong\u003E: DEMO_PAT (upper case)\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003EExpires in\u003C/strong\u003E: Leave with default (15 days)\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003EGrant access\u003C/strong\u003E: Select \u003Cstrong\u003ESingle role (recommended)\u003C/strong\u003E, then the \u003Ccode\u003EDEMO_ROLE\u003C/code\u003E role\u003C/li\u003E\u003C/ul\u003E\n","\u003Cp\u003EMake sure to save the PAT before leaving the page, as you won't be able to view it again. We will use the PAT in the next section to configure dbt as well as in the final CI/CD section to connect to Snowflake from GitHub Actions.\u003C/p\u003E\n","\u003Cp\u003EFinally, run the following command in a SQL script in Workspaces. This will allow you to bypass the active network policy rule temporarily, for 60 minutes, in order to test out the CI/CD pipeline. For long-term access you need to create a network policy allowing access from the GitHub Actions environment. For more details check out our \u003Ca href=\"https://docs.snowflake.com/en/user-guide/network-policies\"\u003EControlling network traffic with network policies\u003C/a\u003E page.\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003EALTER USER &lt;YOUR_USER_NAME&gt; MODIFY PROGRAMMATIC ACCESS TOKEN DEMO_PAT\n  SET MINS_TO_BYPASS_NETWORK_POLICY_REQUIREMENT = 60;\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cblockquote\u003E\n","\u003Cp\u003E\u003Cstrong\u003ENote\u003C/strong\u003E &mdash; You may need to put double-quotes around the PAT token name in this query if you didn't name your token with all uppercase letters.\u003C/p\u003E\n\u003C/blockquote\u003E\n","\u003Ch3\u003EConfigure dbt\u003C/h3\u003E\n","\u003Cp\u003Edbt looks for \u003Ccode\u003Eprofiles.yml\u003C/code\u003E in \u003Ccode\u003E~/.dbt/\u003C/code\u003E by default. If you don't have one yet, copy the example file:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-bash\"\u003Emkdir -p ~/.dbt\ncp dbt/profiles.yml.example ~/.dbt/profiles.yml\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EIf you already have a \u003Ccode\u003E~/.dbt/profiles.yml\u003C/code\u003E, open it and add the \u003Ccode\u003Ecoco_de_guide\u003C/code\u003E profile block from \u003Ccode\u003Edbt/profiles.yml.example\u003C/code\u003E alongside your existing profiles &mdash; each top-level key is a separate profile and they won't conflict.\u003C/p\u003E\n","\u003Cp\u003EOpen \u003Ccode\u003E~/.dbt/profiles.yml\u003C/code\u003E (CMD/CTRL+p) and replace the placeholders in the \u003Ccode\u003Ecoco_de_guide\u003C/code\u003E block with your values:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-yaml\"\u003Ecoco_de_guide:\n  target: dev\n  outputs:\n    dev:\n      type: snowflake\n      account: &quot;&lt;YOUR_ACCOUNT&gt;&quot;\n      user: &quot;&lt;YOUR_USERNAME&gt;&quot;\n      password: &quot;&lt;YOUR_PERSONAL_ACCESS_TOKEN&gt;&quot;\n      role: DEMO_ROLE\n      database: DEMO_DB\n      warehouse: DEMO_WH\n      schema: TPCH_TRANSFORMED\n      threads: 4\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cblockquote\u003E\n","\u003Cp\u003E\u003Cstrong\u003ENote\u003C/strong\u003E &mdash; \u003Ccode\u003E~/.dbt/profiles.yml\u003C/code\u003E lives outside your repository so your credentials are never at risk of being committed.\u003C/p\u003E\n\u003C/blockquote\u003E\n","\u003Ch3\u003EVerify Your dbt Setup\u003C/h3\u003E\n","\u003Cp\u003EMake sure dbt can connect to your Snowflake account. Open a terminal in CoCo Desktop and run the following command:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-bash\"\u003Edbt debug --project-dir dbt/\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EYou should see \u003Ccode\u003EAll checks passed!\u003C/code\u003E at the end of the output. If you run into any connection issues, double-check your \u003Ccode\u003Eprofiles.yml\u003C/code\u003E values and make sure your Snowflake account identifier is in the correct format (e.g., \u003Ccode\u003Exy12345.us-east-1\u003C/code\u003E).\u003C/p\u003E\n&lt;!-- ------------------------ --&gt;\n","\u003Ch2\u003EWhat is Cortex Code?\u003C/h2\u003E\n","\u003Cp\u003E\u003Cimg src=\"https://www.snowflake.com/content/dam/snowflake-site/developers/guides/data-engineering-with-coco/coco_logo.png\" alt=\"CoCo DE Logo\"\u003E\u003C/p\u003E\n","\u003Cp\u003E\u003Ca href=\"https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code\"\u003ECortex Code\u003C/a\u003E (CoCo) is Snowflake's AI coding agent &mdash; an autonomous, context-aware agent optimized for data engineering, analytics, and machine learning tasks. Unlike generic coding assistants, CoCo has deep native knowledge of Snowflake: it understands your schemas, respects your RBAC configuration, and knows Snowflake best practices without being told. Critically for enterprises, the model and the data it touches never leave Snowflake's security perimeter.\u003C/p\u003E\n","\u003Ch3\u003EForm Factors\u003C/h3\u003E\n","\u003Cp\u003ECoCo is available in three form factors, and the right choice depends on how you work:\u003C/p\u003E\n\u003Ctable\u003E\u003Cthead\u003E\u003Ctr\u003E\u003Cth colspan=\"1\" rowspan=\"1\"\u003EForm factor\u003C/th\u003E\u003Cth colspan=\"1\" rowspan=\"1\"\u003EBest for\u003C/th\u003E\u003C/tr\u003E\u003C/thead\u003E\u003Ctbody\u003E\u003Ctr\u003E\u003Ctd colspan=\"1\" rowspan=\"1\"\u003E\u003Cstrong\u003ECoCo in Snowsight\u003C/strong\u003E\u003C/td\u003E\u003Ctd colspan=\"1\" rowspan=\"1\"\u003EWeb-based access directly inside Snowflake's UI. Great for SQL and notebook authoring without installing anything.\u003C/td\u003E\u003C/tr\u003E\u003Ctr\u003E\u003Ctd colspan=\"1\" rowspan=\"1\"\u003E\u003Cstrong\u003ECoCo Desktop\u003C/strong\u003E\u003C/td\u003E\u003Ctd colspan=\"1\" rowspan=\"1\"\u003EA standalone IDE for macOS and Windows (built on VS Code). Full agent experience with local file access, native Git integration, and complete support for plugins, skills, hooks, and subagents.\u003C/td\u003E\u003C/tr\u003E\u003Ctr\u003E\u003Ctd colspan=\"1\" rowspan=\"1\"\u003E\u003Cstrong\u003ECoCo CLI\u003C/strong\u003E\u003C/td\u003E\u003Ctd colspan=\"1\" rowspan=\"1\"\u003EA terminal-native agent for power users who prefer the command line or want to integrate CoCo into scripts and automation.\u003C/td\u003E\u003C/tr\u003E\u003C/tbody\u003E\u003C/table\u003E\n","\u003Cp\u003EThis Guide uses \u003Cstrong\u003ECoCo Desktop\u003C/strong\u003E throughout. Local file access and full extensibility support &mdash; skills, plugins, hooks, and subagents &mdash; are central to what we're building, and Desktop is the right tool for all of it.\u003C/p\u003E\n&lt;!-- ------------------------ --&gt;\n","\u003Ch2\u003ECreate an AGENTS.md\u003C/h2\u003E\n","\u003Cp\u003EBefore you write a single prompt, there's one thing that will improve every single interaction you have with CoCo in this project: an \u003Ccode\u003EAGENTS.md\u003C/code\u003E file.\u003C/p\u003E\n","\u003Ch3\u003EWhat is AGENTS.md?\u003C/h3\u003E\n","\u003Cp\u003E\u003Ccode\u003EAGENTS.md\u003C/code\u003E is a Markdown file at the root of your project that contains conventions, context, and commands that you want the agent to know about &mdash; every single session, automatically. Without it, you'd have to re-explain your database names, your naming conventions, and your preferred commands every time you start a new chat. With it, that context is always there.\u003C/p\u003E\n","\u003Cp\u003EThink of it as the onboarding document you'd write for a new team member &mdash; except this team member reads it perfectly every time, never forgets it, and follows it consistently. Here's the key guidance I follow when writing \u003Ccode\u003EAGENTS.md\u003C/code\u003E:\u003C/p\u003E\n\u003Cul\u003E\u003Cli\u003E\u003Cstrong\u003EKeep it short.\u003C/strong\u003E The context window is a shared, finite resource. Challenge every sentence: does the agent \u003Cem\u003Eactually\u003C/em\u003E need this, or will it figure it out on its own?\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003EEncode what the model can't infer.\u003C/strong\u003E Don't write instructions telling CoCo how to use dbt &mdash; it already knows how dbt works. Do write down your database name, your schema naming conventions, and the exact command to use for building and testing.\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003EIt doesn't change session-to-session.\u003C/strong\u003E Stable project facts belong here. Session-specific instructions belong in your prompts.\u003C/li\u003E\u003C/ul\u003E\n","\u003Ch3\u003ECreate Your AGENTS.md\u003C/h3\u003E\n","\u003Cp\u003ELet's create an \u003Ccode\u003EAGENTS.md\u003C/code\u003E for this project. In the CoCo chat panel, enter the following prompt:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003ECreate an AGENTS.md file at the root of this project. Include:\n- The Snowflake database (DEMO_DB), schema (TPCH_TRANSFORMED), and warehouse (DEMO_WH)\n- The dbt build command to use: `dbt build --project-dir dbt/`\n- The command to build a single model: `dbt build --select &lt;model_name&gt; --project-dir dbt/`\n- Snake_case naming convention for model files\n- The source data is TPCH_SF1 in SNOWFLAKE_SAMPLE_DATA; all raw tables must be referenced through _sources.yml\n- Feature branches should follow the pattern: feature/&lt;description&gt;\n- PRs are required before merging to main\n- This project uses CoCo Desktop &mdash; do not use the `cortex` CLI command\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003ECoCo will generate an \u003Ccode\u003EAGENTS.md\u003C/code\u003E file. Review it and accept/save the changes by clicking on the &quot;Keep&quot; button. Your \u003Ccode\u003EAGENTS.md\u003C/code\u003E may be slightly different, and that's OK, but it should look something like this:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-markdown\"\u003E# Project: CoCo DE Guide\n\n## Snowflake\n- Database: DEMO_DB\n- Schema: TPCH_TRANSFORMED\n- Warehouse: DEMO_WH\n\n## dbt Commands\n- Build + test: `dbt build --project-dir dbt/`\n- Single model: `dbt build --select &lt;model_name&gt; --project-dir dbt/`\n\n## Naming Conventions\n- Model files: snake_case\n- Source schema: TPCH_SF1 in SNOWFLAKE_SAMPLE_DATA\n- Transformed schema: TPCH_TRANSFORMED\n\n## Branching\n- Feature branches: `feature/&lt;description&gt;`\n- PRs required before merging to main\n\n## CoCo\n- This project uses CoCo Desktop &mdash; do not use the `cortex` CLI command\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cblockquote\u003E\n","\u003Cp\u003E\u003Cstrong\u003ENote\u003C/strong\u003E &mdash; CoCo has bundled skills that know about the CoCo CLI \u003Ccode\u003Ecortex\u003C/code\u003E command. Those skills can activate and cause CoCo to attempt CLI operations. The \u003Ccode\u003EAGENTS.md\u003C/code\u003E instruction to not use the \u003Ccode\u003Ecortex\u003C/code\u003E CLI should prevent this.\u003C/p\u003E\n\u003C/blockquote\u003E\n","\u003Ch3\u003EValidate the Starter Code Against Your Conventions\u003C/h3\u003E\n","\u003Cp\u003ENow let's put \u003Ccode\u003EAGENTS.md\u003C/code\u003E to immediate use. The starter project was built before these conventions were established &mdash; which is exactly the situation you'll often face when inheriting a codebase. Let's have CoCo audit the existing models and bring them into compliance.\u003C/p\u003E\n","\u003Cp\u003EIn the CoCo chat panel, enter:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003EReview all dbt models in this project against the conventions in AGENTS.md\nand fix any violations you find.\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003ECoCo will read \u003Ccode\u003EAGENTS.md\u003C/code\u003E, then inspect each model SQL file. It should find that \u003Ccode\u003Eorders_summary.sql\u003C/code\u003E references source tables directly by their fully-qualified Snowflake path instead of going through \u003Ccode\u003E_sources.yml\u003C/code\u003E:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E-- Violation: direct source reference\nFROM SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.ORDERS o\nLEFT JOIN SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.LINEITEM l ...\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003ECoCo will rewrite the model to use the correct \u003Ccode\u003E{{ source() }}\u003C/code\u003E references:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E-- Fixed: references go through _sources.yml\nFROM {{ source('tpch', 'orders') }} o\nLEFT JOIN {{ source('tpch', 'lineitem') }} l ...\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EClick on &quot;Keep&quot; to accept that changes. Once the fix is applied, run \u003Ccode\u003Edbt build\u003C/code\u003E to confirm nothing broke:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-bash\"\u003Edbt build --project-dir dbt/\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EThis is \u003Ccode\u003EAGENTS.md\u003C/code\u003E doing its job. CoCo didn't need to be told what the violation was or what the fix should look like &mdash; it read the conventions, read the code, and connected the two. That's the value: not any single dramatic prompt, but every prompt in the session being grounded in your actual standards rather than the model's best guess.\u003C/p\u003E\n\u003Cblockquote\u003E\n","\u003Cp\u003E\u003Cstrong\u003ETip\u003C/strong\u003E &mdash; Your \u003Ccode\u003EAGENTS.md\u003C/code\u003E should evolve as your project grows. Any time you find yourself repeating the same context in multiple prompts (a team convention, a frequently-used command, an important constraint), that's a signal it belongs in \u003Ccode\u003EAGENTS.md\u003C/code\u003E.\u003C/p\u003E\n\u003C/blockquote\u003E\n&lt;!-- ------------------------ --&gt;\n","\u003Ch2\u003EWhat is a Skill?\u003C/h2\u003E\n","\u003Cp\u003EWe've seen \u003Ccode\u003EAGENTS.md\u003C/code\u003E handle project context and enforce existing conventions. But what about when you're creating something new? When the task is &quot;build a new dbt model,&quot; \u003Ccode\u003EAGENTS.md\u003C/code\u003E tells CoCo the database name and the build command &mdash; but it doesn't tell it the specific workflow your team follows or the standards that must hold for every new model. That's what Skills are for.\u003C/p\u003E\n","\u003Cp\u003ELet's take a few minutes to understand what Skills actually are &mdash; because this concept is central to everything that follows in this Guide.\u003C/p\u003E\n","\u003Ch3\u003ESkills Defined\u003C/h3\u003E\n","\u003Cp\u003EAgent Skills are used for implementing repeatable, multi-step workflows. They're made up of instructions that tell the agent how to perform a specific type of task. Skills are supported by most AI coding agents, and the emerging open standard is documented at \u003Ca href=\"https://agentskills.io/\"\u003Eagentskills.io\u003C/a\u003E.\u003C/p\u003E\n","\u003Cp\u003EHere's the key insight: \u003Cstrong\u003ESkills encode what the model can't infer on its own.\u003C/strong\u003E This is worth repeating because it's the most common mistake I see when teams start writing skills. The frontier LLM models are incredibly capable and already know how to do most data engineering tasks. You don't need to write a Skill teaching CoCo what dbt is or how to write a SQL transformation &mdash; it already knows. What you \u003Cem\u003Edo\u003C/em\u003E need to capture in a Skill is any repeatable process that is \u003Cem\u003Especific to your team\u003C/em\u003E: your naming conventions, your testing standards, your deployment workflow, the exact steps you want followed in a particular order.\u003C/p\u003E\n","\u003Ch3\u003EThe SKILL.md File\u003C/h3\u003E\n","\u003Cp\u003EAt its core, a Skill is a folder containing a single required file: \u003Ccode\u003ESKILL.md\u003C/code\u003E. This file has two parts:\u003C/p\u003E\n\u003Col\u003E\u003Cli\u003E\u003Cstrong\u003EYAML Frontmatter\u003C/strong\u003E &mdash; metadata about the skill, including its name and description\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003EMarkdown body\u003C/strong\u003E &mdash; the actual instructions the agent will follow\u003C/li\u003E\u003C/ol\u003E\n","\u003Cp\u003EThe \u003Ccode\u003Edescription\u003C/code\u003E field is especially important: CoCo uses it to decide when to automatically invoke the Skill. Write it as a clear, one-sentence trigger &mdash; think of it as answering the question &quot;when should CoCo use this skill?&quot;\u003C/p\u003E\n","\u003Cp\u003EHere's the minimum structure of a \u003Ccode\u003ESKILL.md\u003C/code\u003E file:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-markdown\"\u003E---\nname: my-skill\ndescription: Brief description of when this skill should be used.\n---\n\n# Instructions\n\nYour workflow steps and conventions go here.\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Ch3\u003ESkill Folder Structure\u003C/h3\u003E\n","\u003Cp\u003EA Skill lives in a folder, and that folder can contain more than just \u003Ccode\u003ESKILL.md\u003C/code\u003E. You can bundle scripts, templates, and reference materials alongside your instructions:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003Emy-skill/\n├── SKILL.md          # Required &mdash; instructions and metadata\n└── scripts/          # Optional &mdash; reusable scripts the agent can run\n    └── my-script.py\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EFor many Skills, the \u003Ccode\u003ESKILL.md\u003C/code\u003E file alone is enough. The scripts folder becomes useful when your workflow requires running a specific piece of code consistently.\u003C/p\u003E\n","\u003Ch3\u003EBundled vs. Custom Skills\u003C/h3\u003E\n","\u003Cp\u003ECoCo ships with a set of bundled Skills for Snowflake-specific workflows that require specialized knowledge the base model doesn't have on its own &mdash; things like deploying dbt projects as Snowflake-native objects via the \u003Ccode\u003Esnow dbt\u003C/code\u003E CLI, managing Dynamic Tables, working with Iceberg catalogs, and more. These are maintained by Snowflake and are automatically available without any setup.\u003C/p\u003E\n","\u003Cp\u003E\u003Cimg src=\"https://www.snowflake.com/content/dam/snowflake-site/developers/guides/data-engineering-with-coco/coco_built_in_de_skills.png\" alt=\"CoCo Built-In DE Skills\"\u003E\u003C/p\u003E\n","\u003Cp\u003EFor common tasks that are well-represented in the model's training data &mdash; standard SQL, Python, dbt syntax, general software engineering practices &mdash; you typically don't need a skill at all. CoCo's base knowledge handles those.\u003C/p\u003E\n","\u003Cp\u003ECustom Skills are ones you write yourself, for your specific team and project. They don't teach CoCo how to use a tool &mdash; it already knows. They encode the \u003Cem\u003Echoices\u003C/em\u003E your team has made: which conventions to follow, which steps to run in which order, which guardrails to apply.\u003C/p\u003E\n","\u003Cp\u003EA useful rule of thumb: if you find yourself starting a prompt with &quot;remember, we always...&quot; &mdash; that's a custom skill waiting to be written.\u003C/p\u003E\n\u003Cblockquote\u003E\n","\u003Cp\u003E\u003Cstrong\u003EBest practices\u003C/strong\u003E\u003C/p\u003E\n\u003Cul\u003E\u003Cli\u003EKeep Skills under 500 lines &mdash; long skills are hard to maintain and can dilute the context window\u003C/li\u003E\u003Cli\u003EWrite the \u003Ccode\u003Edescription\u003C/code\u003E as a clear, specific trigger phrase\u003C/li\u003E\u003Cli\u003EDon't repeat general knowledge &mdash; only encode what CoCo can't infer\u003C/li\u003E\u003Cli\u003ETest your skill by invoking it and checking if CoCo follows every convention without extra prompting\u003C/li\u003E\u003C/ul\u003E\n\u003C/blockquote\u003E\n&lt;!-- ------------------------ --&gt;\n","\u003Ch2\u003EUsing CoCo Without a Skill\u003C/h2\u003E\n","\u003Cp\u003EBefore writing your first custom Skill, it's worth understanding what you \u003Cem\u003Edon't\u003C/em\u003E need to encode. The frontier model behind CoCo has broad, deep knowledge of the software and data engineering ecosystem &mdash; and that means for a lot of common tasks, you can just ask.\u003C/p\u003E\n","\u003Ch3\u003EAdd Schema Tests Without Any Skill\u003C/h3\u003E\n","\u003Cp\u003EOur starter project has two models &mdash; \u003Ccode\u003Ecustomers\u003C/code\u003E and \u003Ccode\u003Eorders_summary\u003C/code\u003E &mdash; but neither has schema tests defined in \u003Ccode\u003E_schema.yml\u003C/code\u003E. Schema tests validate your data against expectations (like \u003Ccode\u003Enot_null\u003C/code\u003E and \u003Ccode\u003Eunique\u003C/code\u003E) every time you run \u003Ccode\u003Edbt build\u003C/code\u003E, catching data quality issues before they reach downstream consumers.\u003C/p\u003E\n","\u003Cp\u003ELet's ask CoCo to add them. No skill invocation, no special instructions &mdash; just a direct prompt:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003EAdd schema tests to the existing models in this project.\nSave the results in dbt/models/_schema.yml.\nAt a minimum, each model's primary key should have not_null and unique tests.\nAdd any other tests that make sense given the columns in each model.\nFor parameterized tests like accepted_values, nest all test parameters under an arguments: key.\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003ECoCo will read the model SQL files, identify the primary key columns, and generate \u003Ccode\u003Edbt/models/_schema.yml\u003C/code\u003E with appropriate tests for \u003Ccode\u003Ecustomer_key\u003C/code\u003E in \u003Ccode\u003Ecustomers\u003C/code\u003E and \u003Ccode\u003Eorder_key\u003C/code\u003E in \u003Ccode\u003Eorders_summary\u003C/code\u003E, along with additional column-level tests where they make sense. Review the changes and click on &quot;Keep&quot; to accept/save them. Run \u003Ccode\u003Edbt build\u003C/code\u003E to confirm everything passes:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-bash\"\u003Edbt build --project-dir dbt/\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cblockquote\u003E\n","\u003Cp\u003E\u003Cstrong\u003ENote\u003C/strong\u003E &mdash; If any tests fail, it likely means the source data doesn't meet the expected constraints. Inspect the failure message and adjust the tests accordingly. Not every column that \u003Cem\u003Elooks\u003C/em\u003E like a primary key actually has unique values in the TPC-H dataset.\u003C/p\u003E\n\u003C/blockquote\u003E\n","\u003Ch3\u003EWhat This Demonstrates\u003C/h3\u003E\n","\u003Cp\u003ECoCo just added a complete set of schema tests without being told what the primary keys were, how \u003Ccode\u003E_schema.yml\u003C/code\u003E is structured, or what test types are available in dbt. It already knew all of that.\u003C/p\u003E\n","\u003Cp\u003ENotice, though, that we had to specify the filename \u003Ccode\u003E_schema.yml\u003C/code\u003E explicitly &mdash; without it, CoCo defaults to \u003Ccode\u003Eschema.yml\u003C/code\u003E. Both are valid dbt, but your project uses the underscore prefix by convention. This is a small but telling example of the broader point: \u003Cstrong\u003Ethe model knows the tool, not your team's choices\u003C/strong\u003E. It doesn't know that you always use \u003Ccode\u003Edbt build\u003C/code\u003E rather than \u003Ccode\u003Edbt run\u003C/code\u003E, that primary key tests are required on every new model, or that source references must go through \u003Ccode\u003E_sources.yml\u003C/code\u003E. Those are your team's specific conventions, and without being told, the model will handle them inconsistently from one session to the next. That's exactly what a custom Skill addresses.\u003C/p\u003E\n&lt;!-- ------------------------ --&gt;\n","\u003Ch2\u003ECreate a Custom Skill\u003C/h2\u003E\n","\u003Cp\u003ECoCo's base knowledge is great for standard dbt tasks. But for the conventions that are \u003Cem\u003Especific to this project\u003C/em\u003E &mdash; the ones that need to hold consistently across every new model your team builds &mdash; that's where a custom Skill comes in.\u003C/p\u003E\n","\u003Ch3\u003EWhy We Need a Custom Skill\u003C/h3\u003E\n","\u003Cp\u003ECoCo knew the dbt test syntax, the \u003Ccode\u003E_schema.yml\u003C/code\u003E structure, and the right test types &mdash; all general knowledge. What it doesn't know is the three conventions your team has agreed on for this project: always use \u003Ccode\u003Edbt build\u003C/code\u003E (not \u003Ccode\u003Edbt run\u003C/code\u003E), every primary key must have \u003Ccode\u003Enot_null\u003C/code\u003E and \u003Ccode\u003Eunique\u003C/code\u003E tests, and raw tables must always go through \u003Ccode\u003E_sources.yml\u003C/code\u003E. Those choices aren't right or wrong in any absolute sense &mdash; they're just the standards \u003Cem\u003Eyour team\u003C/em\u003E has decided to follow. A custom Skill is how you encode them so CoCo applies them consistently, without being reminded.\u003C/p\u003E\n","\u003Ch3\u003ECreate the Skill Folder Structure\u003C/h3\u003E\n","\u003Cp\u003ESkills need to live somewhere CoCo can find them. CoCo auto-discovers \u003Cstrong\u003Eproject skills\u003C/strong\u003E from a \u003Ccode\u003E.snowflake/cortex/skills/\u003C/code\u003E folder inside the open workspace &mdash; no registration or install step required. As soon as the folder exists and contains a \u003Ccode\u003ESKILL.md\u003C/code\u003E, the skill is live. Let's create it:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-bash\"\u003Emkdir -p .snowflake/cortex/skills/new-dbt-model\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cblockquote\u003E\n","\u003Cp\u003E\u003Cstrong\u003ENote\u003C/strong\u003E &mdash; The \u003Ccode\u003E.snowflake/cortex/skills/\u003C/code\u003E path is intentional. CoCo scans this folder automatically whenever your workspace is open, which means the skill will be available immediately after you write it &mdash; no further setup needed.\u003C/p\u003E\n\u003C/blockquote\u003E\n","\u003Ch3\u003EWrite the SKILL.md\u003C/h3\u003E\n","\u003Cp\u003ENow let's write the Skill. In the CoCo chat panel, enter:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003ECreate a custom skill at .snowflake/cortex/skills/new-dbt-model/SKILL.md for creating \nnew dbt models in this project.\n\nThe skill should have exactly two sections:\n\n# Conventions &mdash; a numbered list of these three rules:\n1. Always use `dbt build` (not `dbt run`) so tests run together with compilation\n2. Every model's primary key must have not_null and unique tests in _schema.yml\n3. All raw tables must be referenced through _sources.yml using source() &mdash; never reference the source database directly in model SQL\n\n# Workflow &mdash; a numbered list of these four steps:\n1. Confirm which source table(s) to model &mdash; ask if not specified\n2. Write the model SQL using source() references\n3. Add the model entry to _schema.yml with a description and primary key tests\n4. Run dbt build --select &lt;model_name&gt; --project-dir dbt/ and report the result\n\nUse the name new-dbt-model. Write a one-sentence description that tells CoCo when \nto invoke this skill. Keep the skill concise &mdash; no sub-steps, no examples, no error \nhandling instructions. The model is smart enough to infer the details.\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EReview the generated \u003Ccode\u003ESKILL.md\u003C/code\u003E and click on &quot;Keep&quot; to accept/save the changes. It should have a clean YAML frontmatter block with \u003Ccode\u003Ename\u003C/code\u003E and \u003Ccode\u003Edescription\u003C/code\u003E, followed by the four workflow steps and the three conventions. The description should read something like: \u003Cem\u003E&quot;Create a new dbt model in this project. Use when adding a model for a new source table or analytical use case.&quot;\u003C/em\u003E\u003C/p\u003E\n","\u003Cp\u003EIf anything looks off &mdash; a missing convention, a step out of order &mdash; correct it now. Your \u003Ccode\u003ESKILL.md\u003C/code\u003E may be slightly different, and that's OK, but it should look something like this:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-markdown\"\u003E---\nname: new-dbt-model\ndescription: Create a new dbt model in this project. Use when adding a model for a new source table or analytical use case.\n---\n\n# Conventions\n\n1. Always use `dbt build` (not `dbt run`) so tests run together with compilation.\n2. Every model's primary key must have `not_null` and `unique` tests in `_schema.yml`.\n3. Reference all raw tables through `_sources.yml`. Never reference the source database directly in model SQL.\n\n# Workflow\n\n1. Confirm which source table(s) to model &mdash; ask if not specified.\n2. Write the model SQL in `dbt/models/&lt;model_name&gt;.sql` using `{{ source('&lt;source&gt;', '&lt;table&gt;') }}` references.\n3. Add the model entry to `dbt/models/_schema.yml` with a description and tests for the primary key.\n4. Run `dbt build --select &lt;model_name&gt; --project-dir dbt/` and report the result.\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Ch3\u003EInvoke the Skill to Build a New Model\u003C/h3\u003E\n","\u003Cp\u003ENow for the payoff: let's use the skill we just wrote to build the third model in our project. In the CoCo chat panel, enter:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003EUse the new-dbt-model skill to create a supplier_performance model.\nIt should summarize performance metrics per supplier from the supplier and lineitem source tables.\nInclude total orders, total revenue, and average discount.\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EWatch what happens. CoCo auto-discovers the skill from \u003Ccode\u003E.snowflake/cortex/skills/\u003C/code\u003E, matches the prompt against its description, and invokes it automatically. It will follow the workflow steps in order and apply all three conventions &mdash; without you having to repeat any of them:\u003C/p\u003E\n\u003Col\u003E\u003Cli\u003EIdentify the \u003Ccode\u003Esupplier\u003C/code\u003E and \u003Ccode\u003Elineitem\u003C/code\u003E source tables from \u003Ccode\u003E_sources.yml\u003C/code\u003E\u003C/li\u003E\u003Cli\u003EWrite \u003Ccode\u003Edbt/models/supplier_performance.sql\u003C/code\u003E using \u003Ccode\u003E{{ source() }}\u003C/code\u003E references\u003C/li\u003E\u003Cli\u003EAdd the model entry to \u003Ccode\u003E_schema.yml\u003C/code\u003E with primary key tests\u003C/li\u003E\u003Cli\u003ERun \u003Ccode\u003Edbt build --select supplier_performance --project-dir dbt/\u003C/code\u003E and report the result\u003C/li\u003E\u003C/ol\u003E\n","\u003Cp\u003EThat's the difference between a one-off prompt and a Skill. The conventions are encoded once. The team benefits every time. Accept the changes by clicking &quot;Keep&quot; on each new/modified file.\u003C/p\u003E\n\u003Cblockquote\u003E\n","\u003Cp\u003E\u003Cstrong\u003ETip\u003C/strong\u003E &mdash; Resist the urge to put too much into a single Skill. A focused Skill for &quot;create a new dbt model&quot; is more useful than a sprawling one for &quot;do everything dbt-related.&quot; Smaller, well-named Skills are easier to maintain and easier for CoCo to invoke correctly.\u003C/p\u003E\n\u003C/blockquote\u003E\n&lt;!-- ------------------------ --&gt;\n","\u003Ch2\u003EWhat is a Plugin?\u003C/h2\u003E\n","\u003Cp\u003EWe now have a working custom Skill. Let's talk about Plugins before we build one &mdash; because understanding \u003Cem\u003Ewhy\u003C/em\u003E Plugins exist makes it much easier to understand what we're about to put together.\u003C/p\u003E\n","\u003Ch3\u003ESkills Alone Have Limitations\u003C/h3\u003E\n","\u003Cp\u003EThe project skill you just built works great &mdash; for you, in this workspace. But what if you want to use this skill in a different project/repository? You'd have to create a copy of it in the other project, and then you'd have multiple copies to maintain. And there are other important extensibility features for AI coding agents besides skills. For example, what if you want to add a production safety hook alongside it? Or a subagent for PR review? Now you're managing three separate things, none of them versioned together or installable as a unit. And what if your hook or subagent needs to be shared across multiple repositories, not just this one?\u003C/p\u003E\n","\u003Cp\u003EThat's where Plugins come in. A Plugin is a single installable unit that bundles everything together &mdash; skills, hooks, subagents, and MCP servers &mdash; with a version number, a formal validation step, and a one-command install. Plugins were designed to be the right packaging unit for distributing agent capabilities, both within a team and across an organization.\u003C/p\u003E\n","\u003Cp\u003EHere's a short list of why a Plugin is a better packaging unit than a raw Skill folder:\u003C/p\u003E\n\u003Cul\u003E\u003Cli\u003E\u003Cstrong\u003EVersioned\u003C/strong\u003E &mdash; the manifest has a \u003Ccode\u003Eversion\u003C/code\u003E field; raw Skill folders don't\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003EValidatable\u003C/strong\u003E &mdash; the manifest is formally parsed and checked when you install; no equivalent check exists for raw Skill folders\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003ESingle installable unit\u003C/strong\u003E &mdash; one Add Local Plugin action in the Agent Settings panel registers everything; individual Skills require separate registration per Skill\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003EUpdatable\u003C/strong\u003E &mdash; GitHub-sourced plugins have a Sync button that pulls the latest version; Skills have no equivalent lifecycle\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003EBundling\u003C/strong\u003E &mdash; one Plugin can carry Skills, hooks, subagents, and MCP servers as a coherent capability\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003ERegistry tracking\u003C/strong\u003E &mdash; installed Plugins are recorded with source, install time, and active state; you always know exactly what's deployed\u003C/li\u003E\u003C/ul\u003E\n","\u003Ch3\u003EPlugin Folder Structure\u003C/h3\u003E\n","\u003Cp\u003EA Plugin is a self-contained directory with a manifest file at a well-known path:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003Emy-plugin/\n├── .cortex-plugin/\n│   ├── plugin.json       # Manifest (required)\n│   └── activation.md     # Optional &mdash; displayed when the plugin is activated\n├── skills/               # Auto-discovered if present\n│   └── my-skill/\n│       └── SKILL.md\n├── agents/               # Auto-discovered if present\n│   └── my-agent.md\n└── hooks/\n    └── hooks.json        # Lifecycle hooks\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cblockquote\u003E\n","\u003Cp\u003E\u003Cstrong\u003ENote\u003C/strong\u003E &mdash; CoCo uses the \u003Ccode\u003E.cortex-plugin/\u003C/code\u003E directory name. If you use \u003Ccode\u003E.claude-plugin/\u003C/code\u003E, that works too for Claude-compatible tooling, but \u003Ccode\u003E.cortex-plugin/\u003C/code\u003E is the standard for CoCo.\u003C/p\u003E\n\u003C/blockquote\u003E\n","\u003Ch3\u003EThe plugin.json Manifest\u003C/h3\u003E\n","\u003Cp\u003EThe \u003Ccode\u003Eplugin.json\u003C/code\u003E file is the heart of the Plugin. It declares everything the Plugin contains, who made it, and how it behaves. Here's a minimal example:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-json\"\u003E{\n  &quot;name&quot;: &quot;my-plugin&quot;,\n  &quot;description&quot;: &quot;What this plugin does&quot;,\n  &quot;version&quot;: &quot;1.0.0&quot;,\n  &quot;author&quot;: { &quot;name&quot;: &quot;Your Team&quot; },\n  &quot;skills&quot;: [&quot;./skills&quot;],\n  &quot;agents&quot;: [&quot;./agents&quot;],\n  &quot;hooks&quot;: &quot;./hooks/hooks.json&quot;\n}\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Ch3\u003EPlugin Elements\u003C/h3\u003E\n","\u003Cp\u003ELet's briefly cover each element a Plugin can contain:\u003C/p\u003E\n","\u003Cp\u003E\u003Cstrong\u003ESkills\u003C/strong\u003E &mdash; the Skill folders we already know about, now bundled and versioned together. Pointed to via the \u003Ccode\u003E&quot;skills&quot;\u003C/code\u003E array in the manifest.\u003C/p\u003E\n","\u003Cp\u003E\u003Cstrong\u003EAgents (Subagents)\u003C/strong\u003E &mdash; Markdown files that define autonomous, specialized agents. Like Skills, they have YAML frontmatter with \u003Ccode\u003Ename\u003C/code\u003E, \u003Ccode\u003Edescription\u003C/code\u003E, and optionally \u003Ccode\u003Etools\u003C/code\u003E and \u003Ccode\u003Emodel\u003C/code\u003E. The body contains instructions the agent follows when invoked. The key difference from a Skill: a subagent is designed to run autonomously to completion on a specific task, whereas a Skill guides an interactive session.\u003C/p\u003E\n","\u003Cp\u003E\u003Cstrong\u003EHooks\u003C/strong\u003E &mdash; shell commands that run on lifecycle events. The most useful for data engineers is \u003Ccode\u003EPreToolUse\u003C/code\u003E, which fires before CoCo executes a tool (like running a Bash command). This is how you add guardrails &mdash; for example, blocking direct production deployments. Hooks are defined in a \u003Ccode\u003Ehooks.json\u003C/code\u003E file and reference shell scripts.\u003C/p\u003E\n","\u003Cp\u003E\u003Cstrong\u003EMCP Servers\u003C/strong\u003E &mdash; Model Context Protocol servers that expose external tools to the agent. For example, you could wire up a connection to your internal issue tracker or GitHub so CoCo can pull context from outside the codebase. We won't cover MCP Servers in depth in this Guide, but you can find full details in the \u003Ca href=\"https://docs.snowflake.com/en/user-guide/cortex-code/extensibility#model-context-protocol-mcp\"\u003ECoCo documentation\u003C/a\u003E.\u003C/p\u003E\n","\u003Cp\u003E\u003Cstrong\u003Eactivation.md\u003C/strong\u003E &mdash; an optional Markdown file displayed to the user when the Plugin is activated. Use it to explain what the Plugin does and how to enable it.\u003C/p\u003E\n&lt;!-- ------------------------ --&gt;\n","\u003Ch2\u003ECreate a Custom Plugin\u003C/h2\u003E\n","\u003Cp\u003EWe have all the pieces &mdash; a custom Skill, a clear understanding of what Plugins are, and a project that's ready to be hardened. Now let's bundle everything into a proper Plugin. The first thing we'll do is migrate the skill from its project-local home into the plugin folder, then add a production safety hook and a dbt review subagent alongside it.\u003C/p\u003E\n","\u003Ch3\u003EMove the Skill into the Plugin\u003C/h3\u003E\n","\u003Cp\u003EThe skill currently lives at \u003Ccode\u003E.snowflake/cortex/skills/new-dbt-model/\u003C/code\u003E &mdash; scoped to this workspace. We're going to move it into \u003Ccode\u003E.cortex/plugins/coco-de-guide/\u003C/code\u003E &mdash; the project-scoped plugin directory that CoCo auto-discovers. Run these commands in the terminal:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-bash\"\u003Emkdir -p .cortex/plugins/coco-de-guide/skills\nmv .snowflake/cortex/skills/new-dbt-model .cortex/plugins/coco-de-guide/skills/\nrm -rf .snowflake/\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EThe skill is now in \u003Ccode\u003E.cortex/plugins/coco-de-guide/skills/new-dbt-model/SKILL.md\u003C/code\u003E. CoCo auto-discovers plugins in \u003Ccode\u003E.cortex/plugins/\u003C/code\u003E, so once the manifest is in place, the plugin will be live &mdash; no separate install step needed.\u003C/p\u003E\n","\u003Ch3\u003ECreate the Plugin Manifest\u003C/h3\u003E\n","\u003Cp\u003ELet's create the \u003Ccode\u003E.cortex-plugin/\u003C/code\u003E directory and write the manifest. In the CoCo chat panel, enter:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003EConsult the CoCo Desktop plugin\ndocumentation at https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code-desktop/plugins\nfor the correct plugin.json schema and file structure.\n\nCreate a CoCo plugin manifest for this project at .cortex/plugins/coco-de-guide/.cortex-plugin/plugin.json.\n\nThe manifest must include all of the following fields:\n- name: &quot;coco-de-guide&quot;\n- version: 1.0.0\n- author: me\n- skills: pointing to ./skills\n- agents: pointing to ./agents\n- hooks: pointing to ./hooks/hooks.json\n\nAlso create .cortex/plugins/coco-de-guide/.cortex-plugin/activation.md that briefly explains\nwhat the plugin includes.\n\nDo not use the cortex CLI &mdash; write the files directly.\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cblockquote\u003E\n","\u003Cp\u003E\u003Cstrong\u003ENote\u003C/strong\u003E &mdash; CoCo has bundled skills that know about the \u003Ccode\u003Ecortex\u003C/code\u003E CLI's plugin commands (\u003Ccode\u003Ecortex plugin install\u003C/code\u003E, \u003Ccode\u003Ecortex plugin validate\u003C/code\u003E, etc.). Those skills can activate here and cause CoCo to attempt CLI operations instead of just writing files. The \u003Ccode\u003EAGENTS.md\u003C/code\u003E instruction to not use the \u003Ccode\u003Ecortex\u003C/code\u003E CLI should prevent this, but if CoCo does try to run CLI commands, remind it: \u003Cem\u003E&quot;Do not use the cortex CLI &mdash; write the files directly.&quot;\u003C/em\u003E\u003C/p\u003E\n\u003C/blockquote\u003E\n","\u003Cp\u003ECoCo will create both \u003Ccode\u003Eplugin.json\u003C/code\u003E and \u003Ccode\u003Eactivation.md\u003C/code\u003E. Accept the changes by clicking &quot;Keep&quot; on each new/modified file. Your \u003Ccode\u003Eplugin.json\u003C/code\u003E manifest may be slightly different, and that's OK, but it should look something like this:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-json\"\u003E{\n  &quot;name&quot;: &quot;coco-de-guide&quot;,\n  &quot;description&quot;: &quot;dbt/Snowflake data engineering plugin for the CoCo DE Guide&quot;,\n  &quot;version&quot;: &quot;1.0.0&quot;,\n  &quot;author&quot;: { &quot;name&quot;: &quot;&lt;YOUR_NAME&gt;&quot; },\n  &quot;skills&quot;: [&quot;./skills&quot;],\n  &quot;agents&quot;: [&quot;./agents&quot;],\n  &quot;hooks&quot;: &quot;./hooks/hooks.json&quot;\n}\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Ch3\u003EAdd a Production Safety Hook\u003C/h3\u003E\n","\u003Cp\u003EOne of the most valuable things a Plugin can do is protect your environment from mistakes. A common problem with AI coding agents is that they'll happily run whatever command you ask &mdash; including commands that write directly to production. We can prevent that with a \u003Ccode\u003EPreToolUse\u003C/code\u003E hook.\u003C/p\u003E\n","\u003Cp\u003ELet's add a hook that blocks any \u003Ccode\u003Edbt\u003C/code\u003E command that targets production:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003EConsult the CoCo Desktop hooks documentation at\nhttps://docs.snowflake.com/en/user-guide/cortex-code/cortex-code-desktop/hooks\nfor the correct hooks.json schema and shell script format.\n\nCreate a PreToolUse hook at .cortex/plugins/coco-de-guide/hooks/validate-bash.sh that blocks\nany dbt command that includes --target prod. If the command is blocked, return a clear error\nmessage explaining that direct production dbt runs are not allowed and to use the CI/CD\npipeline instead.\nAlso create .cortex/plugins/coco-de-guide/hooks/hooks.json that wires this script to the\nPreToolUse event using the matcher value &quot;bash&quot; (lowercase).\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003ECoCo will create both files. The shell script reads the tool input from stdin (as JSON), extracts the command, and checks it against the pattern. The \u003Ccode\u003Ehooks.json\u003C/code\u003E wires it up. Accept the changes by clicking the 'Keep' button. Your \u003Ccode\u003Ehooks.json\u003C/code\u003E may be slightly different, and that's OK, but it should look something like this:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-json\"\u003E{\n  &quot;hooks&quot;: {\n    &quot;PreToolUse&quot;: [\n      {\n        &quot;matcher&quot;: &quot;bash&quot;,\n        &quot;hooks&quot;: [\n          {\n            &quot;type&quot;: &quot;command&quot;,\n            &quot;command&quot;: &quot;bash .cortex/plugins/coco-de-guide/hooks/validate-bash.sh&quot;,\n            &quot;timeout&quot;: 10\n          }\n        ]\n      }\n    ]\n  }\n}\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EWe'll test the hook in the next step.\u003C/p\u003E\n","\u003Ch3\u003EAdd a dbt Review Subagent\u003C/h3\u003E\n","\u003Cp\u003EThe final piece of our Plugin is a subagent for reviewing dbt model changes. Unlike a Skill &mdash; which guides an interactive session &mdash; this subagent is designed to run autonomously to completion. We'll use it both locally (before opening a PR) and in CI/CD (on every PR automatically). That &quot;same agent, two contexts&quot; pattern is one of the most powerful things you can build with CoCo.\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003EConsult the CoCo Desktop agents documentation at\nhttps://docs.snowflake.com/en/user-guide/cortex-code/cortex-code-desktop/agents\nfor the correct agent definition format and frontmatter schema.\n\nCreate a dbt-review subagent at .cortex/plugins/coco-de-guide/agents/dbt-review.md.\nThe subagent should:\n- Find all changed dbt model files compared to origin/main\n- For each changed model, run dbt build --select &lt;model&gt; --project-dir dbt/\n- Verify that each convention from the new-dbt-model skill is met\n- Produce a concise PASS/FAIL report per convention with specific remediation steps for any failures\n\nIt should use the bash, read, grep, and glob tools. Set the model to auto.\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EReview the generated \u003Ccode\u003Edbt-review.md\u003C/code\u003E and click on &quot;Keep&quot; to accept/save the changes. It should have YAML frontmatter with \u003Ccode\u003Ename\u003C/code\u003E, \u003Ccode\u003Edescription\u003C/code\u003E, \u003Ccode\u003Etools\u003C/code\u003E, and \u003Ccode\u003Emodel\u003C/code\u003E fields, followed by the review steps and output format.\u003C/p\u003E\n","\u003Ch3\u003EActivate the Plugin\u003C/h3\u003E\n","\u003Cp\u003EBecause the plugin lives in \u003Ccode\u003E.cortex/plugins/coco-de-guide/\u003C/code\u003E, CoCo Desktop will discover it automatically when the workspace is opened. To verify it is active:\u003C/p\u003E\n\u003Col\u003E\u003Cli\u003EClick the \u003Cstrong\u003ESettings\u003C/strong\u003E tab (gear icon) in the bottom of the left sidebar\u003C/li\u003E\u003Cli\u003EOpen the \u003Cstrong\u003EPlugins\u003C/strong\u003E section\u003C/li\u003E\u003Cli\u003ELook for \u003Ccode\u003Ecoco-de-guide\u003C/code\u003E in the Plugins grid\u003C/li\u003E\u003C/ol\u003E\n","\u003Cp\u003EIf the plugin appears but is toggled off, click the toggle to enable it. If it doesn't appear at all, click the \u003Cstrong\u003E↻\u003C/strong\u003E (refresh) button in the Plugins toolbar to force a reload of the plugin registry.\u003C/p\u003E\n","\u003Cp\u003E\u003Cimg src=\"https://www.snowflake.com/content/dam/snowflake-site/developers/guides/data-engineering-with-coco/coco_desktop_plugin_summary.png\" alt=\"CoCo Plugin Summary\"\u003E\u003C/p\u003E\n\u003Cblockquote\u003E\n","\u003Cp\u003E\u003Cstrong\u003ENote\u003C/strong\u003E &mdash; Project-scoped plugins require workspace trust before they auto-activate. If your workspace is not trusted, the plugin will appear in the Plugins panel but will be disabled. Enable it individually via the toggle, or trust the workspace to activate all project plugins automatically.\u003C/p\u003E\n\u003C/blockquote\u003E\n","\u003Cp\u003EClick the plugin card to open its detail view and verify that all three components &mdash; the skill, the hook, and the subagent &mdash; are listed.\u003C/p\u003E\n","\u003Cp\u003E\u003Cimg src=\"https://www.snowflake.com/content/dam/snowflake-site/developers/guides/data-engineering-with-coco/coco_desktop_plugin_detail.png\" alt=\"CoCo Plugin Detail\"\u003E\u003C/p\u003E\n\u003Cblockquote\u003E\n","\u003Cp\u003E\u003Cstrong\u003ETip\u003C/strong\u003E &mdash; File watchers detect changes to plugin files automatically, so edits to \u003Ccode\u003Eplugin.json\u003C/code\u003E, \u003Ccode\u003ESKILL.md\u003C/code\u003E, the hook script, or the subagent take effect immediately. Use the \u003Cstrong\u003E↻\u003C/strong\u003E button only if a change isn't appearing after a bulk file operation.\u003C/p\u003E\n\u003C/blockquote\u003E\n","\u003Ch3\u003ETest the Hook\u003C/h3\u003E\n","\u003Cp\u003ENow that the plugin is active, the hook is live. Try to get CoCo to run a production deployment by entering this prompt in the chat panel (not in the terminal):\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003ERun dbt build --target prod --project-dir dbt/\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EYou should see the hook fire and block the command with a clear explanation before CoCo can execute it. This is a small but important example of the broader principle: \u003Cstrong\u003Eagents should not make changes directly in production\u003C/strong\u003E. Even with clear instructions, agents generate content dynamically &mdash; and that non-determinism is not something you want in a production pipeline. Hooks give you hard guardrails that enforce that boundary regardless of what the agent decides.\u003C/p\u003E\n","\u003Ch3\u003ETry the Subagent Locally\u003C/h3\u003E\n","\u003Cp\u003EBefore wiring this subagent into CI/CD, try it from the chat panel first. Type:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003EUse the dbt-review agent to review the changes in this branch.\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EThe subagent will run to completion autonomously &mdash; finding changed model files, running \u003Ccode\u003Edbt build\u003C/code\u003E for each, checking conventions, and producing a PASS/FAIL report. If you've made any changes that violate the \u003Ccode\u003Enew-dbt-model\u003C/code\u003E skill conventions, you'll see specific remediation steps in the output.\u003C/p\u003E\n&lt;!-- ------------------------ --&gt;\n","\u003Ch2\u003EPublish to the Plugin Catalog\u003C/h2\u003E\n","\u003Cp\u003ESo far, your plugin lives at \u003Ccode\u003E.cortex/plugins/coco-de-guide/\u003C/code\u003E inside this repository. Teammates can install it by cloning the repo or using \u003Cstrong\u003EAdd from GitHub\u003C/strong\u003E in CoCo Desktop. That works &mdash; but Snowflake has a better option for teams that want centralized discovery and access control: the \u003Cstrong\u003EPlugins Catalog\u003C/strong\u003E.\u003C/p\u003E\n","\u003Ch3\u003EWhat is the Plugins Catalog?\u003C/h3\u003E\n","\u003Cp\u003EThe Plugins Catalog is Snowflake's built-in registry for sharing and discovering plugins across your organization. Publishing to it gives you:\u003C/p\u003E\n\u003Cul\u003E\u003Cli\u003E\u003Cstrong\u003EGovernance\u003C/strong\u003E &mdash; access is controlled by Snowflake roles and grants, not Git permissions\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003EDiscoverability\u003C/strong\u003E &mdash; teammates can browse and search for plugins from CoCo Desktop\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003ENo credentials required\u003C/strong\u003E &mdash; consumers install directly from Snowflake, no GitHub access needed\u003C/li\u003E\u003Cli\u003E\u003Cstrong\u003EVersioning\u003C/strong\u003E &mdash; each publish creates a new version; consumers sync to get the latest\u003C/li\u003E\u003C/ul\u003E\n","\u003Ch3\u003EWhere the Plugin Lives in Snowflake\u003C/h3\u003E\n","\u003Cp\u003EWhen you publish a plugin, CoCo creates a \u003Ccode\u003ECORTEX EXTENSION\u003C/code\u003E object in your Snowflake account. A Cortex Extension is a schema-level object (\u003Ccode\u003ETYPE = PLUGIN\u003C/code\u003E) that stores your plugin's files as a live, versioned stage and holds the \u003Ccode\u003EREAD\u003C/code\u003E grants that control who can use it.\u003C/p\u003E\n","\u003Cp\u003EThe naming follows a convention: the plugin's \u003Ccode\u003Ename\u003C/code\u003E field is uppercased and hyphens are replaced with underscores. The object is created in a \u003Ccode\u003ESKILL_SHARING\u003C/code\u003E schema inside your personal database:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003EUSER$&lt;YOUR_USERNAME&gt;.SKILL_SHARING.COCO_DE_GUIDE\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EOnce published, the plugin has a \u003Cstrong\u003Eshare URI\u003C/strong\u003E &mdash; a \u003Ccode\u003Esnow://\u003C/code\u003E link that uniquely identifies this version:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003Esnow://skill_catalog/USER$&lt;YOUR_USERNAME&gt;.SKILL_SHARING.COCO_DE_GUIDE/versions/version$1/\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EThis is what you share with your team. It's stable, access-controlled, and works regardless of whether the recipient has access to your Git repository.\u003C/p\u003E\n","\u003Ch3\u003EPublish from CoCo Desktop\u003C/h3\u003E\n\u003Col\u003E\u003Cli\u003EClick the \u003Cstrong\u003ESettings\u003C/strong\u003E tab (gear icon) in the bottom of the left sidebar\u003C/li\u003E\u003Cli\u003EOpen the \u003Cstrong\u003EPlugins\u003C/strong\u003E section\u003C/li\u003E\u003Cli\u003EClick the \u003Ccode\u003Ecoco-de-guide\u003C/code\u003E plugin card to open its detail view\u003C/li\u003E\u003Cli\u003EClick the \u003Cstrong\u003EPublish to Plugins Catalog\u003C/strong\u003E button (cloud-upload icon)\u003C/li\u003E\u003C/ol\u003E\n","\u003Cp\u003EA chat session opens and the \u003Ccode\u003Eshare-skill-and-plugin\u003C/code\u003E skill runs automatically. It will:\u003C/p\u003E\n\u003Col\u003E\u003Cli\u003EPrompt you to confirm the plugin name and description\u003C/li\u003E\u003Cli\u003ECreate the \u003Ccode\u003ESKILL_SHARING\u003C/code\u003E schema in your personal database (if it doesn't exist) and grant \u003Ccode\u003EUSAGE\u003C/code\u003E to \u003Ccode\u003EPUBLIC\u003C/code\u003E\u003C/li\u003E\u003Cli\u003ECreate the \u003Ccode\u003ECOCO_DE_GUIDE\u003C/code\u003E Cortex Extension object\u003C/li\u003E\u003Cli\u003EUpload all plugin files to the extension's versioned stage\u003C/li\u003E\u003Cli\u003ECommit the version and apply your chosen access settings\u003C/li\u003E\u003C/ol\u003E\n","\u003Cp\u003EAt the end, CoCo reports the share URI:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003Esnow://skill_catalog/USER$&lt;YOUR_USERNAME&gt;.SKILL_SHARING.COCO_DE_GUIDE/versions/version$1/\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cblockquote\u003E\n","\u003Cp\u003E\u003Cstrong\u003ENote\u003C/strong\u003E &mdash; By default the plugin is not discoverable in the catalog browser &mdash; it's reachable only by anyone you share the URI with. You can change this during the publish flow if you want the plugin to be visible to everyone in your organization.\u003C/p\u003E\n\u003C/blockquote\u003E\n","\u003Ch3\u003EInstalling a Catalog Plugin\u003C/h3\u003E\n","\u003Cp\u003EThis Guide doesn't walk through the consumer-side flow, but here's how a teammate would install your published plugin:\u003C/p\u003E\n\u003Col\u003E\u003Cli\u003EClick the \u003Cstrong\u003ESettings\u003C/strong\u003E tab (gear icon) in the bottom of the left sidebar\u003C/li\u003E\u003Cli\u003EOpen the \u003Cstrong\u003EPlugins\u003C/strong\u003E section\u003C/li\u003E\u003Cli\u003EClick \u003Cstrong\u003E+\u003C/strong\u003E and choose \u003Cstrong\u003EAdd from Plugins Catalog\u003C/strong\u003E\u003C/li\u003E\u003Cli\u003EPaste the \u003Ccode\u003Esnow://skill_catalog/...\u003C/code\u003E URI and click \u003Cstrong\u003EImport\u003C/strong\u003E\u003C/li\u003E\u003C/ol\u003E\n","\u003Cp\u003ECoCo downloads the plugin files from Snowflake, validates the manifest, and registers it. The plugin appears in the grid with a \u003Cstrong\u003ECATALOG\u003C/strong\u003E badge. They can sync to newer versions at any time from the plugin's detail view.\u003C/p\u003E\n&lt;!-- ------------------------ --&gt;\n","\u003Ch2\u003EEnforce Standards Automatically in CI/CD\u003C/h2\u003E\n","\u003Cp\u003EEverything we've built so far &mdash; the \u003Ccode\u003EAGENTS.md\u003C/code\u003E, the Skill, the Plugin, the hook, the subagent &mdash; was designed with this moment in mind. We're going to take the exact same dbt-review subagent we've been running locally and wire it into a GitHub Actions workflow so it runs automatically on every pull request that touches a dbt model. Same agent. Same conventions. Now running in CI.\u003C/p\u003E\n","\u003Cp\u003EThis is the payoff of building a Plugin instead of a loose collection of Skill files. But there's one important note about what's different here: while this Guide uses \u003Cstrong\u003ECoCo Desktop\u003C/strong\u003E for the interactive development sections, the CI/CD pipeline uses the \u003Cstrong\u003ECoCo CLI\u003C/strong\u003E &mdash; the terminal-native form of the same agent. The CLI is the right tool for automation: it runs headlessly, connects via a credentials file, and is installable in any CI environment. The plugin you built in \u003Ccode\u003E.cortex/plugins/\u003C/code\u003E is auto-discovered by the CLI just as it is by Desktop &mdash; no separate install step needed.\u003C/p\u003E\n","\u003Ch3\u003EConfigure GitHub Secrets\u003C/h3\u003E\n","\u003Cp\u003EFrom your forked repository on GitHub, click \u003Cstrong\u003ESettings &rarr; Secrets and variables &rarr; Actions\u003C/strong\u003E. Add the following repository secrets:\u003C/p\u003E\n\u003Ctable\u003E\u003Cthead\u003E\u003Ctr\u003E\u003Cth colspan=\"1\" rowspan=\"1\"\u003ESecret name\u003C/th\u003E\u003Cth colspan=\"1\" rowspan=\"1\"\u003EValue\u003C/th\u003E\u003C/tr\u003E\u003C/thead\u003E\u003Ctbody\u003E\u003Ctr\u003E\u003Ctd colspan=\"1\" rowspan=\"1\"\u003E\u003Ccode\u003ESNOWFLAKE_ACCOUNT\u003C/code\u003E\u003C/td\u003E\u003Ctd colspan=\"1\" rowspan=\"1\"\u003EYour Snowflake account identifier\u003C/td\u003E\u003C/tr\u003E\u003Ctr\u003E\u003Ctd colspan=\"1\" rowspan=\"1\"\u003E\u003Ccode\u003ESNOWFLAKE_USER\u003C/code\u003E\u003C/td\u003E\u003Ctd colspan=\"1\" rowspan=\"1\"\u003EYour Snowflake username\u003C/td\u003E\u003C/tr\u003E\u003Ctr\u003E\u003Ctd colspan=\"1\" rowspan=\"1\"\u003E\u003Ccode\u003ESNOWFLAKE_PASSWORD\u003C/code\u003E\u003C/td\u003E\u003Ctd colspan=\"1\" rowspan=\"1\"\u003EYour Snowflake PAT\u003C/td\u003E\u003C/tr\u003E\u003C/tbody\u003E\u003C/table\u003E\n","\u003Ch3\u003ECreate the GitHub Actions Workflow\u003C/h3\u003E\n","\u003Cp\u003ELet's have CoCo write the workflow file. In the CoCo chat panel, enter:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003ECreate a GitHub Actions workflow at .github/workflows/pr-review.yml.\nTrigger on pull requests that touch dbt/models/** and also allow manual dispatch.\nGrant permissions: contents read and pull-requests write.\n\nFor the CoCo steps:\n- Configure a Snowflake connection by writing ~/.snowflake/connections.toml with a\n  [default] profile using keys account, user, and password sourced from the\n  SNOWFLAKE_ACCOUNT, SNOWFLAKE_USER, and SNOWFLAKE_PASSWORD secrets. Set file\n  permissions to 600.\n- Install the CoCo CLI:\n    curl -LsS https://ai.snowflake.com/static/cc-scripts/install.sh | sh\n  and add $HOME/.local/bin to PATH. No plugin install step is needed &mdash; the plugin\n  in .cortex/plugins/ is auto-discovered.\n- Run the dbt-review agent:\n    cortex --print &quot;Use the dbt-review agent to review the changes in this PR&quot; \\\n      &gt; review.md 2&gt;/dev/null || true\n\nPost the contents of review.md as a comment on the pull request.\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EReview the generated workflow and click &quot;Keep&quot; to accept/save the changes. Your workflow may be slightly different, and that's OK, but it should look something like this:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\"language-yaml\"\u003Ename: dbt-review Agent PR Review\n\non:\n  pull_request:\n    paths:\n      - 'dbt/models/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\n\npermissions:\n  contents: read\n  pull-requests: write\n\njobs:\n  review:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v7\n        with:\n          fetch-depth: 0   # need base branch to diff changed files\n\n      - name: Configure Snowflake connection for Cortex Code\n        run: |\n          mkdir -p ~/.snowflake\n          cat &gt; ~/.snowflake/connections.toml &lt;&lt;EOF\n          [default]\n          account = &quot;${{ secrets.SNOWFLAKE_ACCOUNT }}&quot;\n          user = &quot;${{ secrets.SNOWFLAKE_USER }}&quot;\n          password = &quot;${{ secrets.SNOWFLAKE_PASSWORD }}&quot;\n          EOF\n          chmod 600 ~/.snowflake/connections.toml\n\n      - name: Install Cortex Code CLI\n        run: |\n          curl -LsS https://ai.snowflake.com/static/cc-scripts/install.sh | sh\n          echo &quot;$HOME/.local/bin&quot; &gt;&gt; &quot;$GITHUB_PATH&quot;\n\n      - name: Run Cortex Code and the dbt-review agent\n        run: |\n          cortex --print &quot;Use the dbt-review agent to review the changes in this PR&quot; \\\n            &gt; review.md 2&gt;/dev/null || true\n          echo &quot;----- review.md -----&quot;; cat review.md\n\n      - name: Post review as PR comment\n        uses: actions/github-script@v9\n        with:\n          script: |\n            const fs = require('fs');\n            let body = '## dbt-review Agent (Cortex Code)\\n\\n';\n            try { body += fs.readFileSync('review.md', 'utf8'); }\n            catch (e) { body += '_No review output produced._'; }\n            const issue_number = context.payload.pull_request?.number ?? context.issue.number;\n            if (!issue_number) {\n              console.log('No PR number found (workflow_dispatch run). Skipping comment.');\n              console.log(body);\n              return;\n            }\n            await github.rest.issues.createComment({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              issue_number,\n              body,\n            });\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EA few things worth noting. \u003Ccode\u003Efetch-depth: 0\u003C/code\u003E is essential &mdash; the dbt-review agent uses \u003Ccode\u003Egit diff origin/main...HEAD\u003C/code\u003E to find changed files, which requires full history. The Snowflake connection is configured as a \u003Ccode\u003Econnections.toml\u003C/code\u003E file rather than environment variables &mdash; this is how the CoCo CLI picks up credentials. The plugin in \u003Ccode\u003E.cortex/plugins/\u003C/code\u003E is auto-discovered by the CLI the same way it is by Desktop, so no install step is needed. And the intelligence lives entirely in the subagent definition, not in this workflow &mdash; the workflow is just infrastructure.\u003C/p\u003E\n","\u003Ch3\u003EEnable GitHub Actions\u003C/h3\u003E\n","\u003Cp\u003EBy default, GitHub Actions workflows are disabled in forked repositories. Enable them by going to the \u003Cstrong\u003EActions\u003C/strong\u003E tab in your forked repository and clicking \u003Cstrong\u003EI understand my workflows, go ahead and enable them\u003C/strong\u003E.\u003C/p\u003E\n","\u003Cp\u003E\u003Cimg src=\"https://www.snowflake.com/content/dam/snowflake-site/developers/guides/data-engineering-with-coco/github_actions_activate.png\" alt=\"Activate GitHub Actions\"\u003E\u003C/p\u003E\n","\u003Ch3\u003ETest the Workflow\u003C/h3\u003E\n","\u003Cp\u003ECommit all the files you've created in this Guide to a new feature branch and push to GitHub using CoCo Desktop's built-in Source Control panel.\u003C/p\u003E\n","\u003Cp\u003E\u003Cstrong\u003ECreate a new branch\u003C/strong\u003E\u003C/p\u003E\n","\u003Cp\u003EClick the branch name in the bottom status bar (it will show \u003Ccode\u003Emain\u003C/code\u003E or whatever branch you're on). Select \u003Cstrong\u003ECreate new branch...\u003C/strong\u003E and enter \u003Ccode\u003Efeature/add-coco-plugin\u003C/code\u003E.\u003C/p\u003E\n","\u003Cp\u003E\u003Cstrong\u003EStage and commit your changes\u003C/strong\u003E\u003C/p\u003E\n","\u003Cp\u003EOpen the Source Control panel by clicking the Source Control icon in the Activity Bar on the left, or press \u003Ccode\u003ECmd+Shift+G\u003C/code\u003E (macOS) / \u003Ccode\u003ECtrl+Shift+G\u003C/code\u003E (Windows/Linux). You'll see all the files you've created listed under \u003Cstrong\u003EChanges\u003C/strong\u003E.\u003C/p\u003E\n","\u003Cp\u003EClick the \u003Cstrong\u003E+\u003C/strong\u003E icon next to \u003Cstrong\u003EChanges\u003C/strong\u003E to stage everything, then type a commit message in the input box at the top of the panel:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003EAdd AGENTS.md, custom skill, plugin, and CI workflow\n\u003C/code\u003E\u003C/pre\u003E\n","\u003Cp\u003EClick the \u003Cstrong\u003ECommit\u003C/strong\u003E button, or press \u003Ccode\u003ECmd+Enter\u003C/code\u003E / \u003Ccode\u003ECtrl+Enter\u003C/code\u003E.\u003C/p\u003E\n","\u003Cp\u003E\u003Cstrong\u003EPush and open a pull request\u003C/strong\u003E\u003C/p\u003E\n","\u003Cp\u003EClick \u003Cstrong\u003EPublish Branch\u003C/strong\u003E in the Source Control panel (or the sync icon in the status bar) to push \u003Ccode\u003Efeature/add-coco-plugin\u003C/code\u003E to your fork on GitHub.\u003C/p\u003E\n","\u003Cp\u003EThen switch to GitHub in your browser and open a pull request from \u003Ccode\u003Efeature/add-coco-plugin\u003C/code\u003E to \u003Ccode\u003Emain\u003C/code\u003E in your forked repository. When creating the pull request, make sure the base repository is \u003Cem\u003Eyour fork\u003C/em\u003E, not the upstream Snowflake-Labs repository. GitHub defaults to comparing against the upstream, which you'll need to change.\u003C/p\u003E\n","\u003Cp\u003ENavigate to the \u003Cstrong\u003EActions\u003C/strong\u003E tab to watch the workflow run. Once it completes, you'll see the dbt-review agent's PASS/FAIL report as output in the workflow logs. You will also see the agent's output in the PR itself as a comment.\u003C/p\u003E\n&lt;!-- ------------------------ --&gt;\n","\u003Ch2\u003EConclusion And Resources\u003C/h2\u003E\n","\u003Cp\u003ECongratulations! You've built a complete, professional-grade data engineering workflow with Cortex Code. Let's take a moment to look back at what you actually built &mdash; and more importantly, \u003Cem\u003Ewhy\u003C/em\u003E each piece matters.\u003C/p\u003E\n","\u003Cp\u003EYou started with an empty project and an AI coding agent. The first thing you did wasn't write a prompt &mdash; it was write an \u003Ccode\u003EAGENTS.md\u003C/code\u003E. That single file changed the quality of every subsequent interaction. From there, you used the agent to add test coverage to existing models, then created a custom Skill that encoded your team's specific conventions. You immediately proved that Skill worked by using it to build a new model. Then you packaged that Skill &mdash; along with a production safety hook and a dbt review subagent &mdash; into a Plugin: a versioned, validatable, single-installable unit that can be shared across your entire team. And finally, you took that same subagent and wired it into GitHub Actions, so code review by your AI agent now happens automatically on every pull request.\u003C/p\u003E\n","\u003Cp\u003EThat last part is the real payoff. The \u003Ccode\u003Edbt-review\u003C/code\u003E subagent didn't get smarter when you moved it to CI/CD &mdash; it just became \u003Cem\u003Econsistent\u003C/em\u003E. And consistency, at scale, is what separates a professional data engineering practice from a collection of one-off prompts.\u003C/p\u003E\n","\u003Ch3\u003EWhat You Learned\u003C/h3\u003E\n\u003Cul\u003E\u003Cli\u003EHow to use \u003Ccode\u003EAGENTS.md\u003C/code\u003E to establish project-level context for every CoCo session\u003C/li\u003E\u003Cli\u003EWhat agent Skills are, how they're structured, and how the \u003Ccode\u003Edescription\u003C/code\u003E field drives automatic invocation\u003C/li\u003E\u003Cli\u003EHow to create a custom Skill that encodes team-specific conventions\u003C/li\u003E\u003Cli\u003EWhat CoCo Plugins are and why they're the right packaging unit for sharing agent capabilities\u003C/li\u003E\u003Cli\u003EHow to add a \u003Ccode\u003EPreToolUse\u003C/code\u003E hook to protect your production environment\u003C/li\u003E\u003Cli\u003EHow to define a subagent for autonomous, repeatable tasks\u003C/li\u003E\u003Cli\u003EHow to run a CoCo subagent from a GitHub Actions CI/CD pipeline\u003C/li\u003E\u003C/ul\u003E\n","\u003Ch3\u003ERelated Resources\u003C/h3\u003E\n\u003Cul\u003E\u003Cli\u003E\u003Ca href=\"https://github.com/Snowflake-Labs/sfguide-data-engineering-with-coco\"\u003ESource Code on GitHub\u003C/a\u003E\u003C/li\u003E\u003Cli\u003E\u003Ca href=\"https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code\"\u003ECortex Code documentation\u003C/a\u003E\u003C/li\u003E\u003Cli\u003E\u003Ca href=\"https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code-plugins\"\u003ECoCo Plugins reference\u003C/a\u003E\u003C/li\u003E\u003Cli\u003E\u003Ca href=\"https://docs.snowflake.com/en/user-guide/cortex-code/extensibility\"\u003ECoCo Extensibility (Skills, Agents, Hooks, MCP)\u003C/a\u003E\u003C/li\u003E\u003Cli\u003E\u003Ca href=\"https://jeremiahhansen.medium.com/cortex-code-for-data-engineers-8db01c77bf03\"\u003ECortex Code for Data Engineers\u003C/a\u003E &mdash; companion blog post\u003C/li\u003E\u003C/ul\u003E"],"description":"","title":"Base Quickstart CF",":type":"snowflake-site/components/contentfragment","elements":{"quickstartArticleBody":{"dataType":"string","title":"Quickstart Article Body","value":"\u003C!-- ------------------------ --\u003E\n## Overview\n\n![CoCo DE Logo](https://www.snowflake.com/content/dam/snowflake-site/developers/guides/data-engineering-with-coco/coco_de_logo.png)\n\nAnyone can get an AI agent to produce a result. Professionals ensure the right result, every time.\n\nAI coding agents are completely reshaping the data engineering landscape — and if you're not already using them regularly, I'd encourage you to start today. But here's the thing: the fact that an AI agent can generate code isn't actually that interesting anymore. What *is* interesting is how professional data engineers should be thinking about and leveraging these tools to create repeatable, high-quality outcomes.\n\nThat's exactly what this Guide is about. We're going to use Snowflake's AI coding agent — [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code) (or \"CoCo\") — to build a real data engineering project. But more importantly, we're going to do it the *right way*, by encoding our standards and conventions into reusable Skills and Plugins so that every member of your team gets consistent, professional results from the agent — not just you, and not just today.\n\n### What You'll Learn\n* What Cortex Code is, how to install it, and why it's particularly powerful for Snowflake data engineers\n* How to use `AGENTS.md` to give your AI coding agent project-level context and conventions\n* What agent Skills are, how they're structured, and when to create custom ones vs. using bundled ones\n* How to create a custom skill that encodes your team's specific conventions\n* What CoCo Plugins are, how all the pieces fit together, and why they're the right packaging unit for sharing agent capabilities\n* How to add a lifecycle hook to protect your production environment\n* How to define a subagent for autonomous, repeatable tasks\n* How to run a CoCo subagent from a GitHub Actions CI/CD pipeline\n\n### What You'll Build\n* An `AGENTS.md` file that gives CoCo project-level context for every session\n* A custom agent Skill that encodes your team's dbt conventions\n* A new dbt model built by CoCo using that custom skill\n* A CoCo Plugin that bundles your skill, a production safety hook, and a dbt review subagent together into a single deployable unit\n* A GitHub Actions CI/CD pipeline that automatically reviews dbt changes on every pull request using CoCo\n\n### Prerequisites\n* Familiarity with dbt (models, sources, tests)\n* Familiarity with Snowflake\n* Familiarity with Git and GitHub\n\n### What You'll Need\n* **A Snowflake Account**. If you don't already have a Snowflake account you can create a trial account for free. Visit the [Snowflake Trial Account for CoCo Sign Up](https://signup.snowflake.com/cortex-code) page to get started.\n* **A GitHub account**. If you don't already have a GitHub account you can create one for free. Visit the [Join GitHub](https://github.com/signup) page to get started.\n* **CoCo Desktop** installed on your local machine. Visit the [CoCo Desktop Installation](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code-desktop/onboarding-and-authentication) page to get started.\n* **dbt Core** installed on your local machine. Visit the [dbt Core Install](https://docs.getdbt.com/docs/core/installation-overview) page to get started.\n\n\n\u003C!-- ------------------------ --\u003E\n## Setup\n\nBefore we start building, let's get CoCo and the starter dbt project connected to your Snowflake account.\n\n### Fork and Clone the Guide Repository\n\nThis Guide uses a starter repository that includes a pre-built dbt project. The two existing models (`customers` and `orders_summary`) are there as a starting point — you'll add the third model yourself using a custom skill you create later on.\n\nStart by forking the starter repository to your own GitHub account. Visit the [Data Engineering with CoCo Guide Repository](https://github.com/Snowflake-Labs/sfguide-data-engineering-with-coco) and click the **Fork** button near the top right. Complete any required fields and click **Create Fork**.\n\nThen clone your fork to your local machine:\n\n```bash\ngit clone https://github.com/\u003CYOUR_USERNAME\u003E/sfguide-data-engineering-with-coco\ncd sfguide-data-engineering-with-coco\n```\n\nTake a moment to look at what's in the starter:\n\n```\n├── dbt/\n│   ├── dbt_project.yml\n│   ├── profiles.yml.example\n│   └── models/\n│       ├── _sources.yml\n│       ├── customers.sql\n│       └── orders_summary.sql\n├── scripts/\n│   └── setup.sql\n├── .gitignore\n├── LICENSE\n├── README.md\n```\n\n### Configure CoCo Desktop and Open the Project\n\nIf you haven't already installed CoCo Desktop, follow the [installation instructions](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code-desktop/onboarding-and-authentication) for your operating system.\n\nOnce installed, open CoCo Desktop and configure your Snowflake connection. CoCo supports several authentication methods, for this Guide use Local OAuth authentication. See the [CoCo authentication documentation](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code-desktop/onboarding-and-authentication#authentication-methods) for all options.\n\nFinally, use **File → Open Folder** to open the `sfguide-data-engineering-with-coco` directory you cloned above. The first time you open the folder CoCo Desktop will ask you if you Trust the files, go ahead and Trust them. CoCo is context-aware: opening the project folder means the agent can see your files, read your code, and run commands in the right place.\n\n### Create the Snowflake Demo Environment\n\nThe dbt project is pointed at `SNOWFLAKE_SAMPLE_DATA.TPCH_SF1`, which is available in every Snowflake account. There's nothing to load — the data is already there.\n\n\u003E **Note** — The `SNOWFLAKE_SAMPLE_DATA` sample database is created by default for newer accounts. If the database has not been created for your account and you want access to it follow the instructions on the [Use the sample database](https://docs.snowflake.com/en/user-guide/sample-data-using) page.\n\nBut we need to create the demo environment in Snowflake so that dbt can write to it. The `scripts/setup.sql` script contains all the code needed to create the role, warehouse, database and schema for the demo environment.\n\nAnd the good part is you can run SQL scripts directly from CoCo Desktop by following these steps:\n* Open the `scripts/setup.sql` script\n* Run all of the SQL statements in this script by clicking on the down arrow and \"Run all\", next to the blue play button at the top right of the script, or using the shortcut CMD/CTRL+Shift+Enter\n\n### Create a Snowflake Personal Access Token\nIn order to connect to your Snowflake account from dbt and GitHub Actions, we will use a Snowflake Personal Access Token (or PAT). Please follow the steps in [Generating a programmatic access token](https://docs.snowflake.com/en/user-guide/programmatic-access-tokens#generating-a-programmatic-access-token) to create a Snowflake PAT for your user. Use these values when creating the PAT, in the \"New programmatic access token\" dialog:\n\n* **Name**: DEMO_PAT (upper case)\n* **Expires in**: Leave with default (15 days)\n* **Grant access**: Select **Single role (recommended)**, then the `DEMO_ROLE` role\n\nMake sure to save the PAT before leaving the page, as you won't be able to view it again. We will use the PAT in the next section to configure dbt as well as in the final CI/CD section to connect to Snowflake from GitHub Actions.\n\nFinally, run the following command in a SQL script in Workspaces. This will allow you to bypass the active network policy rule temporarily, for 60 minutes, in order to test out the CI/CD pipeline. For long-term access you need to create a network policy allowing access from the GitHub Actions environment. For more details check out our [Controlling network traffic with network policies](https://docs.snowflake.com/en/user-guide/network-policies) page.\n\n```sql\nALTER USER \u003CYOUR_USER_NAME\u003E MODIFY PROGRAMMATIC ACCESS TOKEN DEMO_PAT\n  SET MINS_TO_BYPASS_NETWORK_POLICY_REQUIREMENT = 60;\n```\n\n\u003E **Note** — You may need to put double-quotes around the PAT token name in this query if you didn't name your token with all uppercase letters.\n\n### Configure dbt\n\ndbt looks for `profiles.yml` in `~/.dbt/` by default. If you don't have one yet, copy the example file:\n\n```bash\nmkdir -p ~/.dbt\ncp dbt/profiles.yml.example ~/.dbt/profiles.yml\n```\n\nIf you already have a `~/.dbt/profiles.yml`, open it and add the `coco_de_guide` profile block from `dbt/profiles.yml.example` alongside your existing profiles — each top-level key is a separate profile and they won't conflict.\n\nOpen `~/.dbt/profiles.yml` (CMD/CTRL+p) and replace the placeholders in the `coco_de_guide` block with your values:\n\n```yaml\ncoco_de_guide:\n  target: dev\n  outputs:\n    dev:\n      type: snowflake\n      account: \"\u003CYOUR_ACCOUNT\u003E\"\n      user: \"\u003CYOUR_USERNAME\u003E\"\n      password: \"\u003CYOUR_PERSONAL_ACCESS_TOKEN\u003E\"\n      role: DEMO_ROLE\n      database: DEMO_DB\n      warehouse: DEMO_WH\n      schema: TPCH_TRANSFORMED\n      threads: 4\n```\n\n\u003E **Note** — `~/.dbt/profiles.yml` lives outside your repository so your credentials are never at risk of being committed.\n\n### Verify Your dbt Setup\n\nMake sure dbt can connect to your Snowflake account. Open a terminal in CoCo Desktop and run the following command:\n\n```bash\ndbt debug --project-dir dbt/\n```\n\nYou should see `All checks passed!` at the end of the output. If you run into any connection issues, double-check your `profiles.yml` values and make sure your Snowflake account identifier is in the correct format (e.g., `xy12345.us-east-1`).\n\n\n\u003C!-- ------------------------ --\u003E\n## What is Cortex Code?\n\n![CoCo DE Logo](https://www.snowflake.com/content/dam/snowflake-site/developers/guides/data-engineering-with-coco/coco_logo.png)\n\n[Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code) (CoCo) is Snowflake's AI coding agent — an autonomous, context-aware agent optimized for data engineering, analytics, and machine learning tasks. Unlike generic coding assistants, CoCo has deep native knowledge of Snowflake: it understands your schemas, respects your RBAC configuration, and knows Snowflake best practices without being told. Critically for enterprises, the model and the data it touches never leave Snowflake's security perimeter.\n\n### Form Factors\n\nCoCo is available in three form factors, and the right choice depends on how you work:\n\n| Form factor | Best for |\n|-------------|----------|\n| **CoCo in Snowsight** | Web-based access directly inside Snowflake's UI. Great for SQL and notebook authoring without installing anything. |\n| **CoCo Desktop** | A standalone IDE for macOS and Windows (built on VS Code). Full agent experience with local file access, native Git integration, and complete support for plugins, skills, hooks, and subagents. |\n| **CoCo CLI** | A terminal-native agent for power users who prefer the command line or want to integrate CoCo into scripts and automation. |\n\nThis Guide uses **CoCo Desktop** throughout. Local file access and full extensibility support — skills, plugins, hooks, and subagents — are central to what we're building, and Desktop is the right tool for all of it.\n\n\n\u003C!-- ------------------------ --\u003E\n## Create an AGENTS.md\n\nBefore you write a single prompt, there's one thing that will improve every single interaction you have with CoCo in this project: an `AGENTS.md` file.\n\n### What is AGENTS.md?\n\n`AGENTS.md` is a Markdown file at the root of your project that contains conventions, context, and commands that you want the agent to know about — every single session, automatically. Without it, you'd have to re-explain your database names, your naming conventions, and your preferred commands every time you start a new chat. With it, that context is always there.\n\nThink of it as the onboarding document you'd write for a new team member — except this team member reads it perfectly every time, never forgets it, and follows it consistently. Here's the key guidance I follow when writing `AGENTS.md`:\n\n* **Keep it short.** The context window is a shared, finite resource. Challenge every sentence: does the agent *actually* need this, or will it figure it out on its own?\n* **Encode what the model can't infer.** Don't write instructions telling CoCo how to use dbt — it already knows how dbt works. Do write down your database name, your schema naming conventions, and the exact command to use for building and testing.\n* **It doesn't change session-to-session.** Stable project facts belong here. Session-specific instructions belong in your prompts.\n\n### Create Your AGENTS.md\n\nLet's create an `AGENTS.md` for this project. In the CoCo chat panel, enter the following prompt:\n\n```\nCreate an AGENTS.md file at the root of this project. Include:\n- The Snowflake database (DEMO_DB), schema (TPCH_TRANSFORMED), and warehouse (DEMO_WH)\n- The dbt build command to use: `dbt build --project-dir dbt/`\n- The command to build a single model: `dbt build --select \u003Cmodel_name\u003E --project-dir dbt/`\n- Snake_case naming convention for model files\n- The source data is TPCH_SF1 in SNOWFLAKE_SAMPLE_DATA; all raw tables must be referenced through _sources.yml\n- Feature branches should follow the pattern: feature/\u003Cdescription\u003E\n- PRs are required before merging to main\n- This project uses CoCo Desktop — do not use the `cortex` CLI command\n```\n\nCoCo will generate an `AGENTS.md` file. Review it and accept/save the changes by clicking on the \"Keep\" button. Your `AGENTS.md` may be slightly different, and that's OK, but it should look something like this:\n\n```markdown\n# Project: CoCo DE Guide\n\n## Snowflake\n- Database: DEMO_DB\n- Schema: TPCH_TRANSFORMED\n- Warehouse: DEMO_WH\n\n## dbt Commands\n- Build + test: `dbt build --project-dir dbt/`\n- Single model: `dbt build --select \u003Cmodel_name\u003E --project-dir dbt/`\n\n## Naming Conventions\n- Model files: snake_case\n- Source schema: TPCH_SF1 in SNOWFLAKE_SAMPLE_DATA\n- Transformed schema: TPCH_TRANSFORMED\n\n## Branching\n- Feature branches: `feature/\u003Cdescription\u003E`\n- PRs required before merging to main\n\n## CoCo\n- This project uses CoCo Desktop — do not use the `cortex` CLI command\n```\n\n\u003E **Note** — CoCo has bundled skills that know about the CoCo CLI `cortex` command. Those skills can activate and cause CoCo to attempt CLI operations. The `AGENTS.md` instruction to not use the `cortex` CLI should prevent this.\n\n### Validate the Starter Code Against Your Conventions\n\nNow let's put `AGENTS.md` to immediate use. The starter project was built before these conventions were established — which is exactly the situation you'll often face when inheriting a codebase. Let's have CoCo audit the existing models and bring them into compliance.\n\nIn the CoCo chat panel, enter:\n\n```\nReview all dbt models in this project against the conventions in AGENTS.md\nand fix any violations you find.\n```\n\nCoCo will read `AGENTS.md`, then inspect each model SQL file. It should find that `orders_summary.sql` references source tables directly by their fully-qualified Snowflake path instead of going through `_sources.yml`:\n\n```sql\n-- Violation: direct source reference\nFROM SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.ORDERS o\nLEFT JOIN SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.LINEITEM l ...\n```\n\nCoCo will rewrite the model to use the correct `{{ source() }}` references:\n\n```sql\n-- Fixed: references go through _sources.yml\nFROM {{ source('tpch', 'orders') }} o\nLEFT JOIN {{ source('tpch', 'lineitem') }} l ...\n```\n\nClick on \"Keep\" to accept that changes. Once the fix is applied, run `dbt build` to confirm nothing broke:\n\n```bash\ndbt build --project-dir dbt/\n```\n\nThis is `AGENTS.md` doing its job. CoCo didn't need to be told what the violation was or what the fix should look like — it read the conventions, read the code, and connected the two. That's the value: not any single dramatic prompt, but every prompt in the session being grounded in your actual standards rather than the model's best guess.\n\n\u003E **Tip** — Your `AGENTS.md` should evolve as your project grows. Any time you find yourself repeating the same context in multiple prompts (a team convention, a frequently-used command, an important constraint), that's a signal it belongs in `AGENTS.md`.\n\n\n\u003C!-- ------------------------ --\u003E\n## What is a Skill?\n\nWe've seen `AGENTS.md` handle project context and enforce existing conventions. But what about when you're creating something new? When the task is \"build a new dbt model,\" `AGENTS.md` tells CoCo the database name and the build command — but it doesn't tell it the specific workflow your team follows or the standards that must hold for every new model. That's what Skills are for.\n\nLet's take a few minutes to understand what Skills actually are — because this concept is central to everything that follows in this Guide.\n\n### Skills Defined\n\nAgent Skills are used for implementing repeatable, multi-step workflows. They're made up of instructions that tell the agent how to perform a specific type of task. Skills are supported by most AI coding agents, and the emerging open standard is documented at [agentskills.io](https://agentskills.io/).\n\nHere's the key insight: **Skills encode what the model can't infer on its own.** This is worth repeating because it's the most common mistake I see when teams start writing skills. The frontier LLM models are incredibly capable and already know how to do most data engineering tasks. You don't need to write a Skill teaching CoCo what dbt is or how to write a SQL transformation — it already knows. What you *do* need to capture in a Skill is any repeatable process that is *specific to your team*: your naming conventions, your testing standards, your deployment workflow, the exact steps you want followed in a particular order.\n\n### The SKILL.md File\n\nAt its core, a Skill is a folder containing a single required file: `SKILL.md`. This file has two parts:\n\n1. **YAML Frontmatter** — metadata about the skill, including its name and description\n2. **Markdown body** — the actual instructions the agent will follow\n\nThe `description` field is especially important: CoCo uses it to decide when to automatically invoke the Skill. Write it as a clear, one-sentence trigger — think of it as answering the question \"when should CoCo use this skill?\"\n\nHere's the minimum structure of a `SKILL.md` file:\n\n```markdown\n---\nname: my-skill\ndescription: Brief description of when this skill should be used.\n---\n\n# Instructions\n\nYour workflow steps and conventions go here.\n```\n\n### Skill Folder Structure\n\nA Skill lives in a folder, and that folder can contain more than just `SKILL.md`. You can bundle scripts, templates, and reference materials alongside your instructions:\n\n```\nmy-skill/\n├── SKILL.md          # Required — instructions and metadata\n└── scripts/          # Optional — reusable scripts the agent can run\n    └── my-script.py\n```\n\nFor many Skills, the `SKILL.md` file alone is enough. The scripts folder becomes useful when your workflow requires running a specific piece of code consistently.\n\n### Bundled vs. Custom Skills\n\nCoCo ships with a set of bundled Skills for Snowflake-specific workflows that require specialized knowledge the base model doesn't have on its own — things like deploying dbt projects as Snowflake-native objects via the `snow dbt` CLI, managing Dynamic Tables, working with Iceberg catalogs, and more. These are maintained by Snowflake and are automatically available without any setup.\n\n![CoCo Built-In DE Skills](https://www.snowflake.com/content/dam/snowflake-site/developers/guides/data-engineering-with-coco/coco_built_in_de_skills.png)\n\nFor common tasks that are well-represented in the model's training data — standard SQL, Python, dbt syntax, general software engineering practices — you typically don't need a skill at all. CoCo's base knowledge handles those.\n\nCustom Skills are ones you write yourself, for your specific team and project. They don't teach CoCo how to use a tool — it already knows. They encode the *choices* your team has made: which conventions to follow, which steps to run in which order, which guardrails to apply.\n\nA useful rule of thumb: if you find yourself starting a prompt with \"remember, we always...\" — that's a custom skill waiting to be written.\n\n\u003E **Best practices**\n\u003E * Keep Skills under 500 lines — long skills are hard to maintain and can dilute the context window\n\u003E * Write the `description` as a clear, specific trigger phrase\n\u003E * Don't repeat general knowledge — only encode what CoCo can't infer\n\u003E * Test your skill by invoking it and checking if CoCo follows every convention without extra prompting\n\n\n\u003C!-- ------------------------ --\u003E\n## Using CoCo Without a Skill\n\nBefore writing your first custom Skill, it's worth understanding what you *don't* need to encode. The frontier model behind CoCo has broad, deep knowledge of the software and data engineering ecosystem — and that means for a lot of common tasks, you can just ask.\n\n### Add Schema Tests Without Any Skill\n\nOur starter project has two models — `customers` and `orders_summary` — but neither has schema tests defined in `_schema.yml`. Schema tests validate your data against expectations (like `not_null` and `unique`) every time you run `dbt build`, catching data quality issues before they reach downstream consumers.\n\nLet's ask CoCo to add them. No skill invocation, no special instructions — just a direct prompt:\n\n```\nAdd schema tests to the existing models in this project.\nSave the results in dbt/models/_schema.yml.\nAt a minimum, each model's primary key should have not_null and unique tests.\nAdd any other tests that make sense given the columns in each model.\nFor parameterized tests like accepted_values, nest all test parameters under an arguments: key.\n```\n\nCoCo will read the model SQL files, identify the primary key columns, and generate `dbt/models/_schema.yml` with appropriate tests for `customer_key` in `customers` and `order_key` in `orders_summary`, along with additional column-level tests where they make sense. Review the changes and click on \"Keep\" to accept/save them. Run `dbt build` to confirm everything passes:\n\n```bash\ndbt build --project-dir dbt/\n```\n\n\u003E **Note** — If any tests fail, it likely means the source data doesn't meet the expected constraints. Inspect the failure message and adjust the tests accordingly. Not every column that *looks* like a primary key actually has unique values in the TPC-H dataset.\n\n### What This Demonstrates\n\nCoCo just added a complete set of schema tests without being told what the primary keys were, how `_schema.yml` is structured, or what test types are available in dbt. It already knew all of that.\n\nNotice, though, that we had to specify the filename `_schema.yml` explicitly — without it, CoCo defaults to `schema.yml`. Both are valid dbt, but your project uses the underscore prefix by convention. This is a small but telling example of the broader point: **the model knows the tool, not your team's choices**. It doesn't know that you always use `dbt build` rather than `dbt run`, that primary key tests are required on every new model, or that source references must go through `_sources.yml`. Those are your team's specific conventions, and without being told, the model will handle them inconsistently from one session to the next. That's exactly what a custom Skill addresses.\n\n\n\u003C!-- ------------------------ --\u003E\n## Create a Custom Skill\n\nCoCo's base knowledge is great for standard dbt tasks. But for the conventions that are *specific to this project* — the ones that need to hold consistently across every new model your team builds — that's where a custom Skill comes in.\n\n### Why We Need a Custom Skill\n\nCoCo knew the dbt test syntax, the `_schema.yml` structure, and the right test types — all general knowledge. What it doesn't know is the three conventions your team has agreed on for this project: always use `dbt build` (not `dbt run`), every primary key must have `not_null` and `unique` tests, and raw tables must always go through `_sources.yml`. Those choices aren't right or wrong in any absolute sense — they're just the standards *your team* has decided to follow. A custom Skill is how you encode them so CoCo applies them consistently, without being reminded.\n\n### Create the Skill Folder Structure\n\nSkills need to live somewhere CoCo can find them. CoCo auto-discovers **project skills** from a `.snowflake/cortex/skills/` folder inside the open workspace — no registration or install step required. As soon as the folder exists and contains a `SKILL.md`, the skill is live. Let's create it:\n\n```bash\nmkdir -p .snowflake/cortex/skills/new-dbt-model\n```\n\n\u003E **Note** — The `.snowflake/cortex/skills/` path is intentional. CoCo scans this folder automatically whenever your workspace is open, which means the skill will be available immediately after you write it — no further setup needed.\n\n### Write the SKILL.md\n\nNow let's write the Skill. In the CoCo chat panel, enter:\n\n```\nCreate a custom skill at .snowflake/cortex/skills/new-dbt-model/SKILL.md for creating \nnew dbt models in this project.\n\nThe skill should have exactly two sections:\n\n# Conventions — a numbered list of these three rules:\n1. Always use `dbt build` (not `dbt run`) so tests run together with compilation\n2. Every model's primary key must have not_null and unique tests in _schema.yml\n3. All raw tables must be referenced through _sources.yml using source() — never reference the source database directly in model SQL\n\n# Workflow — a numbered list of these four steps:\n1. Confirm which source table(s) to model — ask if not specified\n2. Write the model SQL using source() references\n3. Add the model entry to _schema.yml with a description and primary key tests\n4. Run dbt build --select \u003Cmodel_name\u003E --project-dir dbt/ and report the result\n\nUse the name new-dbt-model. Write a one-sentence description that tells CoCo when \nto invoke this skill. Keep the skill concise — no sub-steps, no examples, no error \nhandling instructions. The model is smart enough to infer the details.\n```\n\nReview the generated `SKILL.md` and click on \"Keep\" to accept/save the changes. It should have a clean YAML frontmatter block with `name` and `description`, followed by the four workflow steps and the three conventions. The description should read something like: *\"Create a new dbt model in this project. Use when adding a model for a new source table or analytical use case.\"*\n\nIf anything looks off — a missing convention, a step out of order — correct it now. Your `SKILL.md` may be slightly different, and that's OK, but it should look something like this:\n\n```markdown\n---\nname: new-dbt-model\ndescription: Create a new dbt model in this project. Use when adding a model for a new source table or analytical use case.\n---\n\n# Conventions\n\n1. Always use `dbt build` (not `dbt run`) so tests run together with compilation.\n2. Every model's primary key must have `not_null` and `unique` tests in `_schema.yml`.\n3. Reference all raw tables through `_sources.yml`. Never reference the source database directly in model SQL.\n\n# Workflow\n\n1. Confirm which source table(s) to model — ask if not specified.\n2. Write the model SQL in `dbt/models/\u003Cmodel_name\u003E.sql` using `{{ source('\u003Csource\u003E', '\u003Ctable\u003E') }}` references.\n3. Add the model entry to `dbt/models/_schema.yml` with a description and tests for the primary key.\n4. Run `dbt build --select \u003Cmodel_name\u003E --project-dir dbt/` and report the result.\n```\n\n### Invoke the Skill to Build a New Model\n\nNow for the payoff: let's use the skill we just wrote to build the third model in our project. In the CoCo chat panel, enter:\n\n```\nUse the new-dbt-model skill to create a supplier_performance model.\nIt should summarize performance metrics per supplier from the supplier and lineitem source tables.\nInclude total orders, total revenue, and average discount.\n```\n\nWatch what happens. CoCo auto-discovers the skill from `.snowflake/cortex/skills/`, matches the prompt against its description, and invokes it automatically. It will follow the workflow steps in order and apply all three conventions — without you having to repeat any of them:\n\n1. Identify the `supplier` and `lineitem` source tables from `_sources.yml`\n2. Write `dbt/models/supplier_performance.sql` using `{{ source() }}` references\n3. Add the model entry to `_schema.yml` with primary key tests\n4. Run `dbt build --select supplier_performance --project-dir dbt/` and report the result\n\nThat's the difference between a one-off prompt and a Skill. The conventions are encoded once. The team benefits every time. Accept the changes by clicking \"Keep\" on each new/modified file.\n\n\u003E **Tip** — Resist the urge to put too much into a single Skill. A focused Skill for \"create a new dbt model\" is more useful than a sprawling one for \"do everything dbt-related.\" Smaller, well-named Skills are easier to maintain and easier for CoCo to invoke correctly.\n\n\n\u003C!-- ------------------------ --\u003E\n## What is a Plugin?\n\nWe now have a working custom Skill. Let's talk about Plugins before we build one — because understanding *why* Plugins exist makes it much easier to understand what we're about to put together.\n\n### Skills Alone Have Limitations\n\nThe project skill you just built works great — for you, in this workspace. But what if you want to use this skill in a different project/repository? You'd have to create a copy of it in the other project, and then you'd have multiple copies to maintain. And there are other important extensibility features for AI coding agents besides skills. For example, what if you want to add a production safety hook alongside it? Or a subagent for PR review? Now you're managing three separate things, none of them versioned together or installable as a unit. And what if your hook or subagent needs to be shared across multiple repositories, not just this one?\n\nThat's where Plugins come in. A Plugin is a single installable unit that bundles everything together — skills, hooks, subagents, and MCP servers — with a version number, a formal validation step, and a one-command install. Plugins were designed to be the right packaging unit for distributing agent capabilities, both within a team and across an organization.\n\nHere's a short list of why a Plugin is a better packaging unit than a raw Skill folder:\n\n* **Versioned** — the manifest has a `version` field; raw Skill folders don't\n* **Validatable** — the manifest is formally parsed and checked when you install; no equivalent check exists for raw Skill folders\n* **Single installable unit** — one Add Local Plugin action in the Agent Settings panel registers everything; individual Skills require separate registration per Skill\n* **Updatable** — GitHub-sourced plugins have a Sync button that pulls the latest version; Skills have no equivalent lifecycle\n* **Bundling** — one Plugin can carry Skills, hooks, subagents, and MCP servers as a coherent capability\n* **Registry tracking** — installed Plugins are recorded with source, install time, and active state; you always know exactly what's deployed\n\n### Plugin Folder Structure\n\nA Plugin is a self-contained directory with a manifest file at a well-known path:\n\n```\nmy-plugin/\n├── .cortex-plugin/\n│   ├── plugin.json       # Manifest (required)\n│   └── activation.md     # Optional — displayed when the plugin is activated\n├── skills/               # Auto-discovered if present\n│   └── my-skill/\n│       └── SKILL.md\n├── agents/               # Auto-discovered if present\n│   └── my-agent.md\n└── hooks/\n    └── hooks.json        # Lifecycle hooks\n```\n\n\u003E **Note** — CoCo uses the `.cortex-plugin/` directory name. If you use `.claude-plugin/`, that works too for Claude-compatible tooling, but `.cortex-plugin/` is the standard for CoCo.\n\n### The plugin.json Manifest\n\nThe `plugin.json` file is the heart of the Plugin. It declares everything the Plugin contains, who made it, and how it behaves. Here's a minimal example:\n\n```json\n{\n  \"name\": \"my-plugin\",\n  \"description\": \"What this plugin does\",\n  \"version\": \"1.0.0\",\n  \"author\": { \"name\": \"Your Team\" },\n  \"skills\": [\"./skills\"],\n  \"agents\": [\"./agents\"],\n  \"hooks\": \"./hooks/hooks.json\"\n}\n```\n\n### Plugin Elements\n\nLet's briefly cover each element a Plugin can contain:\n\n**Skills** — the Skill folders we already know about, now bundled and versioned together. Pointed to via the `\"skills\"` array in the manifest.\n\n**Agents (Subagents)** — Markdown files that define autonomous, specialized agents. Like Skills, they have YAML frontmatter with `name`, `description`, and optionally `tools` and `model`. The body contains instructions the agent follows when invoked. The key difference from a Skill: a subagent is designed to run autonomously to completion on a specific task, whereas a Skill guides an interactive session.\n\n**Hooks** — shell commands that run on lifecycle events. The most useful for data engineers is `PreToolUse`, which fires before CoCo executes a tool (like running a Bash command). This is how you add guardrails — for example, blocking direct production deployments. Hooks are defined in a `hooks.json` file and reference shell scripts.\n\n**MCP Servers** — Model Context Protocol servers that expose external tools to the agent. For example, you could wire up a connection to your internal issue tracker or GitHub so CoCo can pull context from outside the codebase. We won't cover MCP Servers in depth in this Guide, but you can find full details in the [CoCo documentation](https://docs.snowflake.com/en/user-guide/cortex-code/extensibility#model-context-protocol-mcp).\n\n**activation.md** — an optional Markdown file displayed to the user when the Plugin is activated. Use it to explain what the Plugin does and how to enable it.\n\n\n\u003C!-- ------------------------ --\u003E\n## Create a Custom Plugin\n\nWe have all the pieces — a custom Skill, a clear understanding of what Plugins are, and a project that's ready to be hardened. Now let's bundle everything into a proper Plugin. The first thing we'll do is migrate the skill from its project-local home into the plugin folder, then add a production safety hook and a dbt review subagent alongside it.\n\n### Move the Skill into the Plugin\n\nThe skill currently lives at `.snowflake/cortex/skills/new-dbt-model/` — scoped to this workspace. We're going to move it into `.cortex/plugins/coco-de-guide/` — the project-scoped plugin directory that CoCo auto-discovers. Run these commands in the terminal:\n\n```bash\nmkdir -p .cortex/plugins/coco-de-guide/skills\nmv .snowflake/cortex/skills/new-dbt-model .cortex/plugins/coco-de-guide/skills/\nrm -rf .snowflake/\n```\n\nThe skill is now in `.cortex/plugins/coco-de-guide/skills/new-dbt-model/SKILL.md`. CoCo auto-discovers plugins in `.cortex/plugins/`, so once the manifest is in place, the plugin will be live — no separate install step needed.\n\n### Create the Plugin Manifest\n\nLet's create the `.cortex-plugin/` directory and write the manifest. In the CoCo chat panel, enter:\n\n```\nConsult the CoCo Desktop plugin\ndocumentation at https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code-desktop/plugins\nfor the correct plugin.json schema and file structure.\n\nCreate a CoCo plugin manifest for this project at .cortex/plugins/coco-de-guide/.cortex-plugin/plugin.json.\n\nThe manifest must include all of the following fields:\n- name: \"coco-de-guide\"\n- version: 1.0.0\n- author: me\n- skills: pointing to ./skills\n- agents: pointing to ./agents\n- hooks: pointing to ./hooks/hooks.json\n\nAlso create .cortex/plugins/coco-de-guide/.cortex-plugin/activation.md that briefly explains\nwhat the plugin includes.\n\nDo not use the cortex CLI — write the files directly.\n```\n\n\u003E **Note** — CoCo has bundled skills that know about the `cortex` CLI's plugin commands (`cortex plugin install`, `cortex plugin validate`, etc.). Those skills can activate here and cause CoCo to attempt CLI operations instead of just writing files. The `AGENTS.md` instruction to not use the `cortex` CLI should prevent this, but if CoCo does try to run CLI commands, remind it: *\"Do not use the cortex CLI — write the files directly.\"*\n\nCoCo will create both `plugin.json` and `activation.md`. Accept the changes by clicking \"Keep\" on each new/modified file. Your `plugin.json` manifest may be slightly different, and that's OK, but it should look something like this:\n\n```json\n{\n  \"name\": \"coco-de-guide\",\n  \"description\": \"dbt/Snowflake data engineering plugin for the CoCo DE Guide\",\n  \"version\": \"1.0.0\",\n  \"author\": { \"name\": \"\u003CYOUR_NAME\u003E\" },\n  \"skills\": [\"./skills\"],\n  \"agents\": [\"./agents\"],\n  \"hooks\": \"./hooks/hooks.json\"\n}\n```\n\n### Add a Production Safety Hook\n\nOne of the most valuable things a Plugin can do is protect your environment from mistakes. A common problem with AI coding agents is that they'll happily run whatever command you ask — including commands that write directly to production. We can prevent that with a `PreToolUse` hook.\n\nLet's add a hook that blocks any `dbt` command that targets production:\n\n```\nConsult the CoCo Desktop hooks documentation at\nhttps://docs.snowflake.com/en/user-guide/cortex-code/cortex-code-desktop/hooks\nfor the correct hooks.json schema and shell script format.\n\nCreate a PreToolUse hook at .cortex/plugins/coco-de-guide/hooks/validate-bash.sh that blocks\nany dbt command that includes --target prod. If the command is blocked, return a clear error\nmessage explaining that direct production dbt runs are not allowed and to use the CI/CD\npipeline instead.\nAlso create .cortex/plugins/coco-de-guide/hooks/hooks.json that wires this script to the\nPreToolUse event using the matcher value \"bash\" (lowercase).\n```\n\nCoCo will create both files. The shell script reads the tool input from stdin (as JSON), extracts the command, and checks it against the pattern. The `hooks.json` wires it up. Accept the changes by clicking the 'Keep' button. Your `hooks.json` may be slightly different, and that's OK, but it should look something like this:\n\n```json\n{\n  \"hooks\": {\n    \"PreToolUse\": [\n      {\n        \"matcher\": \"bash\",\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"bash .cortex/plugins/coco-de-guide/hooks/validate-bash.sh\",\n            \"timeout\": 10\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\nWe'll test the hook in the next step.\n\n### Add a dbt Review Subagent\n\nThe final piece of our Plugin is a subagent for reviewing dbt model changes. Unlike a Skill — which guides an interactive session — this subagent is designed to run autonomously to completion. We'll use it both locally (before opening a PR) and in CI/CD (on every PR automatically). That \"same agent, two contexts\" pattern is one of the most powerful things you can build with CoCo.\n\n```\nConsult the CoCo Desktop agents documentation at\nhttps://docs.snowflake.com/en/user-guide/cortex-code/cortex-code-desktop/agents\nfor the correct agent definition format and frontmatter schema.\n\nCreate a dbt-review subagent at .cortex/plugins/coco-de-guide/agents/dbt-review.md.\nThe subagent should:\n- Find all changed dbt model files compared to origin/main\n- For each changed model, run dbt build --select \u003Cmodel\u003E --project-dir dbt/\n- Verify that each convention from the new-dbt-model skill is met\n- Produce a concise PASS/FAIL report per convention with specific remediation steps for any failures\n\nIt should use the bash, read, grep, and glob tools. Set the model to auto.\n```\n\nReview the generated `dbt-review.md` and click on \"Keep\" to accept/save the changes. It should have YAML frontmatter with `name`, `description`, `tools`, and `model` fields, followed by the review steps and output format.\n\n### Activate the Plugin\n\nBecause the plugin lives in `.cortex/plugins/coco-de-guide/`, CoCo Desktop will discover it automatically when the workspace is opened. To verify it is active:\n\n1. Click the **Settings** tab (gear icon) in the bottom of the left sidebar\n2. Open the **Plugins** section\n3. Look for `coco-de-guide` in the Plugins grid\n\nIf the plugin appears but is toggled off, click the toggle to enable it. If it doesn't appear at all, click the **↻** (refresh) button in the Plugins toolbar to force a reload of the plugin registry.\n\n![CoCo Plugin Summary](https://www.snowflake.com/content/dam/snowflake-site/developers/guides/data-engineering-with-coco/coco_desktop_plugin_summary.png)\n\n\u003E **Note** — Project-scoped plugins require workspace trust before they auto-activate. If your workspace is not trusted, the plugin will appear in the Plugins panel but will be disabled. Enable it individually via the toggle, or trust the workspace to activate all project plugins automatically.\n\nClick the plugin card to open its detail view and verify that all three components — the skill, the hook, and the subagent — are listed.\n\n![CoCo Plugin Detail](https://www.snowflake.com/content/dam/snowflake-site/developers/guides/data-engineering-with-coco/coco_desktop_plugin_detail.png)\n\n\n\u003E **Tip** — File watchers detect changes to plugin files automatically, so edits to `plugin.json`, `SKILL.md`, the hook script, or the subagent take effect immediately. Use the **↻** button only if a change isn't appearing after a bulk file operation.\n\n### Test the Hook\n\nNow that the plugin is active, the hook is live. Try to get CoCo to run a production deployment by entering this prompt in the chat panel (not in the terminal):\n\n```\nRun dbt build --target prod --project-dir dbt/\n```\n\nYou should see the hook fire and block the command with a clear explanation before CoCo can execute it. This is a small but important example of the broader principle: **agents should not make changes directly in production**. Even with clear instructions, agents generate content dynamically — and that non-determinism is not something you want in a production pipeline. Hooks give you hard guardrails that enforce that boundary regardless of what the agent decides.\n\n### Try the Subagent Locally\n\nBefore wiring this subagent into CI/CD, try it from the chat panel first. Type:\n\n```\nUse the dbt-review agent to review the changes in this branch.\n```\n\nThe subagent will run to completion autonomously — finding changed model files, running `dbt build` for each, checking conventions, and producing a PASS/FAIL report. If you've made any changes that violate the `new-dbt-model` skill conventions, you'll see specific remediation steps in the output.\n\n\n\u003C!-- ------------------------ --\u003E\n## Publish to the Plugin Catalog\n\nSo far, your plugin lives at `.cortex/plugins/coco-de-guide/` inside this repository. Teammates can install it by cloning the repo or using **Add from GitHub** in CoCo Desktop. That works — but Snowflake has a better option for teams that want centralized discovery and access control: the **Plugins Catalog**.\n\n### What is the Plugins Catalog?\n\nThe Plugins Catalog is Snowflake's built-in registry for sharing and discovering plugins across your organization. Publishing to it gives you:\n\n* **Governance** — access is controlled by Snowflake roles and grants, not Git permissions\n* **Discoverability** — teammates can browse and search for plugins from CoCo Desktop\n* **No credentials required** — consumers install directly from Snowflake, no GitHub access needed\n* **Versioning** — each publish creates a new version; consumers sync to get the latest\n\n### Where the Plugin Lives in Snowflake\n\nWhen you publish a plugin, CoCo creates a `CORTEX EXTENSION` object in your Snowflake account. A Cortex Extension is a schema-level object (`TYPE = PLUGIN`) that stores your plugin's files as a live, versioned stage and holds the `READ` grants that control who can use it.\n\nThe naming follows a convention: the plugin's `name` field is uppercased and hyphens are replaced with underscores. The object is created in a `SKILL_SHARING` schema inside your personal database:\n\n```\nUSER$\u003CYOUR_USERNAME\u003E.SKILL_SHARING.COCO_DE_GUIDE\n```\n\nOnce published, the plugin has a **share URI** — a `snow://` link that uniquely identifies this version:\n\n```\nsnow://skill_catalog/USER$\u003CYOUR_USERNAME\u003E.SKILL_SHARING.COCO_DE_GUIDE/versions/version$1/\n```\n\nThis is what you share with your team. It's stable, access-controlled, and works regardless of whether the recipient has access to your Git repository.\n\n### Publish from CoCo Desktop\n\n1. Click the **Settings** tab (gear icon) in the bottom of the left sidebar\n2. Open the **Plugins** section\n3. Click the `coco-de-guide` plugin card to open its detail view\n4. Click the **Publish to Plugins Catalog** button (cloud-upload icon)\n\nA chat session opens and the `share-skill-and-plugin` skill runs automatically. It will:\n\n1. Prompt you to confirm the plugin name and description\n2. Create the `SKILL_SHARING` schema in your personal database (if it doesn't exist) and grant `USAGE` to `PUBLIC`\n3. Create the `COCO_DE_GUIDE` Cortex Extension object\n4. Upload all plugin files to the extension's versioned stage\n5. Commit the version and apply your chosen access settings\n\nAt the end, CoCo reports the share URI:\n\n```\nsnow://skill_catalog/USER$\u003CYOUR_USERNAME\u003E.SKILL_SHARING.COCO_DE_GUIDE/versions/version$1/\n```\n\n\u003E **Note** — By default the plugin is not discoverable in the catalog browser — it's reachable only by anyone you share the URI with. You can change this during the publish flow if you want the plugin to be visible to everyone in your organization.\n\n### Installing a Catalog Plugin\n\nThis Guide doesn't walk through the consumer-side flow, but here's how a teammate would install your published plugin:\n\n1. Click the **Settings** tab (gear icon) in the bottom of the left sidebar\n2. Open the **Plugins** section\n3. Click **+** and choose **Add from Plugins Catalog**\n4. Paste the `snow://skill_catalog/...` URI and click **Import**\n\nCoCo downloads the plugin files from Snowflake, validates the manifest, and registers it. The plugin appears in the grid with a **CATALOG** badge. They can sync to newer versions at any time from the plugin's detail view.\n\n\n\u003C!-- ------------------------ --\u003E\n## Enforce Standards Automatically in CI/CD\n\nEverything we've built so far — the `AGENTS.md`, the Skill, the Plugin, the hook, the subagent — was designed with this moment in mind. We're going to take the exact same dbt-review subagent we've been running locally and wire it into a GitHub Actions workflow so it runs automatically on every pull request that touches a dbt model. Same agent. Same conventions. Now running in CI.\n\nThis is the payoff of building a Plugin instead of a loose collection of Skill files. But there's one important note about what's different here: while this Guide uses **CoCo Desktop** for the interactive development sections, the CI/CD pipeline uses the **CoCo CLI** — the terminal-native form of the same agent. The CLI is the right tool for automation: it runs headlessly, connects via a credentials file, and is installable in any CI environment. The plugin you built in `.cortex/plugins/` is auto-discovered by the CLI just as it is by Desktop — no separate install step needed.\n\n### Configure GitHub Secrets\n\nFrom your forked repository on GitHub, click **Settings → Secrets and variables → Actions**. Add the following repository secrets:\n\n| Secret name | Value |\n|-------------|-------|\n| `SNOWFLAKE_ACCOUNT` | Your Snowflake account identifier |\n| `SNOWFLAKE_USER` | Your Snowflake username |\n| `SNOWFLAKE_PASSWORD` | Your Snowflake PAT |\n\n### Create the GitHub Actions Workflow\n\nLet's have CoCo write the workflow file. In the CoCo chat panel, enter:\n\n```\nCreate a GitHub Actions workflow at .github/workflows/pr-review.yml.\nTrigger on pull requests that touch dbt/models/** and also allow manual dispatch.\nGrant permissions: contents read and pull-requests write.\n\nFor the CoCo steps:\n- Configure a Snowflake connection by writing ~/.snowflake/connections.toml with a\n  [default] profile using keys account, user, and password sourced from the\n  SNOWFLAKE_ACCOUNT, SNOWFLAKE_USER, and SNOWFLAKE_PASSWORD secrets. Set file\n  permissions to 600.\n- Install the CoCo CLI:\n    curl -LsS https://ai.snowflake.com/static/cc-scripts/install.sh | sh\n  and add $HOME/.local/bin to PATH. No plugin install step is needed — the plugin\n  in .cortex/plugins/ is auto-discovered.\n- Run the dbt-review agent:\n    cortex --print \"Use the dbt-review agent to review the changes in this PR\" \\\n      \u003E review.md 2\u003E/dev/null || true\n\nPost the contents of review.md as a comment on the pull request.\n```\n\nReview the generated workflow and click \"Keep\" to accept/save the changes. Your workflow may be slightly different, and that's OK, but it should look something like this:\n\n\n```yaml\nname: dbt-review Agent PR Review\n\non:\n  pull_request:\n    paths:\n      - 'dbt/models/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\n\npermissions:\n  contents: read\n  pull-requests: write\n\njobs:\n  review:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v7\n        with:\n          fetch-depth: 0   # need base branch to diff changed files\n\n      - name: Configure Snowflake connection for Cortex Code\n        run: |\n          mkdir -p ~/.snowflake\n          cat \u003E ~/.snowflake/connections.toml \u003C\u003CEOF\n          [default]\n          account = \"${{ secrets.SNOWFLAKE_ACCOUNT }}\"\n          user = \"${{ secrets.SNOWFLAKE_USER }}\"\n          password = \"${{ secrets.SNOWFLAKE_PASSWORD }}\"\n          EOF\n          chmod 600 ~/.snowflake/connections.toml\n\n      - name: Install Cortex Code CLI\n        run: |\n          curl -LsS https://ai.snowflake.com/static/cc-scripts/install.sh | sh\n          echo \"$HOME/.local/bin\" \u003E\u003E \"$GITHUB_PATH\"\n\n      - name: Run Cortex Code and the dbt-review agent\n        run: |\n          cortex --print \"Use the dbt-review agent to review the changes in this PR\" \\\n            \u003E review.md 2\u003E/dev/null || true\n          echo \"----- review.md -----\"; cat review.md\n\n      - name: Post review as PR comment\n        uses: actions/github-script@v9\n        with:\n          script: |\n            const fs = require('fs');\n            let body = '## dbt-review Agent (Cortex Code)\\n\\n';\n            try { body += fs.readFileSync('review.md', 'utf8'); }\n            catch (e) { body += '_No review output produced._'; }\n            const issue_number = context.payload.pull_request?.number ?? context.issue.number;\n            if (!issue_number) {\n              console.log('No PR number found (workflow_dispatch run). Skipping comment.');\n              console.log(body);\n              return;\n            }\n            await github.rest.issues.createComment({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              issue_number,\n              body,\n            });\n```\n\nA few things worth noting. `fetch-depth: 0` is essential — the dbt-review agent uses `git diff origin/main...HEAD` to find changed files, which requires full history. The Snowflake connection is configured as a `connections.toml` file rather than environment variables — this is how the CoCo CLI picks up credentials. The plugin in `.cortex/plugins/` is auto-discovered by the CLI the same way it is by Desktop, so no install step is needed. And the intelligence lives entirely in the subagent definition, not in this workflow — the workflow is just infrastructure.\n\n### Enable GitHub Actions\n\nBy default, GitHub Actions workflows are disabled in forked repositories. Enable them by going to the **Actions** tab in your forked repository and clicking **I understand my workflows, go ahead and enable them**.\n\n![Activate GitHub Actions](https://www.snowflake.com/content/dam/snowflake-site/developers/guides/data-engineering-with-coco/github_actions_activate.png)\n\n\n### Test the Workflow\n\nCommit all the files you've created in this Guide to a new feature branch and push to GitHub using CoCo Desktop's built-in Source Control panel.\n\n**Create a new branch**\n\nClick the branch name in the bottom status bar (it will show `main` or whatever branch you're on). Select **Create new branch...** and enter `feature/add-coco-plugin`.\n\n**Stage and commit your changes**\n\nOpen the Source Control panel by clicking the Source Control icon in the Activity Bar on the left, or press `Cmd+Shift+G` (macOS) / `Ctrl+Shift+G` (Windows/Linux). You'll see all the files you've created listed under **Changes**.\n\nClick the **+** icon next to **Changes** to stage everything, then type a commit message in the input box at the top of the panel:\n\n```\nAdd AGENTS.md, custom skill, plugin, and CI workflow\n```\n\nClick the **Commit** button, or press `Cmd+Enter` / `Ctrl+Enter`.\n\n**Push and open a pull request**\n\nClick **Publish Branch** in the Source Control panel (or the sync icon in the status bar) to push `feature/add-coco-plugin` to your fork on GitHub.\n\nThen switch to GitHub in your browser and open a pull request from `feature/add-coco-plugin` to `main` in your forked repository. When creating the pull request, make sure the base repository is *your fork*, not the upstream Snowflake-Labs repository. GitHub defaults to comparing against the upstream, which you'll need to change.\n\nNavigate to the **Actions** tab to watch the workflow run. Once it completes, you'll see the dbt-review agent's PASS/FAIL report as output in the workflow logs. You will also see the agent's output in the PR itself as a comment.\n\n\u003C!-- ------------------------ --\u003E\n## Conclusion And Resources\n\nCongratulations! You've built a complete, professional-grade data engineering workflow with Cortex Code. Let's take a moment to look back at what you actually built — and more importantly, *why* each piece matters.\n\nYou started with an empty project and an AI coding agent. The first thing you did wasn't write a prompt — it was write an `AGENTS.md`. That single file changed the quality of every subsequent interaction. From there, you used the agent to add test coverage to existing models, then created a custom Skill that encoded your team's specific conventions. You immediately proved that Skill worked by using it to build a new model. Then you packaged that Skill — along with a production safety hook and a dbt review subagent — into a Plugin: a versioned, validatable, single-installable unit that can be shared across your entire team. And finally, you took that same subagent and wired it into GitHub Actions, so code review by your AI agent now happens automatically on every pull request.\n\nThat last part is the real payoff. The `dbt-review` subagent didn't get smarter when you moved it to CI/CD — it just became *consistent*. And consistency, at scale, is what separates a professional data engineering practice from a collection of one-off prompts.\n\n### What You Learned\n* How to use `AGENTS.md` to establish project-level context for every CoCo session\n* What agent Skills are, how they're structured, and how the `description` field drives automatic invocation\n* How to create a custom Skill that encodes team-specific conventions\n* What CoCo Plugins are and why they're the right packaging unit for sharing agent capabilities\n* How to add a `PreToolUse` hook to protect your production environment\n* How to define a subagent for autonomous, repeatable tasks\n* How to run a CoCo subagent from a GitHub Actions CI/CD pipeline\n\n### Related Resources\n* [Source Code on GitHub](https://github.com/Snowflake-Labs/sfguide-data-engineering-with-coco)\n* [Cortex Code documentation](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)\n* [CoCo Plugins reference](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code-plugins)\n* [CoCo Extensibility (Skills, Agents, Hooks, MCP)](https://docs.snowflake.com/en/user-guide/cortex-code/extensibility)\n* [Cortex Code for Data Engineers](https://jeremiahhansen.medium.com/cortex-code-for-data-engineers-8db01c77bf03) — companion blog post","multiValue":false,":type":"text/x-markdown"},"quickstartArticleLogoImage":{"dataType":"string","title":"Quickstart Article Logo Image","multiValue":false,":type":"text/plain"}},"elementsOrder":["quickstartArticleBody","quickstartArticleLogoImage"],":items":{},":itemsOrder":[],"isDeveloperGuidesPage":false,"model":"snowflake-site/models/quickstart-article"},"flexible_column_cont":{"id":"flexible-column-container-3836e22d26","type":"2-column-75-25","alignColumns":"top","containerMaxWidth":"extra-large","topPadding":"none","bottomPadding":"none","spaceBetween":"none","reverseOnMobile":false,"carouselOnMobile":false,"backgroundImageOption":"none","flexible_column_content_container_1":{"layout":"SIMPLE","id":"container-5e42bc8b9d",":type":"snowflake-site/components/flexible-column-container/flexible-column-content-container",":items":{"quickstart_last_modi":{"id":"quickstart-last-modified-56ea2d63e9","icon":{"id":"icon","icon":"calendar",":type":"snowflake-site/components/icon","appliedCssClassNames":"snowflake-icon-blue"},"lastModifiedDatePrefix":"Updated","lastModifiedDate":"2026-08-11",":type":"snowflake-site/components/quickstart/quickstart-last-modified","appliedCssClassNames":"snowflake-responsive-component-top-padding-small"},"text":{"id":"text-97dbf15ea1","additionalClasses":"qs-disclaimer-text","text":"\u003Cp\u003E\u003Cspan style=\"color: #666;\"\u003EThis content is provided as is, and is not maintained on an ongoing basis. It may be out of date with current Snowflake instances\u003C/span\u003E\u003C/p\u003E\r\n","richText":true,":type":"snowflake-site/components/text","appliedCssClassNames":"snowflake-responsive-component-top-padding-small"}},":itemsOrder":["quickstart_last_modi","text"]},"flexible_column_content_container_2":{"layout":"SIMPLE","id":"container-7aa96bfa38",":type":"snowflake-site/components/flexible-column-container/flexible-column-content-container",":items":{},":itemsOrder":[]},":type":"snowflake-site/components/flexible-column-container","isBlogPage":false,"isActiveTOC":false}},":itemsOrder":["contentfragment","flexible_column_cont"]},"flexible_column_content_container_2":{"layout":"SIMPLE","id":"container-a75857b61e",":type":"snowflake-site/components/flexible-column-container/flexible-column-content-container",":items":{"quickstart_table_of_":{"layout":"SIMPLE","id":"container-6b3f0954c9","isDeveloperGuidesPage":false,":type":"snowflake-site/components/quickstart/quickstart-table-of-content/quickstart-table-of-content-container",":items":{"quickstart_table_of_":{"id":"quickstart-table-of-content-c9dcbaadf7","headings":["\u003Ch2\u003EOverview\u003C/h2\u003E","\u003Ch2\u003ESetup\u003C/h2\u003E","\u003Ch2\u003EWhat is Cortex Code?\u003C/h2\u003E","\u003Ch2\u003ECreate an AGENTS.md\u003C/h2\u003E","\u003Ch2\u003EWhat is a Skill?\u003C/h2\u003E","\u003Ch2\u003EUsing CoCo Without a Skill\u003C/h2\u003E","\u003Ch2\u003ECreate a Custom Skill\u003C/h2\u003E","\u003Ch2\u003EWhat is a Plugin?\u003C/h2\u003E","\u003Ch2\u003ECreate a Custom Plugin\u003C/h2\u003E","\u003Ch2\u003EPublish to the Plugin Catalog\u003C/h2\u003E","\u003Ch2\u003EEnforce Standards Automatically in CI/CD\u003C/h2\u003E","\u003Ch2\u003EConclusion And Resources\u003C/h2\u003E"],"fragmentPath":"/content/dam/snowflake-site/en/content-fragments/quickstarts/data-engineering-with-coco",":type":"snowflake-site/components/quickstart/quickstart-table-of-content"},"quickstart_button":{"id":"quickstart-button-7b64cc301d","fragmentPath":"/content/dam/snowflake-site/en/content-fragments/quickstarts/data-engineering-with-coco",":type":"snowflake-site/components/quickstart/quickstart-button","appliedCssClassNames":"snowflake-responsive-component-top-padding-none"}},":itemsOrder":["quickstart_table_of_","quickstart_button"]}},":itemsOrder":["quickstart_table_of_"]},":type":"snowflake-site/components/flexible-column-container","isBlogPage":false,"isActiveTOC":false},"markup_editor":{"id":"markup-editor-f41dad25c7","title":"Page CSS","cssContent":"#quickstart-template-main-flexible-container{padding:24px}#quickstart-template-main-flexible-container \u003E .snowflake-flexible-column-container-items{grid-template-columns:1fr 0}.qs-disclaimer-text p \u003E span{font-size:15px !important}@media (min-width:768px){#quickstart-template-main-flexible-container{padding:24px 32px}#quickstart-template-main-flexible-container \u003E .snowflake-flexible-column-container-items{grid-template-columns:7fr 3fr;gap:48px}}@media (max-width:767px){#quickstart-template-main-flexible-container \u003E .snowflake-flexible-column-container-items{gap:0}}@media (min-width:1024px){#quickstart-template-main-flexible-container{padding:0 92px 48px 92px}#quickstart-template-main-flexible-container \u003E .snowflake-flexible-column-container-items{gap:117px}}",":type":"snowflake-site/components/markup-editor","isGSAPEnabled":false}},":itemsOrder":["quickstart_hero","flexible_column_cont","markup_editor"],":type":"wcm/foundation/components/responsivegrid"},"modal_container":{"layout":"SIMPLE","id":"container-517b7ee3f1",":type":"snowflake-site/components/modal/modal-container",":items":{},":itemsOrder":[]},"experiencefragment-footer":{"id":"experiencefragment-3340cfa949","localizedFragmentVariationPath":"/content/experience-fragments/snowflake-site/language-masters/en/site/footer/master/jcr:content","configured":true,":type":"snowflake-site/components/experiencefragment","xfModelPath":"/content/experience-fragments/snowflake-site/language-masters/en/site/footer/master.xfmodel.json"},"markup_editor":{"id":"markup-editor-99c826933e","title":"Quickstarts Overrides","cssContent":".snowflake-markdown blockquote{padding:24px 32px;background:#f6f9fa;border:1px solid #29b5e8;border-radius:16px}.snowflake-markdown .snowflake-image-container img{width:auto !important;max-width:100%}.snowflake-markdown .snowflake-text ol{padding-left:20px !important}.snowflake-markdown .snowflake-text li{margin:0 0 12px 0 !important}.snowflake-markdown h3.snowflake-markdown-h3{font-size:20px !important;font-family:Texta,sans-serif !important}@media (min-width:768px){.snowflake-markdown h3.snowflake-markdown-h3{font-size:28px !important}}",":type":"snowflake-site/components/markup-editor","isGSAPEnabled":false}},":itemsOrder":["experiencefragment-banner","experiencefragment-header","markup_editor_1950346551","responsivegrid","modal_container","experiencefragment-footer","markup_editor"],":type":"wcm/foundation/components/responsivegrid"}},":itemsOrder":["root"],":hierarchyType":"page",":path":"/content/snowflake-site/global/en/developers/guides/data-engineering-with-coco","analyticsDebugMode":false,"analyticsData":{"excludeFromAnalytics":false,"subCategory":"","pageType":"quickstart-page-template","templateName":"quickstart-page-template","siteName":"snowflake","pageUrl":"/content/snowflake-site/global/en/developers/guides/data-engineering-with-coco","language":"en","category":"general","pageName":"Data Engineering with CoCo","contentTags":["snowflake-site:taxonomy/solution-center/certification/quickstart","snowflake-site:taxonomy/product/ai","snowflake-site:taxonomy/solution-center/certification/community-sourced","snowflake-site:taxonomy/product/data-engineering","snowflake-site:taxonomy/snowflake-feature/coco"]},"isPasswordProtected":false,"analyticsEnabled":true,"coveoConfig":{"searchHub":"snowflake.com","organizationId":"snowflakecomputingproduction8neljofn","apiKey":"xx335921a6-2a0a-40f2-a167-e390b4766c3d","pipeline":"snowflake.com"},"analyticsContentTags":["snowflake-site:taxonomy/solution-center/certification/quickstart","snowflake-site:taxonomy/product/ai","snowflake-site:taxonomy/solution-center/certification/community-sourced","snowflake-site:taxonomy/product/data-engineering","snowflake-site:taxonomy/snowflake-feature/coco"],"locale":"en"}
  