Building a Production-Grade Coding Agent on Snowflake: From Trial Account to Enterprise Deployment Snowflake announced at Summit 2026 that the runtime powering its CoCo (Cortex Code) AI coding assistant is now deployable as a managed agent via the Cortex Agents REST API, defined declaratively with a single CREATE AGENT statement. The agent supports tools including Bash, file operations, SQL execution, Python 3.12 with PyPI access, web search, and a skills engine, all within a managed sandbox. However, execution via DATA_AGENT_RUN requires the Cortex Code entitlement, and trial accounts receive error 399504; the agent object can be created on any account, enabling deployment before the entitlement is available. At Snowflake Summit 2026, Snowflake announced a game-changing capability: the same runtime that powers CoCo Cortex Code — Snowflake’s AI coding assistant is now deployable as a managed agent via the Cortex Agents REST API. This means you can: The agent is defined declaratively — a single CREATE AGENT statement — and invoked via a REST API. Snowflake handles model routing, tool invocation, and result assembly. | Tool | Capability || --------------- | ------------------------------------- || Bash | Execute shell commands || Read/Write/Edit | File operations on mounted workspaces || Grep/Glob | Search files and patterns || SQL Exec | Query Snowflake directly || Python 3.12 | Full sandbox with pip access PyPI || Web Search | Find documentation and references || Skills Engine | Extend with custom domain skills | All running inside a managed sandbox — no infrastructure to maintain, no data leaving your governance boundary. Here’s what the announcement didn’t address: code toolset all execution via DATA AGENT RUN requires the Cortex Code entitlement. Trial accounts get error 399504: { "message": "Cortex Code CLI is not enabled or the usage limit has been reached.", "code": "399504"} But here’s the insight: the agent object can be created on any account . Only execution is gated. This means you can deploy the entire architecture today and activate it instantly when the entitlement becomes available. -- Dedicated database for all agent objectsCREATE DATABASE IF NOT EXISTS CORTEX AGENTS;CREATE SCHEMA IF NOT EXISTS CORTEX AGENTS.CODING AGENT;-- XS warehouse - compute happens inside the managed sandboxCREATE WAREHOUSE IF NOT EXISTS CODING AGENT WH WAREHOUSE SIZE = 'X-SMALL' AUTO SUSPEND = 60 AUTO RESUME = TRUE;-- Stage for custom skillsCREATE STAGE IF NOT EXISTS CORTEX AGENTS.CODING AGENT.SKILL STAGE DIRECTORY = ENABLE = TRUE ;-- PyPI access for the sandboxGRANT DATABASE ROLE SNOWFLAKE.PYPI REPOSITORY USER TO ROLE ACCOUNTADMIN; ACCOUNTADMIN └── CODING AGENT ADMIN manages lifecycle, versions, skills └── CODING AGENT DEVELOPER modifies spec, deploys candidates └── CODING AGENT CONSUMER invokes agent only CREATE ROLE IF NOT EXISTS CODING AGENT ADMIN;CREATE ROLE IF NOT EXISTS CODING AGENT DEVELOPER;CREATE ROLE IF NOT EXISTS CODING AGENT CONSUMER;GRANT ROLE CODING AGENT CONSUMER TO ROLE CODING AGENT DEVELOPER;GRANT ROLE CODING AGENT DEVELOPER TO ROLE CODING AGENT ADMIN;GRANT ROLE CODING AGENT ADMIN TO ROLE ACCOUNTADMIN;-- Consumer can invoke but never modifyGRANT CREATE AGENT ON SCHEMA CORTEX AGENTS.CODING AGENT TO ROLE CODING AGENT ADMIN; Workspaces provide persistent file storage that the agent sandbox can mount: CREATE WORKSPACE IF NOT EXISTS CORTEX AGENTS.CODING AGENT.AGENT WORKSPACE COMMENT = 'Persistent workspace for agent file operations';CREATE WORKSPACE IF NOT EXISTS CORTEX AGENTS.CODING AGENT.SHARED DATA COMMENT = 'Shared reference data'; The agent sees these as /workspace and /data — standard filesystem paths. CREATE OR REPLACE AGENT CORTEX AGENTS.CODING AGENT.PRODUCTION CODING AGENT COMMENT = 'Production Coding Agent - full CoCo runtime' FROM SPECIFICATION$$models: orchestration: claude-sonnet-4-5instructions: system: | You are a production data engineering assistant deployed inside Snowflake. Safety Rules NEVER violate : - NEVER execute DROP, TRUNCATE, or DELETE without explicit confirmation - NEVER modify user credentials ALTER USER, GRANT, REVOKE - NEVER access databases/schemas outside authorized scope - NEVER output raw credentials or secrets Operational Rules: - Always validate SQL before executing - Write outputs to /workspace for persistence - Use LIMIT clauses on exploratory queries - When errors occur, explain root cause and suggest fixtools: - tool spec: type: code toolset all name: code toolset alltool resources: code toolset all: permission policy: type: always allow workspace mounts: - name: "CORTEX AGENTS.CODING AGENT.AGENT WORKSPACE" type: workspace mount path: "/workspace" - name: "CORTEX AGENTS.CODING AGENT.SHARED DATA" type: workspace mount path: "/data" artifact repositories: - SNOWFLAKE.SNOWPARK.PYPI SHARED REPOSITORY$$; Key configuration choices: | Parameter | Choice | Rationale || --------------------- | ----------------- | ---------------------------------------------- || orchestration | claude-sonnet-4-5 | Best speed/quality for coding tasks || permission policy | always allow | No human gate for automated workflows || workspace mounts | 2 mounts | Separate working directory from read-only data || artifact repositories | PyPI shared | Enables pip install in the sandbox | For interactive use, create a second variant with always ask that requests permission before state changes. These Snowpark procedures are the foundation. They work on ALL accounts: CREATE OR REPLACE PROCEDURE EXECUTE PYTHON code VARCHAR RETURNS VARCHAR LANGUAGE PYTHON RUNTIME VERSION = '3.11'PACKAGES = 'snowflake-snowpark-python' HANDLER = 'execute'AS $$import sysfrom io import StringIOdef execute session, code : old stdout = sys.stdout sys.stdout = buffer = StringIO local vars = {'session': session} try: exec code, {}, local vars output = buffer.getvalue if not output and 'result' in local vars: output = str local vars 'result' return output if output else " no output " except Exception as e: return f"ERROR {type e . name } : {str e }" finally: sys.stdout = old stdout$$; CREATE OR REPLACE PROCEDURE PROFILE TABLE table fqn VARCHAR RETURNS VARCHAR LANGUAGE PYTHON RUNTIME VERSION = '3.11'PACKAGES = 'snowflake-snowpark-python' HANDLER = 'profile'AS $$def profile session, table fqn : df = session.table table fqn row count = df.count fields = df.schema.fields Returns: row count, column types, null rates, cardinality, and sample data first 5 rows ...$$; CREATE OR REPLACE PROCEDURE VALIDATE SQL sql text VARCHAR RETURNS VARCHAR LANGUAGE PYTHON RUNTIME VERSION = '3.11'PACKAGES = 'snowflake-snowpark-python' HANDLER = 'validate'AS $$import reBLOCKED PATTERNS = r"\bINSERT\b", "INSERT blocked - read-only mode" , r"\bUPDATE\b", "UPDATE blocked - read-only mode" , r"\bDELETE\b", "DELETE blocked - read-only mode" , r"\bCREATE\b", "CREATE blocked - read-only mode" , r"\bALTER\b", "ALTER blocked - read-only mode" , r"\bDROP\b", "DROP blocked - read-only mode" , r"\bGRANT\b", "GRANT blocked - read-only mode" , r"\bREVOKE\b", "REVOKE blocked - read-only mode" , r"\bCOPY\s+INTO\b", "COPY INTO blocked - read-only mode" , r"\bEXECUTE\b", "EXECUTE blocked - read-only mode" , r"\bSYSTEM\$", "System functions blocked - read-only mode" , r"\bUSE\s+ROLE\b", "USE ROLE blocked - read-only mode" , ... more patterns def validate session, sql text : for pattern, msg in BLOCKED PATTERNS: if re.search pattern, sql text.upper , re.IGNORECASE : return f"BLOCKED: {msg}" return "PASS"$$; | | Procedure | Purpose | Verified || -: | ------------------------------------- | -------------------------------------- | -------- || 1 | EXECUTE PYTHON code | Run arbitrary Python | Yes || 2 | PROFILE TABLE table | Schema, nulls, cardinality, and sample | Yes || 3 | EXECUTE SQL sql, max rows | Formatted tabular output | Yes || 4 | TRANSFORM AND LOAD sql, target, mode | ETL pipeline | Yes || 5 | EXPORT TO STAGE sql, path, format | Export CSV/JSON to stage | Yes || 6 | COMPARE TABLES table list | Multi-table comparison | Yes || 7 | VALIDATE SQL sql | Read-only guardrails | Yes | Since trial accounts block all Snowflake LLM functions CORTEX.COMPLETE, DATA AGENT RUN , we use Groq's free API for reasoning and Snowflake for execution. User: "What are the top 5 customers by order value?" │ ▼ Groq LLM Llama 3.3 70B reasons and plans │ Returns: {"action": "execute sql", "sql": "SELECT C NAME..."} │ ▼ Client-side guardrails check read-only patterns │ ▼ Snowflake executes: CALL EXECUTE SQL 'SELECT C NAME...' │ Returns: formatted results │ ▼ Groq LLM analyzes results │ Needs more data? → loop back. Has answer? → respond. │ ▼ Final answer to user The hybrid agent isn’t a toy. It includes: python class HybridCodingAgent: def init self, groq api key, snowflake config : self.audit = AuditLogger Structured event trail self.reasoner = GroqReasoner ... Token tracking + pruning self.executor = SnowflakeExecutor ... Retry + health check | Feature | Implementation || ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- || Retry with backoff | 3 retries with exponential backoff 2s, 4s, 8s for both Groq and Snowflake || Conversation pruning | Caps conversation at 20 messages while retaining the system prompt and latest messages || Token budget | 50K tokens per session; blocks further API calls when the limit is exceeded || SQL guardrails | Development mode allows CREATE , INSERT , UPDATE , and DELETE with WHERE clause ; blocks destructive operations such as DROP , TRUNCATE , and unrestricted DELETE / UPDATE || Connection health check | Verifies Snowflake connectivity and required stored procedures during application startup || Audit logger | Logs every action, error, and guardrail event with timestamps || Rate limit handling | Detects Groq HTTP 429 responses, waits using exponential backoff, and retries automatically || Graceful degradation | Handles partial failures gracefully without terminating the user session | | Attribute | Value || --------- | -------------------------------------------------------------- || Free tier | 30 requests/minute, no credit card required || Speed | Less than 500 ms response time custom LPU hardware || Model | Llama 3.3 70B – versatile and code-aware || API Key | https://console.groq.com/keys https://console.groq.com/keys | pip install groq snowflake-connector-pythonexport GROQ API KEY='gsk ...'export SNOWFLAKE ACCOUNT='FQDRZOE-SD47007' org-account formatexport SNOWFLAKE USER='SATISH'export SNOWFLAKE PASSWORD='...' python groq hybrid agent.py ============================================================ HYBRID CODING AGENT Production Groq LLM reasoning + Snowflake execution Type 'quit' to exit, 'reset' to clear, 'audit' for stats============================================================ Snowflake: connected CZ04821, ACCOUNTADMIN Procedures: available Groq model: llama-3.3-70b-versatile Token budget: 50,000 Profile the ORDERS table --- Iteration 1 tokens: 1,247/50,000 ---AGENT: {"action": "profile table", "table": "SNOWFLAKE SAMPLE DATA.TPCH SF1.ORDERS"} RESULT: Total Rows: 1,500,000 | Columns: 9 | ... --- Iteration 2 tokens: 3,891/50,000 ---FINAL ANSWER:The ORDERS table has 1,500,000 rows with 9 columns:- O ORDERKEY: 1.5M distinct primary key - O CUSTKEY: 99,996 distinct customers- O ORDERSTATUS: 3 values F, O, P - O TOTALPRICE: range $857 to $555,285- O ORDERDATE: 2,406 distinct dates 1992-2998 ... A full-featured chat interface that brings it all together: | Feature | Description || ------------------- | ------------------------------------------------------------------------------- || Chat interface | st.chat input and st.chat message with full conversation history || Agent trace | Expandable execution steps showing action, parameters, result, and duration || Guardrail banners | Warning banner displayed when SQL execution is blocked || Token budget meter | Visual progress bar with threshold warnings || Quick actions | One-click buttons to trigger predefined agent actions || Health indicators | Status indicators for Groq and Snowflake connectivity || Export session | Download complete conversation history and execution traces as JSON || Auto-reconnect | Automatically retries Snowflake connection failures || Rate limit handling | Displays a waiting message and automatically retries on Groq HTTP 429 responses | pip install streamlit groq snowflake-connector-pythonexport GROQ API KEY='gsk ...'export SNOWFLAKE ACCOUNT='FQDRZOE-SD47007'export SNOWFLAKE USER='SATISH'export SNOWFLAKE PASSWORD='...' streamlit run streamlit groq app.py Open http://localhost:8501 — you'll see the chat interface with sidebar controls. The sidebar has quick action buttons that execute immediately on click — no second step needed: if st.button "📊 Profile ORDERS", use container width=True : st.session state.messages.append {"role": "user", "content": "Profile ORDERS"} st.session state.trigger agent = True st.rerun Immediately triggers agent execution Since this is a coding agent for developers , the guardrails are tuned for a DEV environment — allowing developers to build and iterate while preventing destructive or privilege-escalation operations. A coding agent needs to create things . Blocking all DML/DDL would make it useless for development. Instead, we protect against: DANGEROUS SQL PATTERNS = --- DESTRUCTIVE OPS blocked even in dev --- r"\bDROP\s+ DATABASE|SCHEMA \b", "DROP DATABASE/SCHEMA blocked — too destructive" , r"\bTRUNCATE\b", "TRUNCATE blocked — use DELETE WHERE instead" , r"\bDELETE\b ? . \bWHERE\b ", "DELETE without WHERE blocked" , r"\bUPDATE\b ? . \bWHERE\b ", "UPDATE without WHERE blocked" , --- PRIVILEGE ESCALATION never allowed --- r"\bGRANT\b", "GRANT blocked - request via admin role" , r"\bREVOKE\b", "REVOKE blocked - request via admin role" , r"\bCREATE\s+USER\b", "CREATE USER blocked - admin only" , r"\bALTER\s+USER\b", "ALTER USER blocked - admin only" , r"\bCREATE\s+ROLE\b", "CREATE ROLE blocked - admin only" , r"\bALTER\s+ROLE\b", "ALTER ROLE blocked - admin only" , --- ACCOUNT/ORG LEVEL never allowed --- r"\bALTER\s+ACCOUNT\b", "ALTER ACCOUNT blocked - org admin only" , r"\bALTER\s+WAREHOUSE\b. \b SUSPEND|RESUME \b", "Warehouse SUSPEND/RESUME blocked" , --- DATA EXFILTRATION never allowed --- r"\bCOPY\s+INTO\b. 's3://", "COPY to external S3 blocked" , r"\bCOPY\s+INTO\b. 'gcs://", "COPY to external GCS blocked" , r"\bCOPY\s+INTO\b. 'azure://", "COPY to external Azure blocked" , --- SECURITY/NETWORK never allowed --- r"\bCREATE\s+. \bNETWORK\s+RULE\b", "Network rule creation blocked" , r"\bCREATE\s+. \bSECRET\b", "Secret creation blocked" , --- PRODUCTION SCHEMA PROTECTION --- r"\b INSERT|UPDATE|DELETE|DROP|ALTER|CREATE \b. \bSNOWFLAKE SAMPLE DATA\b", "SNOWFLAKE SAMPLE DATA is read-only - use CORTEX AGENTS schema" , CALL CORTEX AGENTS.CODING AGENT.VALIDATE SQL 'DROP DATABASE PRODUCTION' ;-- Returns: BLOCKED: DROP DATABASE/SCHEMA blockedCALL CORTEX AGENTS.CODING AGENT.VALIDATE SQL 'CREATE TABLE CORTEX AGENTS.CODING AGENT.MY TEST AS SELECT 1' ;-- Returns: PASSCALL CORTEX AGENTS.CODING AGENT.VALIDATE SQL 'DELETE FROM MY TABLE' ;-- Returns: BLOCKED: DELETE without WHERE blocked | Operation | Allowed | Rationale ||-----------|---------|-----------|| SELECT , SHOW , DESCRIBE | Yes | Read-only operations || CREATE TABLE , CREATE VIEW | Yes | Create development objects || CREATE OR REPLACE | Yes | Iterate on object definitions || INSERT INTO | Yes | Load test or development data || UPDATE ... WHERE ... | Yes | Modify specific rows only || DELETE ... WHERE ... | Yes | Remove specific rows only || DROP TABLE , DROP VIEW | Yes | Clean up development objects || USE DATABASE , USE SCHEMA | Yes | Navigate databases and schemas || CREATE TABLE AS SELECT CTAS | Yes | Materialize query results || COPY INTO @internal stage | Yes | Export data to internal Snowflake stages || DROP DATABASE , DROP SCHEMA | No | Too destructive, even in development || TRUNCATE | No | Use DELETE ... WHERE ... instead || DELETE without WHERE | No | Requires a WHERE clause || UPDATE without WHERE | No | Requires a WHERE clause || GRANT , REVOKE | No | Prevent privilege escalation || ALTER USER , ALTER ROLE | No | Administrative operations only || COPY to Amazon S3, Google Cloud Storage, or Azure Blob Storage | No | Prevent data exfiltration || Modify SNOWFLAKE SAMPLE DATA | No | Protect reference datasets || Network rules, secrets, and security integrations | No | Infrastructure team responsibility | Even if the LLM generates a blocked operation, it shows a clear warning explaining why it was blocked and what to do instead . Agent specs evolve. Use ALTER AGENT to deploy updates: ALTER AGENT PRODUCTION CODING AGENT MODIFY LIVE VERSION SET SPECIFICATION $$ models: orchestration: claude-opus-4-6 -- Upgraded model ... $$; The Versioning UI Public Preview in Snowsight lets you compare versions side-by-side, rollback with one click, and promote candidates. -- Procedure usage by typeSELECT CASE WHEN query text ILIKE '%EXECUTE PYTHON%' THEN 'EXECUTE PYTHON' WHEN query text ILIKE '%PROFILE TABLE%' THEN 'PROFILE TABLE' WHEN query text ILIKE '%EXECUTE SQL%' THEN 'EXECUTE SQL' WHEN query text ILIKE '%VALIDATE SQL%' THEN 'VALIDATE SQL' ELSE 'OTHER' END AS procedure name, COUNT AS calls, AVG DATEDIFF 'second', start time, end time AS avg secFROM SNOWFLAKE.ACCOUNT USAGE.QUERY HISTORYWHERE query text ILIKE '%CORTEX AGENTS.CODING AGENT.%' AND start time = DATEADD 'day', -7, CURRENT TIMESTAMP GROUP BY 1 ORDER BY calls DESC;-- Guardrail block rateSELECT DATE TRUNC 'day', start time AS day, COUNT AS total validate calls, COUNT IF query text ILIKE '%BLOCKED%' AS blocked count, ROUND blocked count / NULLIF total validate calls, 0 100, 2 AS block rate pctFROM SNOWFLAKE.ACCOUNT USAGE.QUERY HISTORYWHERE query text ILIKE '%VALIDATE SQL%' AND start time = DATEADD 'day', -30, CURRENT TIMESTAMP GROUP BY 1 ORDER BY 1 DESC; ┌─────────────────────────────────────────────────────────┐│ TRIAL ACCOUNT what works today : ││ ✅ Agent objects created, versioned, ready ││ ✅ 7 Snowpark procedures full execution layer ││ ✅ VALIDATE SQL guardrail server-side ││ ✅ Groq Hybrid Agent CLI + Streamlit UI ││ ✅ Workspaces, stages, RBAC, cost controls ││ ❌ DATA AGENT RUN error 399504 ││ ❌ CORTEX.COMPLETE blocked ││ ❌ External access integrations │├─────────────────────────────────────────────────────────┤│ PAID ACCOUNT after upgrade : ││ ✅ Everything above, PLUS: ││ ✅ DATA AGENT RUN full managed CoCo runtime ││ ✅ REST API + SDK + Async execution ││ ✅ External access GitHub, etc. ││ ✅ Streaming responses, multi-turn sessions ││ ││ UPGRADE REQUIRES: ZERO REDEPLOYMENT ││ Agents are already created and waiting. │└─────────────────────────────────────────────────────────┘ When your account gets the Cortex Code entitlement: CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION github integration ALLOWED NETWORK RULES = CORTEX AGENTS.CODING AGENT.github access rule ENABLED = TRUE; 3. Verify agent runtime : SELECT SNOWFLAKE.CORTEX.DATA AGENT RUN 'CORTEX AGENTS.CODING AGENT.PRODUCTION CODING AGENT', '{"messages": {"role": "user", "content": {"type": "text", "text": "Reply: AGENT OK"} } }' ; -- Should return "AGENT OK" instead of error 399504 4. Switch clients from Groq hybrid to native REST API/SDK 5. Fallback procedures remain as backup | Feature | Status | Impact on This Architecture ||---------|--------|-----------------------------|| Skills Package | Preview Soon | Package custom skills as a single reusable URI || Agent Toolset | Preview Soon | Reuse tools across multiple agents without duplication || Tool Search | Preview Soon | Progressive tool discovery instead of loading all tools upfront || Async Agent API | GA Soon | Enable background execution for long-running tasks || Code Execution Tool | Preview Soon | Sandboxed Python execution with PDF and chart generation || Interrupt and Resume | GA Soon | Pause, modify, and continue agent workflows || Partial Access | Preview Soon | Support multiple permission levels for a single agent based on role || Versioning UI | Public Preview | Visual comparison of skill and agent versions in Snowsight |Our architecture supports all of these. The foundation is ready. Agent objects, RBAC, workspaces, procedures — all deployed on trial. When the entitlement activates: zero redeployment. The agent should NEVER modify production data without explicit override. 25+ regex patterns at two layers ensure this. Free, fast, no credit card. The hybrid pattern keeps data inside Snowflake while reasoning happens externally. Every action, every blocked query, every token spent — logged and queryable. In production: “What did the agent do at 3am?” Track usage, prune conversations, cap sessions. A runaway agent loop can burn through limits fast. Quick actions should trigger immediately. Users expect instant feedback from AI interfaces. cortex-coding-agent/ 22 files, ~4,500 lines├── 01-infrastructure/ Database, RBAC, network├── 02-agent/ CREATE AGENT + workspaces + versioning├── 03-skills/ Custom skill templates├── 04-client-integration/│ ├── groq hybrid agent.py ★ Production CLI agent 555 lines │ ├── streamlit groq app.py ★ Chat UI with trace 431 lines │ ├── rest api example.py REST client paid accounts │ ├── sdk example.py SDK client paid accounts │ └── async example.py Async pattern paid accounts ├── 05-operations/ Monitoring + guardrail tracking├── 06-deployment/ Checklist + CI/CD└── 07-fallback-trial/ 7 procedures + full test suite 1. Run infrastructure SQL in Snowflake 5 min 2. Deploy procedures 2 min 3. Set up locally:pip install groq snowflake-connector-python streamlitexport GROQ API KEY='gsk ...' Free from console.groq.com/keysexport SNOWFLAKE ACCOUNT='YOUR ORG-YOUR ACCOUNT'export SNOWFLAKE USER='YOUR USER'export SNOWFLAKE PASSWORD='YOUR PASSWORD' 4. Run Streamlit UI:streamlit run streamlit groq app.py 5. Or CLI mode:python groq hybrid agent.py "Profile the ORDERS table" The agent reasons, executes, and answers — all within your data governance boundary. No data leaves Snowflake. The LLM only sees query results, never raw data. Youtube Demo : Implementation verified on Snowflake account FQDRZOE-SD47007 July 22, 2026 . Groq hybrid agent tested with Llama 3.3 70B. All procedures and guardrails passing. Full source code in the Github cortex-coding-agent project. This article represents the author’s personal views and experience, not those of any employer. 👏 Clap if it added value 🔗 Share it with your team ➕ Follow for more 📘 Medium: Satish Kumar https://medium.com/u/d170d49944ec 🔗 LinkedIn: satishkumar-snowflake https://www.linkedin.com/in/satishkumar-snowflake/ Stay tuned for the next one 👋 Building a Production-Grade Coding Agent on Snowflake: From Trial Account to Enterprise Deployment https://pub.towardsai.net/building-a-production-grade-coding-agent-on-snowflake-from-trial-account-to-enterprise-deployment-b038ddd6741e was originally published in Towards AI https://pub.towardsai.net on Medium, where people are continuing the conversation by highlighting and responding to this story.