Token导航 LogoToken导航

Agent Skill · 开发

add-malli-schemas(添加 malli 模式)

add-malli-schemas 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

add-malli-schemas 是开发类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证为 MIT,第三方扫描已通过,按安装量在开发类的 21,746 个 Skill 里排第 3,527。

总安装 11,025周安装 446GitHub Stars 47,095下载 3,461核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:add-malli-schemas(添加 malli 模式)
来源仓库:https://github.com/metabase/metabase
仓库路径:skills/add-malli-schemas
安装命令:
npx skills add https://github.com/metabase/metabase --skill add-malli-schemas
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/metabase/metabase --skill add-malli-schemas

这个 Skill 是做什么的

开发类 Skill 面向写代码、改代码和排查问题,一般会读写仓库文件,部分还会执行构建或测试命令。

在 Metabase API 端点中统一添加 Malli 模式定义,增强数据校验一致性。适用于 Clojure 后端服务,支持路由、查询参数与响应结构的模式标注。根据现有 schema 风格扩展新端点,推荐复用命名模式与错误消息模板。修改前建议检查依赖版本与测试用例,确保不影响已有接口行为。

add-malli-schemas 属于开发类 Skill,可作为该场景下的辅助能力补充。

来源仓库内路径:skills/add-malli-schemas

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/metabase/metabase --skill add-malli-schemas;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

add-malli-schemas 怎么安装?

在终端执行 npx skills add https://github.com/metabase/metabase --skill add-malli-schemas。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

add-malli-schemas 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

add-malli-schemas 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

add-malli-schemas 是免费的吗?

来源标注的许可证是 MIT。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

add-malli-schemas 用的人多吗?

公开数据是累计安装 11,025 次,近一周安装 446 次,下载 3,461 次,GitHub 47,095 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

add-malli-schemas 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 3 个目录同时收录,说明这个 Skill 流传比较广。
  • 许可证明确为 MIT,商用和分发边界好判断。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理开发类任务、又不想每次都手写提示词的人。
  • 需要许可证清楚、并且有第三方扫描结果的团队项目。

不太适合

  • 需要厂商级技术支持和 SLA 的生产系统。

开发类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
skill-vetter

技能审查员 · OpenClaw

8,779,018986操作浏览器MIT-0通过
ontology

本体论 · OpenClaw

6,636,960576只读MIT-0通过
entra-app-registration

内部应用程序注册 · Codex、Claude

6,631,872764接触敏感数据未明确通过
entra-app-registration

内部应用程序注册 · Codex、Claude

3,757,680201接触敏感数据未明确通过
nano-banana-pro

纳米香蕉专业版 · OpenClaw

3,526,898364接触敏感数据MIT-0有提醒
add-malli-schemas

添加 malli 模式 · 本页

11,02547,095需要联网MIT通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Add Malli Schemas to API Endpoints

This skill helps you efficiently and uniformly add Malli schemas to API endpoints in the Metabase codebase.

Reference Files (Best Examples)

  • src/metabase/warehouses/api.clj - Most comprehensive schemas, custom error messages
  • src/metabase/api_keys/api.clj - Excellent response schemas
  • src/metabase/collections/api.clj - Great named schema patterns
  • src/metabase/timeline/api/timeline.clj - Clean, simple examples

Quick Checklist

When adding Malli schemas to an endpoint:

  • Route params have schemas
  • Query params have schemas with :optional true and :default where appropriate
  • Request body has a schema (for POST/PUT)
  • Response schema is defined (using :- after route string)
  • Use existing schema types from ms namespace when possible
  • Consider creating named schemas for reusable or complex types
  • Add contextual error messages for validation failures

Basic Structure

Complete Endpoint Example

(mr/def ::Color [:enum "red" "blue" "green"])

(mr/def ::ResponseSchema
  [:map
   [:id pos-int?]
   [:name string?]
   [:color ::Color]
   [:created_at ms/TemporalString]])

