Official agent skill

Error Handling

by microsoft in microsoft/data-formulator

统一错误处理系统。在添加 API 端点、修改错误处理、添加前端 API 调用、编写错误相关测试时使用. An agent skill from microsoft/data-formulator.

OfficialMITAuto-check passedDevelopment

Install Error Handling

skills CLI
$ npx skills add microsoft/data-formulator --skill error-handling -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install microsoft/data-formulator error-handling --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/microsoft/data-formulator.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.cursor/skills/error-handling .claude/skills/error-handling && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
error-handling
GitHub stars
18k
Token cost
~3.8k tokens
SKILL.md length
1,094 words
Files
1
Skills in repo
6
Repo updated
First seen
Licence
MIT

At a glance

统一错误处理系统。在添加 API 端点、修改错误处理、添加前端 API 调用、编写错误相关测试时使用. An agent skill from microsoft/data-formulator.

  • Works in 3 steps: Backend — Add to… → Frontend mapping — Add to… → Translations — Add to both locale files
  • Tasks that involve Error handling
  • SKILL.md covers Architecture Overview, Protocol Snapshot, Backend: Adding a New API… and Frontend: Consuming an API, plus 9 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

Error Handling is an agent skill from microsoft/data-formulator, published by the product's own GitHub organization. 统一错误处理系统。在添加 API 端点、修改错误处理、添加前端 API 调用、编写错误相关测试时使用。

Its SKILL.md is about 3.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Development, covering Error handling. The repository describes itself as: 🪄 Data Formulator is an interactive AI-powered data analysis system makes it easy to connect, explore and visualize data. The licence is MIT.

When your agent uses it

  • Tasks that involve Error handling

Example prompts

  • “/error-handling”

Requirements

  • Python 3

Workflow steps

3 steps, taken from the first numbered list in SKILL.md.

  1. Backend — Add to py-src/data_formulator/errors.py ErrorCode
  2. Frontend mapping — Add to src/app/errorCodes.ts ERROR_CODE_I18N_MAP
  3. Translations — Add to both locale files

What it can do on your machine

Read from SKILL.md and the folder at commit 5477f0e. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are python and typescript).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Error Handling loads about 3.8k tokens when it runs. Until then it costs about 17 tokens; SKILL.md has 1,094 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~17
When it runs · the whole SKILL.md, loaded when a task matches
~3.8k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from microsoft/data-formulator at commit 5477f0e, republished under its MIT licence (© microsoft). 1,094 words, ~3,789 tokens.

