PluginBench
Skill
Pass
Audit score 90

setup-python-tools

cognitedata/builder-skills

Add client-side Python execution to Atlas Chat agents using Pyodide.

What is setup-python-tools?

Integrates Pyodide (v0.29.3) into an Atlas Chat UI to enable client-side Python tool execution for agents. Use this when your CDF agent config includes Python tools and you want to run them in the browser rather than server-side.

  • Loads and caches Pyodide (~30MB) for in-browser Python execution
  • Automatically fetches and runs Python tool code from agent CDF config
  • Provides usePyodideRuntime hook to manage initialization, loading state, and error handling
  • Supports optional package installation (pandas, numpy, etc.) during setup
  • Disables chat input during Python runtime initialization to prevent premature messages

How to install setup-python-tools

npx skills add https://github.com/cognitedata/builder-skills --skill setup-python-tools
Prerequisites
  • Existing `src/atlas-agent/` directory from integrate-atlas-chat skill
  • @sinclair/typebox package (should be installed from integrate-atlas-chat)
  • Copy of python.ts, pyodide.ts, pyodide-react.ts, pyodide-runtime.ts from integrate-atlas-chat/code/
  • CDF agent with Python tools already defined in agent config
Claude Code
Cursor
Windsurf
Cline

How to use setup-python-tools

  1. 1.Read package.json and the component calling useAtlasChat to understand current setup
  2. 2.Install pyodide@0.29.3 using your app's package manager (pnpm/npm/yarn)
  3. 3.Import usePyodideRuntime and loadPyodide, then initialize the hook with loadPyodide, client SDK, and optional requirements array
  4. 4.Add loading/error UI above the chat input to show Pyodide initialization progress
  5. 5.Pass pythonRuntime from usePyodideRuntime to useAtlasChat config (no separate tool declarations needed)
  6. 6.Disable chat input and suggestion chips while pythonLoading is true to prevent premature messages

Use cases

Good for
  • Running data analysis Python tools (pandas, numpy) client-side without server round-trips
  • Executing agent-defined Python tools that process CDF data in the browser
  • Building chat interfaces where Python computation happens locally for faster feedback
  • Reducing server load by offloading Python tool execution to client browsers
  • Displaying Python initialization progress to users during first load (~30-60s)
Who it's for
  • Frontend engineers building Atlas Chat applications with Python tools
  • Teams using Cognite Data Fusion agents that include Python tool definitions
  • Developers wanting to reduce server-side Python execution overhead
  • Product teams prioritizing client-side computation for data analysis workflows

setup-python-tools FAQ

Do I need to declare Python tools to the agent separately?

No. Python tools are already defined in your CDF agent config. The library fetches and executes them automatically when the agent calls them.

How long does Pyodide take to load?

First load is ~30-60 seconds (downloads ~30MB). Subsequent loads are <2 seconds from browser cache.

What version of Pyodide should I install?

Exactly pyodide@0.29.3. Installing a different version will cause runtime errors because the CDN artifacts must match.

Can I add extra Python packages beyond what the agent defines?

Yes. Pass a requirements array to usePyodideRuntime (e.g., ['pandas', 'numpy']) to install additional packages during initialization.

What if Python runtime initialization fails?

The pythonError field will contain an error message. Display it in the UI and optionally provide a retry mechanism or fallback to server-side execution.

Full instructions (SKILL.md)

Source of truth, from cognitedata/builder-skills.


name: setup-python-tools description: "Pyodide Python tools for an already-approved in-app useAtlasChat UI. EOS sidebar Python tools run from agent CDF config — do not vendor Pyodide. Triggers: Pyodide, pythonRuntime, usePyodideRuntime, runPythonCode." allowed-tools: Read, Glob, Grep, Edit, Write, Bash metadata: argument-hint: "[tool-names or agent-external-id]"

Set Up Python Tool Execution

Add client-side Pyodide execution for $ARGUMENTS. Skip this if the app uses the Atlas / EOS sidebar (integrate-fusion-agent).

Prerequisite: src/atlas-agent/ from integrate-atlas-chat, plus @sinclair/typebox. Copy python.ts, pyodide.ts, pyodide-react.ts, pyodide-runtime.ts from integrate-atlas-chat/code/ into src/atlas-agent/.

