agentsclimarketplace

Dify plugin builder

Skill xxzxzmai-droid/dify-builder-skills/dify-plugin-builder

Build and package a Dify plugin (a .difypkg file) from a description of what the tool should do. Use this whenever the user wants to create, build, or package a Dify plugin / tool plugin / 插件 / .difypkg — e.g. "做一个把文本转成可下载文件的Dify插件", "帮我做个Dify工具插件调用某个API", "build a Dify plugin that converts markdown to PDF", "package this as a .difypkg". Trigger even if they don't say ".difypkg". The skill scaffolds the plugin from a proven template, fills in the tool logic, and packages it correctly for air-gapped/内网 Dify with bundled offline wheels.From its SKILL.md

Install
npx -y skills add xxzxzmai-droid/dify-builder-skills --skill dify-plugin-builder

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

5.1 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it

Dify Plugin Builder

Scaffold, implement, and package a Dify tool plugin into an installable .difypkg for air-gapped/内网 Dify. Assume the target Dify server cannot reach the internet. The template and packaging scripts encode several non-obvious gotchas that otherwise cost hours.

Non-negotiable delivery rule

Every generated plugin must be fully offline installable: requirements.txt must use --no-index + --find-links=./wheels/, and wheels/*.whl must be included in the .difypkg. Do not deliver a plugin package that depends on the Dify server reaching PyPI.

Workflow

  1. Understand the tool. What does it take in, what does it produce (text / structured JSON / a downloadable file)? Does it need network or a credential/API key?
  2. Scaffold the plugin. Prefer the deterministic scaffold over manual copying: python3 scripts/scaffold_plugin.py /tmp/<plugin_name> --name <plugin_name> --author <author_id> --label-zh "<中文名>" --label-en "<English name>" --description-zh "<中文描述>" --description-en "<English description>" Use --mode downloadable-file|text|json; the default is a downloadable-file tool that already uses meta["filename"].
  3. Fill in or replace the tool logic (see references/plugin-guide.md for the full SDK reference):
    • manifest.yaml: set author, name, labels, description. author must be lowercase [a-z0-9_]; it forms the provider_id prefix.
    • provider/<provider>.yaml + .py: rename, set identity. No credentials → leave _validate_credentials returning. Needs an API key → declare it and validate.
    • tools/<tool>.yaml + .py: define parameters and the _invoke logic. The template's example tool returns a downloadable file — adapt or replace it.
    • Rename the referenced files and update the source: / tools: paths to match.
  4. Prepare offline dependencies (required):
    • If this machine can reach PyPI for the target platform: bash scripts/fetch_offline_wheels.sh /tmp/<plugin_name> 3.12 manylinux2014_aarch64
    • If not, copy wheels from a plugin already verified on the same Dify server: python3 scripts/prepare_offline_plugin.py /tmp/<plugin_name> --wheels-from /path/to/verified/wheels
    • If neither is available, stop and ask for the target server platform or a verified wheels directory. Do not package an online-only plugin.
  5. Package: bash scripts/pack_plugin.sh /tmp/<plugin_name> <plugin_name>.difypkg The script uses zip -D (no directory entries) — required, or install fails with read tools: is a directory. It also refuses to package unless offline requirements and wheels/*.whl are present.
  6. Deliver the .difypkg and tell the user how to install (Dify → 插件 → 安装插件 → 本地文件), plus any post-install step (select a model, fill credentials).

Offline dependency source

The Dify plugin daemon installs Python deps during plugin install. In our scenario it has no internet. Always bundle wheels. manylinux2014_aarch64 is common for ARM64 servers; use manylinux2014_x86_64 for x86_64. If unsure, ask for the server architecture before packaging.

Output a downloadable file from a tool (common, and full of traps)

self.create_blob_message(blob=bytes, meta={...}) is the way. Two traps the template already handles:

  • Filename: dify-api reads meta["filename"] (NOT file_name). Wrong key → file is named with a random hash.
  • Extension / clickable download: the file's URL ends in an extension guessed from the mime type (yaml/many types → .bin). The downloaded name comes from meta["filename"] only when the request URL has ?as_attachment=true. So in the workflow that calls this tool, append &as_attachment=true to the file's url before presenting it (a small code node can do this).

Full SDK details (message types, session.file.upload, signing) are in references/plugin-guide.md — read it before writing non-trivial tool logic.

Sanity-check before packaging

python3 -m py_compile /tmp/<plugin_name>/main.py /tmp/<plugin_name>/provider/*.py /tmp/<plugin_name>/tools/*.py
python3 -c "import yaml,glob; [yaml.safe_load(open(f)) for f in glob.glob('/tmp/<plugin_name>/**/*.yaml',recursive=True)]"

After packaging, confirm 目录条目=0 and manifest在根=1 (the script prints both).

When changing this skill, run:

python3 -m unittest tests.test_plugin_builder

What ships with it: 15 files

25.2 KB alongside SKILL.md, 7 of them executable

agents/

references/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.