(api.macros/defendpoint :post "/:name" :- ::ResponseSchema
  "Create a resource with a given name."
  [;; Route Params:
   {:keys [name]} :- [:map [:name ms/NonBlankString]]
   ;; Query Params:
   {:keys [include archived]} :- [:map
                                   [:include  {:optional true} [:maybe [:= "details"]]]
                                   [:archived {:default false} [:maybe ms/BooleanValue]]]
   ;; Body Params:
   {:keys [color]} :- [:map [:color ::Color]]
   ]
  ;; endpoint implementation, ex:
  {:id 99
   :name (str "mr or mrs " name)
   :color ({"red" "blue" "blue" "green" "green" "red"} color)
   :created_at (t/format (t/formatter "yyyy-MM-dd'T'HH:mm:ssXXX") (t/zoned-date-time))}
  )

Common Schema Patterns

  1. Route Params (the 5 in api/user/id/5)
  2. Query Params (the sort+asc pair in api/users?sort=asc)
  3. Body Params (the contents of a request body. Almost always decoded from json into edn)
  4. The Raw Request map

Of the 4 arguments, deprioritize usage of the raw request unless necessary.

Route Params

Always required, typically just a map with an ID:

[{:keys [id]} :- [:map [:id ms/PositiveInt]]]

For multiple route params:

[{:keys [id field-id]} :- [:map
                           [:id ms/PositiveInt]
                           [:field-id ms/PositiveInt]]]

Query Params

Add properties for {:optional true...} and :default values:

{:keys [archived include limit offset]} :- [:map
                                            [:archived {:default false} [:maybe ms/BooleanValue]]
                                            [:include  {:optional true}   [:maybe [:= "tables"]]]
                                            [:limit    {:optional true} [:maybe ms/PositiveInt]]
                                            [:offset   {:optional true} [:maybe ms/PositiveInt]]]

Request Body (POST/PUT)

{:keys [name description parent_id]} :- [:map
                                         [:name        ms/NonBlankString]
                                         [:description {:optional true} [:maybe ms/NonBlankString]]
                                         [:parent_id   {:optional true} [:maybe ms/PositiveInt]]]

Response Schemas

Simple inline response:
(api.macros/defendpoint :get "/:id" :- [:map
                                        [:id pos-int?]
                                        [:name string?]]
  "Get a thing"
  ...)
Named schema for reuse:
(mr/def ::Thing
  [:map
   [:id pos-int?]
   [:name string?]
   [:description [:maybe string?]]])

(api.macros/defendpoint :get "/:id" :- ::Thing
  "Get a thing"
  ...)

(api.macros/defendpoint :get "/" :- [:sequential ::Thing]
  "Get all things"
  ...)

Common Schema Types

From metabase.util.malli.schema (aliased as ms)