Download SKILL.mdSave it as .claude/skills/error-handling/SKILL.md (or your agent's skills folder).
name
error-handling
description
统一错误处理系统。在添加 API 端点、修改错误处理、添加前端 API 调用、编写错误相关测试时使用。

Error Handling Skill

Unified error handling system for DF. Use when adding API endpoints, modifying error handling, or adding frontend API calls.

Prerequisites: Read docs/dev-guides/7-unified-error-handling.md before changing API error behavior. Read docs/dev-guides/2-log-sanitization.md when the work involves logging, credentials, external services, or DataLoaders. If your work introduces new error handling patterns or conventions, update this file and related dev-guides accordingly.

Architecture Overview

Frontend                              Backend
────────                              ───────
apiClient.ts                          errors.py
├── apiRequest()    ←── JSON ────     ├── ErrorCode (enum)
├── streamRequest() ←── NDJSON ──     └── AppError (exception)
└── parseStreamLine()
                                      error_handler.py
errorCodes.ts                         ├── register_error_handlers(app)
└── getErrorMessage()                 ├── classify_and_wrap_llm_error()
                                      └── stream_error_event()
errorHandler.ts
└── handleApiError()                  security/sanitize.py
                                      └── classify_llm_error() (internal)
MessageSnackbar ← dfSlice.messages

Protocol Snapshot

Use this contract for all new or reworked DF APIs:

ScenarioHTTPShape
Non-streaming success200{"status": "success", "data": ...}
Non-streaming business/validation error200{"status": "error", "error": {"code", "message", "retry", "request_id"}}
Non-streaming auth/authorization error401 / 403same structured error body
Streaming preflight error200application/json + {"status": "error", "error": ...}
Streaming in-flight fatal error200NDJSON line: {"type": "error", "error": ...}
No Flask route / too large / unhandled crash404 / 413 / 500transport-level error

Do not use HTTP 400/422 for application validation errors in new code. Do not convert in-flight NDJSON errors to status: "error"; once the stream has started, event type is the protocol discriminator.

Backend: Adding a New API Endpoint

HTTP Status Code Policy

Application-controlled business and validation errors return HTTP 200 with status: "error" in the body. Only these use non-200:

  • 401/403 — auth errors (AUTH_REQUIRED, AUTH_EXPIRED, ACCESS_DENIED)
  • 404 — no matching Flask route
  • 413 — WSGI body limit exceeded
  • 500 — unhandled exception (program bug)
Non-streaming endpoint
python
from data_formulator.errors import AppError, ErrorCode
from data_formulator.error_handler import json_ok

@bp.route('/my-endpoint', methods=['POST'])
def my_endpoint():
    content = request.get_json()
    if not content.get('required_field'):
        raise AppError(ErrorCode.INVALID_REQUEST, "Missing required_field")

    try:
        result = do_work(content)
    except SomeBusinessError as e:
        raise AppError(ErrorCode.DATA_LOAD_ERROR, "Failed to load data") from e
    except Exception as e:
        from data_formulator.error_handler import classify_and_wrap_llm_error
        raise classify_and_wrap_llm_error(e) from e

    return json_ok(result)
# Global handler returns: HTTP 200 + {"status": "error", "error": {code, message, retry}}
# Auth errors (AUTH_REQUIRED/AUTH_EXPIRED/ACCESS_DENIED) return 401/403

Legacy {"status": "error", "message": "..."}, error_message, bare {error}, and status: "ok" responses are historical formats. Do not add new compatibility branches for them; migrate the route to json_ok() / AppError before using apiRequest().

Streaming endpoint

Validation MUST be outside the generator. Failures return 200 JSON (not NDJSON).

python
from data_formulator.errors import AppError, ErrorCode
from data_formulator.error_handler import (
    classify_and_wrap_llm_error,
    stream_error_event,
    stream_preflight_error,
)

@bp.route('/my-stream', methods=['POST'])
def my_stream():
    if not request.is_json:
        return stream_preflight_error(
            AppError(ErrorCode.INVALID_REQUEST, "Invalid request")
        )

    content = request.get_json()
    client = get_client(content['model'])

    def generate():
        try:
            for event in agent.run(...):
                yield json.dumps(event, ensure_ascii=False) + "\n"
        except Exception as e:
            yield stream_error_event(classify_and_wrap_llm_error(e))

    return Response(stream_with_context(generate()), mimetype='application/x-ndjson')

Streaming runtime errors intentionally use {"type": "error", "error": ...}. They cannot use a top-level status envelope because the HTTP response and NDJSON event stream have already started.

Frontend: Consuming an API

Non-streaming
typescript
import { apiRequest } from '../app/apiClient';
import { handleApiError } from '../app/errorHandler';

try {
    const { data } = await apiRequest<ResponseType>(getUrls().MY_ENDPOINT, {
        method: 'POST',
        body: JSON.stringify(payload),
        headers: { 'Content-Type': 'application/json' },
    });
} catch (e) {
    handleApiError(e, 'MyComponent');
}

For UI loading state, model the request lifecycle explicitly with LoadableState from src/app/loadableState.ts. Do not infer loading from missing data (!data), because failed requests may legitimately leave data empty while loading has ended.

Streaming
typescript
import { streamRequest } from '../app/apiClient';
import { handleApiError } from '../app/errorHandler';

try {
    for await (const event of streamRequest(url, options, abortController.signal)) {
        switch (event.type) {
            case 'text_delta':
                break;
            case 'error':
                // Error arrived mid-stream — show inline in component.
                break;
            case 'done':
                break;
        }
    }
} catch (e) {
    handleApiError(e, 'MyComponent');
}
With callbacks
typescript
handleApiError(e, 'MyComponent', {
    onAuth: () => redirectToLogin(),        // AUTH_REQUIRED / AUTH_EXPIRED
    onRetryable: () => retryOperation(),    // LLM_RATE_LIMIT / LLM_TIMEOUT
    silent: true,                           // don't show Snackbar (component handles display)
});
Migration and special cases

DF API consumers should use apiRequest() / streamRequest() and handleApiError(). Direct fetchWithIdentity() is for lower-level client helpers and explicit protocol exceptions such as file downloads, blob/CSV responses, OIDC redirects, SPA fallback, or third-party URLs.

Do not apply the normal JSON API protocol mechanically to file downloads / CSV streaming, SPA fallback, OIDC redirect flows, frontend fetches to third-party URLs, or errors after a streaming response has already started. Check the route's protocol first, then preserve safe error bodies and avoid str(exc) exposure.

Adding a New Error Code

  1. Backend — Add to py-src/data_formulator/errors.py ErrorCode:

    python
    MY_NEW_ERROR = "MY_NEW_ERROR"

    No HTTP mapping needed — defaults to HTTP 200. Only add to ERROR_CODE_HTTP_STATUS if it's an auth code.

  2. Frontend mapping — Add to src/app/errorCodes.ts ERROR_CODE_I18N_MAP:

    typescript
    MY_NEW_ERROR: 'errors.myNewError',
  3. Translations — Add to both locale files:

    • src/i18n/locales/en/errors.json: "myNewError": "English message"
    • src/i18n/locales/zh/errors.json: "myNewError": "中文消息"

Migrated Endpoints Reference

All streaming endpoints are now on the unified protocol:

EndpointFormatNotes
/data-agent-streamingNDJSON + stream_error_event()Emits top-level type events; errors use {type:"error", error:{...}}
/get-recommendation-questionsNDJSON + stream_error_event()Was error: {json} prefix
/generate-report-chatPure NDJSON + stream_error_event()Was SSE data: {json} prefix
/data-loading-chatNDJSON + stream_error_event()str(e) removed
/clean-data-streamNDJSON + stream_error_event()Was \n{json}\n format

Non-streaming endpoints:

EndpointError FormatNotes
/chart-insightAppError → HTTP 200 + {status:"error", error:{code,message,retry}}Fully migrated. Frontend uses fetchChartInsight rejected reducer.
All migrated endpointsAppError → HTTP 200 + unified error bodycredentials, knowledge, sessions, tables, agents
/derive-data, /refine-data, /sort-data, /process-data-on-load, /test-modeljson_ok() / AppErrorMigrated to new format

Empty Catch Policy

Not all .catch(() => {}) are bugs. Use this decision tree:

  1. User-initiated action (delete, refresh, submit) → must notify with addMessages or handleApiError()
  2. Background/best-effort fetch (connector list on mount, session list) → OK to swallow, but add a comment
  3. RTK thunks → always add .rejected handler with addMessages
  4. AbortError → filter out with if (action.error?.name !== 'AbortError')

Frontend Stream Parsing Pattern

When consuming a migrated streaming endpoint, handle the current NDJSON event format directly:

typescript
const data = JSON.parse(line);
if (data.type === 'error') {
    const errMsg = data.error?.message || 'Unknown error';
    // show to user...
}
Show full SKILL.md (463 more words)Show less

Backend: Database/Workspace Errors (tables.py)

For table CRUD endpoints, use the specialized classifier:

python
from data_formulator.routes.tables import classify_and_raise_db_error

@tables_bp.route('/my-table-op', methods=['POST'])
def my_table_op():
    try:
        result = workspace.do_something()
        return jsonify({"status": "success", "data": result})
    except Exception as e:
        classify_and_raise_db_error(e)

classify_and_raise_db_error maps common DB errors to appropriate AppError codes (returned as HTTP 200 by the global handler, except ACCESS_DENIED → 403):

  • "Table does not exist" → TABLE_NOT_FOUND (HTTP 200)
  • "Table already exists" → INVALID_REQUEST (HTTP 200)
  • "Permission denied" → ACCESS_DENIED (HTTP 403)
  • Other → CONNECTOR_ERROR (HTTP 200)

Backend: Connector Errors (data_connector.py)

For connector endpoints, use:

python
from data_formulator.data_connector import classify_and_raise_connector_error

except Exception as e:
    classify_and_raise_connector_error(e, operation="preview")

Connector/DataLoader classification is intentionally simple and lives in data_formulator.data_loader.connector_errors. It maps common failures to a small stable set: INVALID_REQUEST, CONNECTOR_AUTH_FAILED, AUTH_EXPIRED, ACCESS_DENIED, DB_CONNECTION_FAILED, DB_QUERY_ERROR, DATA_LOAD_ERROR, or CONNECTOR_ERROR. Do not add endpoint-local string matching unless the classifier cannot reasonably cover the category.

All JSON errors include error.request_id and an X-Request-Id response header. Show/copy this ID for users when reporting backend failures; do not show raw exception text in production. Unhandled 500 responses must never include raw tracebacks, even in debug mode; return a safe category plus request_id and keep full stack traces in server logs only.

Debugging Error Propagation

When an error isn't reaching the frontend:

  1. Check backend logs — is the error logged?
  2. Check response format:
    • Non-streaming: {"status": "error", "error": {"code": ..., "message": ...}}
    • Streaming: one line {"type": "error", "error": {"code": ..., "message": ...}}
  3. Check Content-Type — streaming must be application/x-ndjson, not application/json or text/event-stream
  4. Check frontend parser — is the consumer looking for data.type === 'error'?
  5. Check global handler — verify register_error_handlers(app) is called in app.py
  6. Check blueprint handlers — blueprint-level errorhandler(Exception) takes priority over global handlers

Legacy message / error_message bodies are protocol violations on migrated API paths.

Log Sanitization (Sensitive Data in Server Logs)

Server-side logs must never leak passwords, tokens, API keys, or connection strings. The project uses a defense-in-depth approach with two layers.

Layer 1: Explicit Utilities (call-site)
python
from data_formulator.security.log_sanitizer import (
    sanitize_url, sanitize_params, redact_token,
)

# Dict with credentials → sanitize_params()
log.info("Connecting with: %s", sanitize_params(params))

# URL that may embed credentials → sanitize_url()
logger.info("Issuer: %s", sanitize_url(issuer_url))

# Token/API key → redact_token()
logger.debug("Token: %s", redact_token(token))
Layer 2: SensitiveDataFilter (global safety net)

Registered in app.py:configure_logging(). Automatically redacts:

  • URL credentials (://user:pass@host)
  • Bearer tokens
  • password=xxx, api_key=xxx, secret=xxx patterns
  • JWT-like base64 strings
  • Python dict repr with sensitive keys

Disable with LOG_SANITIZE=false for local debugging only.

When to Use What
DataUtilityWhy not just filter?
dict with password keyssanitize_params()Filter can't identify arbitrary password values in dict repr
URL from config/envsanitize_url()Explicit is clearer; filter is backup
Token/key valueredact_token()Explicit is clearer; filter is backup
Normal textNothingFilter handles edge cases
New Module Checklist

When adding a module that handles credentials or external services:

  1. Audit all logger.*() calls for credential/URL/token logging
  2. Use sanitize_params() for dicts, sanitize_url() for URLs, redact_token() for tokens
  3. Prefer type(exc).__name__ over str(exc) in warning-level logs
  4. If introducing new credential key names, add to SENSITIVE_KEYS in log_sanitizer.py

Key Files

FilePurpose
py-src/data_formulator/errors.pyErrorCode enum + AppError exception
py-src/data_formulator/error_handler.pyGlobal handlers, classify_and_wrap_llm_error, stream_error_event
py-src/data_formulator/security/log_sanitizer.pysanitize_url, sanitize_params, redact_token, SensitiveDataFilter
py-src/data_formulator/routes/tables.pyclassify_and_raise_db_error (database/workspace errors)
py-src/data_formulator/data_connector.pyclassify_and_raise_connector_error (connector errors)
py-src/data_formulator/security/sanitize.pyclassify_llm_error (internal), sanitize_error_message
src/app/apiClient.tsapiRequest, streamRequest, parseStreamLine, ApiRequestError
src/app/errorHandler.tshandleApiError
src/app/errorCodes.tsERROR_CODE_I18N_MAP, getErrorMessage
src/i18n/locales/{en,zh}/errors.jsonError message translations

© microsoft, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .cursor/skills/error-handling of microsoft/data-formulator.

Open the folder on GitHubat commit 5477f0e

Compare with similar skills

Error Handling next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Error Handling compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Error Handling this skillmicrosoft/data-formulator18k—~3.8kAutomated safety check: PassMIT
Mole Bug Patternstw93/Mole70k—~2kAutomated safety check: PassGPL-3.0
Native Data FetchingCherryHQ/cherry-studio-app4k6 repos~2.9kAutomated safety check: NotesMIT
Rust Best Practicesfarm-fe/farm5.6k3 repos~1.1kAutomated safety check: PassMIT
R Function Input Validationtidyverse/dplyr5.1k1 repos~2.3kAutomated safety check: PassCustom licence
Next Best Practicesvercel-labs/openreview1.7k18 repos~1kAutomated safety check: PassNone

Similar skills

  • A catalog of recurring bug shapes in the Mole Mac cleaner, used to review safety-sensitive diffs for deletion safety, unbounded commands, shell traps and weak tests.

    70k GitHub stars~2k tokensUpdated today
    DevelopmentAuto-check passed
  • Native Data Fetching

    CherryHQ/cherry-studio-app

    A skill your agent uses when implementing or debugging ANY network request, API call, or data fetching.

    4k GitHub starsUsed in 6 repos~2.9k tokens
    DevelopmentAuto-check: notes
  • Guide for writing idiomatic Rust code based on Apollo GraphQL's best practices handbook.

    5.6k GitHub starsUsed in 3 repos~1.1k tokens
    DevelopmentAuto-check passed
  • Validates arguments of exported R functions with the standalone check_* type checkers from rlang, in tidyverse style with clear error messages.

    5.1k GitHub starsUsed in 1 repo~2.3k tokens
    DevelopmentAuto-check passed
  • Next Best Practices

    vercel-labs/openreview

    Official

    Next.js best practices - file conventions, RSC boundaries, data patterns, async APIs, metadata, error handling, route handlers, image/font optimization, bundling

    1.7k GitHub starsUsed in 18 repos~1k tokens
    DevelopmentAuto-check passed
  • Zod

    jasonjgardner/blockbench-mcp-plugin

    Zod schema validation best practices for type safety, parsing, and error handling.

    491 GitHub starsUsed in 3 repos~1.4k tokens
    DevelopmentAuto-check passed

More from microsoft/data-formulator

  • Language Injection

    microsoft/data-formulator

    Official

    LLM Agent 多语言注入规范。在修改 Agent 提示词、添加新的 Agent 端点、处理用户可见的后端消息(messagecode)时使用。

    18k GitHub stars~1.2k tokensUpdated today
    Auto-check passed
  • Path Safety

    microsoft/data-formulator

    Official

    服务端路径安全与文件访问编码规范。在编写文件下载路由、Agent 工具(文件读取/目录列出)、数据连接器/Loader、Workspace 路径操作、沙箱配置时使用。

    18k GitHub stars~1.2k tokensUpdated today
    Auto-check passed
  • Data Loading

    microsoft/data-formulator

    Official

    Discover connected data sources, add new data connectors through a user-confirmed form, inspect table metadata, and run bounded read-only probes when the current workspace data is insufficient.

    18k GitHub stars~1.4k tokensUpdated today
    Auto-check passed
  • Report

    microsoft/data-formulator

    Official

    Turn an exploration (threads, findings, charts) into a single Markdown report — note, blog post, executive summary, KPI dashboard, slide brief, or multi-section analytical report, with embedded…

    18k GitHub stars~1.5k tokensUpdated today
    Auto-check passed
  • Core

    microsoft/data-formulator

    Official

    The analyst's built-in capabilities: data-inspection tools and the always-available actions (visualize and askuser).

    18k GitHub stars~5.4k tokensUpdated today
    Auto-check passed

Categories

Questions about Error Handling

What does Error Handling do?

统一错误处理系统。在添加 API 端点、修改错误处理、添加前端 API 调用、编写错误相关测试时使用. An agent skill from microsoft/data-formulator. Error Handling is an agent skill from microsoft/data-formulator, published by the product's own GitHub organization.

When should I use Error Handling?

Error Handling fits situations like: tasks that involve Error handling.

How do I install Error Handling in Claude Code?

Run `npx skills add microsoft/data-formulator --skill error-handling -a claude-code`. Or copy the skill folder (.cursor/skills/error-handling in microsoft/data-formulator) into .claude/skills/error-handling in your project. Claude Code loads it when a task matches its description.

How do I install Error Handling in Codex?

Run `npx skills add microsoft/data-formulator --skill error-handling -a codex`. Or copy the skill folder (.cursor/skills/error-handling in microsoft/data-formulator) into .agents/skills/error-handling in your project. Codex loads it when a task matches its description.

Can I use Error Handling in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add microsoft/data-formulator --skill error-handling -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/error-handling, .gemini/skills/error-handling, .github/skills/error-handling and .opencode/skills/error-handling in your project.

What does Error Handling need to run?

SKILL.md names no scripts, command-line tools or credentials: Error Handling is instructions for the agent only. Our summary lists: Python 3.

Does Error Handling access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Error Handling safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Error Handling use?

Error Handling is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Error Handling use?

About 3.8k tokens (SKILL.md is roughly 15k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Error Handling?

Skills that share tags, products or a category with Error Handling: Mole Bug Patterns (tw93/Mole, 70k stars), Native Data Fetching (CherryHQ/cherry-studio-app, 4k stars), Rust Best Practices (farm-fe/farm, 5.6k stars) and R Function Input Validation (tidyverse/dplyr, 5.1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Error Handling?

microsoft (a GitHub organization, an official publisher) maintains it in microsoft/data-formulator, which has 17,540 GitHub stars. The repository holds 6 skills in this directory. The repository was last updated on October 8, 2026.

Source: microsoft/data-formulator on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.