CDF runPythonCode tools arrive as toolConfirmation + clientTool. Wire usePyodideRuntime and pass pythonRuntime to useAtlasChat — no PythonToolConfig entries. Pyodide is ~30MB, cached after first load.


Step 1 — Understand the app

Read these files before touching anything:

  • package.json — detect package manager and existing deps
  • The component that calls useAtlasChat — understand current tools/config

Step 2 — Install Pyodide

Install exactly pyodide@0.29.3 using the app's package manager. This version must match the CDN artifacts loaded at runtime — installing a different version will cause errors.

  • pnpm → pnpm add pyodide@0.29.3
  • npm → npm install pyodide@0.29.3
  • yarn → yarn add pyodide@0.29.3

@sinclair/typebox should already be installed from integrate-atlas-chat. Add it if missing.


Step 3 — Set up usePyodideRuntime

In the component that calls useAtlasChat, add the Pyodide runtime hook:

import { loadPyodide } from "pyodide";
import { usePyodideRuntime } from "./atlas-agent/pyodide-react";
import { useAtlasChat } from "./atlas-agent/react";

function MyChat() {
  const { sdk, isLoading } = useDune();

  // Initialize Python runtime (loads Pyodide, installs packages, sets up Cognite SDK)
  const {
    runtime: pythonRuntime,
    loading: pythonLoading,
    progress: pythonProgress,
    error: pythonError,
    isReady: pythonReady,
  } = usePyodideRuntime({
    loadPyodide,
    client: isLoading ? null : sdk,
    requirements: ["pandas", "numpy"],    // optional — additional packages
  });

  // ... useAtlasChat below
}

Hook API reference

Return fieldTypeDescription
runtimePythonRuntime | undefinedThe initialized runtime, or undefined if not ready
loadingbooleanTrue while Pyodide is loading / initializing
errorstring | nullError message if initialization failed
progress{ stage: string; percent: number }Current init progress for UI display
isReadybooleanConvenience: !loading && !error && runtime !== undefined

Loading state UI

Place the loading indicator above the chat input, not in the message list. Keep it compact — a pill/badge showing stage text and percent. Show an error badge separately. First load is ~30-60s (downloads ~30MB); subsequent loads are <2s from browser cache.

{/* Loading — shown above the input while Pyodide initializes */}
{pythonLoading && (
  <div className="flex items-center gap-2 rounded-lg border bg-muted/50 px-3 py-2 text-sm text-muted-foreground">
    {/* Optional: <IconBrandPython /> from @tabler/icons-react */}
    <span>{pythonProgress.stage || "Initializing Python..."}</span>
    {pythonProgress.percent > 0 && pythonProgress.percent < 100 && (
      <span className="text-xs opacity-70">({pythonProgress.percent}%)</span>
    )}
  </div>
)}

{/* Error — shown if init fails (after loading finishes) */}
{pythonError && !pythonLoading && (
  <div className="flex items-center gap-2 rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive">
    <span>Python runtime failed to load</span>
  </div>
)}

Step 4 — Wire into useAtlasChat

Pass the runtime to useAtlasChat. That's all — no tool configs needed:

const { messages, send, isStreaming, progress, error, reset, abort } = useAtlasChat({
  client: isLoading ? null : sdk,
  agentExternalId: "my-agent",
  tools: [renderTimeSeries],   // regular client tools (declared to agent), if any
  pythonRuntime,               // from usePyodideRuntime — enables Python tool execution
});

Note: Python tools are NOT declared to the agent via tools. The agent already knows about them from its CDF config. The library fetches the code automatically when needed.


Step 5 — Disable input while Python loads

The user shouldn't send messages before the runtime is ready. Disable the entire input area (not just the send button) so the state is unambiguous:

<ChatInput
  onSend={handleSend}
  disabled={isStreaming || pythonLoading}
  // ...
/>

If you have a home page with suggestion chips, disable those too:

<ChatHomePage
  onSuggestionClick={handleSuggestionClick}
  disabled={pythonLoading}
/>

Done

The app can now execute Python tools client-side via Pyodide. When the agent calls a Python tool, the library automatically fetches its code from the agent config, runs it in the browser, and returns the result to the agent.