Prefer the schemas in the ms/* namespace, since they work better with our api infrastructure.

For example use ms/PositiveInt instead of pos-int?.

ms/PositiveInt                  ;; Positive integer
ms/NonBlankString               ;; Non-empty string
ms/BooleanValue                 ;; String "true"/"false" or boolean
ms/MaybeBooleanValue            ;; BooleanValue or nil
ms/TemporalString               ;; ISO-8601 date/time string (for REQUEST params only!)
ms/Map                          ;; Any map
ms/JSONString                   ;; JSON-encoded string
ms/PositiveNum                  ;; Positive number
ms/IntGreaterThanOrEqualToZero  ;; 0 or positive

IMPORTANT: For response schemas, use :any for temporal fields, not ms/TemporalString! Response schemas validate BEFORE JSON serialization, so they see Java Time objects.

Built-in Malli Types

:string                     ;; Any string
:boolean                    ;; true/false
:int                        ;; Any integer
:keyword                    ;; Clojure keyword
pos-int?                    ;; Positive integer predicate
[:maybe X]                  ;; X or nil
[:enum "a" "b" "c"]         ;; One of these values
[:or X Y]                   ;; Schema that satisfies X or Y
[:and X Y]                  ;; Schema that satisfies X and Y
[:sequential X]             ;; Sequential of Xs
[:set X]                    ;; Set of Xs
[:map-of K V]               ;; Map with keys w/ schema K and values w/ schema V
[:tuple X Y Z]              ;; Fixed-length tuple of schemas X Y Z

Avoid using sequence schemas unless completely necessary.

Step-by-Step: Adding Schemas to an Endpoint

Example: Adding return schema to GET /api/field/:id/related

Before:

(api.macros/defendpoint :get "/:id/related"
  "Return related entities."
  [{:keys [id]} :- [:map [:id ms/PositiveInt]]]
  (-> (t2/select-one :model/Field :id id) api/read-check xrays/related))

Step 1: Check what the function returns (look at xrays/related)

Step 2: Define response schema based on return type:

(mr/def ::RelatedEntity
  [:map
   [:tables [:sequential [:map [:id pos-int?] [:name string?]]]]
   [:fields [:sequential [:map [:id pos-int?] [:name string?]]]]])

Step 3: Add response schema to endpoint:

(api.macros/defendpoint :get "/:id/related" :- ::RelatedEntity
  "Return related entities."
  [{:keys [id]} :- [:map [:id ms/PositiveInt]]]
  (-> (t2/select-one :model/Field :id id) api/read-check xrays/related))

Advanced Patterns

Custom Error Messages

(def DBEngineString
  "Schema for a valid database engine name."
  (mu/with-api-error-message
   [:and
    ms/NonBlankString
    [:fn
     {:error/message "Valid database engine"}
     #(u/ignore-exceptions (driver/the-driver %))]]
   (deferred-tru "value must be a valid database engine.")))

Enum with Documentation

(def PinnedState
  (into [:enum {:error/message "pinned state must be 'all', 'is_pinned', or 'is_not_pinned'"}]
        #{"all" "is_pinned" "is_not_pinned"}))

Complex Nested Response

(mr/def ::DashboardQuestionCandidate
  [:map
   [:id ms/PositiveInt]
   [:name ms/NonBlankString]
   [:description [:maybe string?]]
   [:sole_dashboard_info
    [:map
     [:id ms/PositiveInt]
     [:name ms/NonBlankString]
     [:description [:maybe string?]]]]])

(mr/def ::DashboardQuestionCandidatesResponse
  [:map
   [:data [:sequential ::DashboardQuestionCandidate]]
   [:total ms/PositiveInt]])

Paginated Response Pattern

(mr/def ::PaginatedResponse
  [:map
   [:data [:sequential ::Item]]
   [:total integer?]
   [:limit {:optional true} [:maybe integer?]]
   [:offset {:optional true} [:maybe integer?]]])

Common Pitfalls

Don't: Forget :maybe for nullable fields

[:description ms/NonBlankString]  ;; WRONG - fails if nil
[:description [:maybe ms/NonBlankString]]  ;; RIGHT - allows nil

Don't: Forget :optional true for optional query params

[:limit ms/PositiveInt]  ;; WRONG - required but shouldn't be
[:limit {:optional true} [:maybe ms/PositiveInt]]  ;; RIGHT

Don't: Forget :default values for known params

[:limit ms/PositiveInt]  ;; WRONG - required but shouldn't be
[:limit {:optional true :default 0} [:maybe ms/PositiveInt]]  ;; RIGHT

Don't: Mix up route params, query params, and body

;; WRONG - all in one map
[{:keys [id name archived]} :- [:map ...]]

;; RIGHT - separate destructuring
[{:keys [id]} :- [:map [:id ms/PositiveInt]]
 {:keys [archived]} :- [:map [:archived {:default false} ms/BooleanValue]]
 {:keys [name]} :- [:map [:name ms/NonBlankString]]]

Don't: Use ms/TemporalString for Java Time objects in response schemas

;; WRONG - Java Time objects aren't strings yet
[:date_joined ms/TemporalString]

;; RIGHT - schemas validate BEFORE JSON serialization
[:date_joined :any]  ;; Java Time object, serialized to string by middleware
[:last_login [:maybe :any]]  ;; Java Time object or nil

Why: Response schemas validate the internal Clojure data structures BEFORE they are serialized to JSON. Java Time objects like OffsetDateTime get converted to ISO-8601 strings by the JSON middleware, so the schema needs to accept the raw Java objects.

Don't: Use [:sequential X] when the data is actually a set

;; WRONG - group_ids is actually a set
[:group_ids {:optional true} [:sequential pos-int?]]

;; RIGHT - matches the actual data structure
[:group_ids {:optional true} [:maybe [:set pos-int?]]]

Why: Toucan hydration methods often return sets. The JSON middleware will serialize sets to arrays, but the schema validates before serialization.

Don't: Create anonymous schemas for reused structures

Use mr/def for schemas used in multiple places:

(mr/def ::User
  [:map
   [:id pos-int?]
   [:email string?]
   [:name string?]])

Finding Return Types

  1. Look at the function being called
(api.macros/defendpoint :get "/:id"
  [{:keys [id]}]
  (t2/select-one :model/Field :id id))  ;; Returns a Field instance
  1. Check Toucan models for structure

Look in src/metabase/*/models/*.clj for model definitions.

  1. Use clojure-mcp or REPL to inspect
./bin/mage -repl '(require '\''metabase.xrays.core) (doc metabase.xrays.core/related)'
  1. Check tests

Tests often show the expected response structure.

Understanding Schema Validation Timing

CRITICAL CONCEPT: Schemas validate at different points in the request/response lifecycle:

Request Parameter Schemas (Query/Body/Route)

  • Validate AFTER JSON parsing
  • Data is already deserialized (strings, numbers, booleans)
  • Use ms/TemporalString for date/time inputs
  • Use ms/BooleanValue for boolean query params

Response Schemas

  • Validate BEFORE JSON serialization
  • Data is still in Clojure format (Java Time objects, sets, keywords)
  • Use :any for Java Time objects
  • Use [:set X] for sets
  • Use [:enum:keyword] for keyword enums

Serialization Flow

Request:  JSON string → Parse → Coerce → Handler
Response: Handler → Schema Check → Encode → Serialize → JSON string

Workflow Summary

  1. Read the endpoint - understand what it does
  2. Identify params - route, query, body
  3. Add parameter schemas - use existing types from ms
  4. Determine return type - check the implementation
  5. Define response schema - inline or named with mr/def
  6. Test - ensure the endpoint works and validates correctly

Testing Your Schemas

After adding schemas, verify:

  1. Valid requests work - test with correct data
  2. Invalid requests fail gracefully - test with wrong types
  3. Optional params work - test with/without optional params
  4. Error messages are clear - check validation error responses

Tips

  • Start simple - begin with basic types, refine later
  • Reuse schemas - if you see the same structure twice, make it a named schema
  • Be specific - use ms/PositiveInt instead of pos-int?
  • Document intent - add docstrings to named schemas
  • Follow conventions - look at similar endpoints in the same namespace
  • Check the actual data - use REPL to inspect what's actually returned before serialization

Additional Resources

  • Malli Documentation
  • Metabase Malli utilities: src/metabase/util/malli/schema.clj
  • Metabase schema registry: src/metabase/util/malli/registry.clj

平台分布

Claude Code

26.38%
按下载量换算913

OpenCode

22.63%
按下载量换算783

Gemini CLI

17.18%
按下载量换算595

Cursor

13.91%
按下载量换算481

Antigravity

8.46%
按下载量换算293

Codex

3.88%
按下载量换算134

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

继续浏览同类 Skills