An interactive art installation for tech conferences β draw a bird, let Snowflake Cortex AI animate it, and watch it fly across the big screen!
- A booth volunteer types
birdsin a terminal (an alias for./start-workshop.sh, installed bysetup-laptop.sh) - The attendee types
$bird-workshopto activate the workshop skill - The skill guides them through five phases:
- Draw a bird in a browser canvas that auto-opens on the booth laptop
- Describe how it should fly
- Snowflake Cortex generates a Bird Passport + CSS flight animation via
CORTEX.COMPLETE()(mistral-large2) - The bird gets INSERT'd into a Snowflake table and appears on the live projected display
Throughout the flow, the agent narrates what's happening β so attendees walk away understanding Cortex Code, MCP tool use, Snowflake Cortex, and Snowflake itself.
- Snowflake account with Cortex AI enabled (specifically
mistral-large2) - Cortex Code CLI (
cortex) installed - Snowflake CLI (
snow) installed βbrew install snowflake-cliorpipx install snowflake-cli - Node.js 18+ (for the MCP server / canvas)
setup-laptop.sh writes the Snowflake connection config for you β you don't need to run snow connection add manually.
snow sql -f setup.sql # as ACCOUNTADMIN β creates warehouse, DB, FLOCK table, DATA_BIRDS_USER, registers public keygit clone https://github.com/YOUR_ORG/SnowBirds && cd SnowBirds
./setup-laptop.shsetup-laptop.sh does five things:
- Adds a
databirdsconnection to~/.snowflake/config.toml(keypair auth pointing atDATA_BIRDS_USER) - Creates
.envfrom.env.example - Installs MCP server dependencies and registers the
birdsMCP server withcortex - Pre-approves the workshop's MCP tools in
~/.snowflake/cortex/permissions.jsonso attendees never see permission prompts forstart_canvas,push_to_flock, etc. - Adds shell aliases:
birdsfor attendee sessions andbigscreenfor the projected display
Open a new terminal (so the alias loads) and you're done.
birdsWhen cortex opens, the attendee types $bird-workshop to activate the skill. The browser canvas auto-opens during Phase 2 β no URL clicking needed.
For the projected display, run this in a separate terminal:
bigscreenThat serves index.html locally and opens the live display in the browser. It continuously syncs manifest.json from Snowflake, so a single master display laptop can show birds submitted from all attendee laptops.
That's it. rsa_key.p8 is distributed out-of-band (1Password / encrypted Slack / USB at the booth) and dropped into the repo root before running setup-laptop.sh β it is not committed. See "Rotating the booth keypair" below.
setup-laptop.shβ one-time per laptop. Snowflake connection, MCP registration, pre-approvals, shell aliases.start-workshop.shβ what thebirdsalias runs. Launchescortex --allowed-tools ...with a scoped allowlist: the 5 workshop MCP tools,Read, and safe Bash patterns (ls,cat,grep,find,head,tail). Anything outside the list triggers a normal approval prompt β which is your signal the agent drifted off the skill's intended path.start-display.shβ what thebigscreenalias runs. Serves the live projected display fromindex.html.setup-mcp.shβ legacy. MCP-only registration. Usesetup-laptop.shinstead.
Every booth laptop authenticates as the same DATA_BIRDS_USER via the same RSA private key. No password (no rotation drift, no password-policy rejections), no browser flow (no per-attendee OAuth popups), no MFA prompts. Combined with the --allowed-tools allowlist and the pre-approved MCP cache, attendees should see zero permission prompts during a normal workshop run.
rsa_key.p8 / rsa_key.pub are git-ignored β they must never be committed. The private key is distributed out-of-band to each booth laptop. After each event:
# 1. Generate a fresh keypair (writes into the repo root; both files are git-ignored)
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt
openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub
# 2. Copy the new public key body (between BEGIN/END PUBLIC KEY, no newlines)
# into setup.sql's ALTER USER ... SET RSA_PUBLIC_KEY = '...'
# 3. Push the new key to Snowflake (zero-downtime β Snowflake supports two active
# public keys per user via RSA_PUBLIC_KEY + RSA_PUBLIC_KEY_2)
snow sql -f setup.sql
# 4. Commit ONLY setup.sql β never rsa_key.p8 or rsa_key.pub.
git add setup.sql && git commit -m "Rotate booth keypair"
# 5. Re-distribute the new rsa_key.p8 to each booth laptop via 1Password / encrypted
# Slack DM / USB. Do NOT email, do NOT commit, do NOT paste into a public channel.To fully invalidate a compromised key immediately:
snow sql -c <admin-conn> -q "ALTER USER DATA_BIRDS_USER UNSET RSA_PUBLIC_KEY; ALTER USER DATA_BIRDS_USER UNSET RSA_PUBLIC_KEY_2;"Then generate + install a new keypair as above.
SnowBirds/
βββ .cortex/ β Cortex Code CLI project config
β βββ skills/
β β βββ bird-workshop/
β β βββ SKILL.md β 5-phase workshop instructions
β βββ mcp-server/
β βββ server.js β MCP server (canvas, Cortex AI, Snowflake)
β βββ canvas-server.js β Local drawing canvas web server
β βββ canvas.html β Browser-based drawing interface
β βββ bird-processor.js β Background removal (sharp)
β βββ snowflake-client.js β Snow CLI wrapper for CORTEX.COMPLETE() + FLOCK ops
βββ setup-laptop.sh β Per-laptop booth setup (one-time)
βββ start-workshop.sh β Per-attendee launcher (what the `cortex` alias runs)
βββ setup-mcp.sh β (legacy) MCP-only registration
βββ setup.sql β Snowflake environment setup (one-time per account)
βββ rsa_key.p8 β Booth private key (git-ignored; distributed out-of-band)
βββ rsa_key.pub β Booth public key (git-ignored; canonical copy lives in setup.sql)
βββ index.html β Live projected display (reads manifest.json)
βββ manifest.json β Display cache, synced from Snowflake by bigscreen
βββ sync-display-manifest.py β Polls Snowflake FLOCK table for the display
βββ birds/ β Submitted bird images
βββ .env.example β Environment variable template
βββ .mcp.json β MCP server registration for the cortex CLI
FLOCKtable β Every bird is a row with AI-generated fields (species, personality, flight animation)FLOCK_STATSdynamic table β Real-time aggregation of flock statisticsHOURLY_SUBMISSIONSdynamic table β Hourly aggregates for forecasting / anomaly detectionCORTEX.COMPLETE()β Callsmistral-large2to generate bird data + CSS animation- Keypair auth β
DATA_BIRDS_USERauthenticates via RSA private key; no passwords, no MFA, no OAuth flow
Forked from MLH/BirdsBirdBirds (gemini-cli-skill branch by Jon).
Adapted for Snowflake Cortex by the team.
made with β₯ and βοΈ