Plugin Development

Write a plugin

Plugins add new tools to AI Workdeck so the AI can call your code from a conversation. This guide starts with a minimal working example and ends with submitting for review.

01

First, decide: do you need a plugin or a Skill

The two are easy to confuse, and picking the wrong one wastes a lot of work. The difference fits in one sentence: if it takes code, write a plugin; if explaining it clearly is enough, write a Skill.

ScenarioUse
Call an external system's API to fetch dataPlugin
Parse a special file formatPlugin
Have the AI write review comments in your firm's formatSkill
Define the steps and deliverable structure for a type of matterSkill

A Skill is plain text (a prompt plus trigger words): it goes live on submission with no review, and is much faster to write. If a Skill covers your need, go write a Skill and skip the rest of this page.

02

Run your first plugin in five minutes

A plugin is a Java project compiled into a JAR, plus a manifest.json, zipped up and submitted. You need JDK 21 and Maven.

Download the template project above — it is itself a complete working example. Only two files matter. The first is the tool class:

package com.example.myplugin;

import dev.langchain4j.agent.tool.Tool;

/**
 * 插件工具类。
 *
 * 三条硬约定,违反任意一条工具都不会出现在 AI 面前:
 * 1. 必须有无参构造函数——宿主用反射实例化;
 * 2. 工具方法加 @Tool 注解,方法名即工具名,要与 manifest.json 的 tools[].name 一致;
 * 3. 参数与返回值用 String 最省事(复杂结构自己序列化成 JSON 字符串)。
 *
 * @Tool 里的描述是写给 AI 看的,直接决定它会不会在恰当的时候调用这个工具。
 * 写清楚"什么时候用",比写"这个方法做什么"有用得多。
 */
public class MyTools {

    @Tool("统计一段中文文本的字数,返回可读的统计结果。用户问'多少字'时调用。")
    public String countChinese(String text) {
        if (text == null || text.isBlank()) {
            return "输入为空,字数 0";
        }
        long cjk = text.codePoints()
                .filter(cp -> Character.UnicodeScript.of(cp) == Character.UnicodeScript.HAN)
                .count();
        return String.format("总字符 %d,其中汉字 %d", text.length(), cjk);
    }
}

The description in @Tool is written for the AI — it directly decides whether the AI calls your tool at the right moment. Writing "when to use it" is far more useful than "what this method does": the former is what the AI has to judge.

The second is manifest.json, which describes what the plugin is:

{
  "id": "my-plugin",
  "name": "我的插件",
  "version": "1.0.0",
  "description": "一句话说明这个插件替用户做什么。会展示在插件广场的卡片上。",
  "author": "你的名字或团队",
  "homepage": "https://example.com",
  "permissions": [],
  "tools": [
    {
      "name": "countChinese",
      "description": "统计中文文本字数",
      "permissions": []
    }
  ],
  "backendJars": ["my-plugin-1.0.0.jar"]
}

Tool names must match on both sides: tools[].name must equal the Java method name. If they differ, the tool fails to register and the AI cannot see it.

Then package it:

mvn package
mkdir -p dist && cp target/my-plugin-1.0.0.jar manifest.json dist/
cd dist && zip -r ../my-plugin-1.0.0.zip . && cd ..

Note the zip contains the files themselves — don't nest an extra directory. Unzipping should reveal manifest.json directly, not a folder.

03

Try it on your own machine before submitting

No need to wait for review. Copy the entire dist/ directory into your local plugin folder and restart AI Workdeck:

# macOS / Linux
~/.aiworkdeck/plugins/my-plugin/

Your plugin should appear under Plugin Marketplace → Installed. Enable it, then ask something in a conversation that should use your tool and see whether the AI calls it. If it doesn't, the @Tool description most likely fails to explain when to use it.

04

What each manifest.json field means

FieldDescription
idGlobally unique; lowercase letters, digits and hyphens. It can never change once published — it is how upgrades identify "the same plugin".
versionSemantic version. Every submission must be higher than the previous one, or it is rejected.
name / descriptionShown on the marketplace card. Describe what it does for the user, not the implementation.
author / homepageAuthor and project homepage. Optional but recommended — users judge trust by them.
permissionsThe capabilities this plugin uses; see the next section.
toolsTool list. name must equal the Java method name; write the description so its purpose is clear.
backendJarsJAR file names relative to the package root. ../ paths outside the package are not allowed.
05

permissions: declare honestly — review cross-checks

Four optional values; declare what you use:

  • file_readRead project files
  • file_writeCreate, modify or delete files
  • networkAccess the external network
  • editorOperate the document editor

This is not a sandbox

Plugins run in the same process as the host app, so undeclared behavior cannot be blocked technically — a tool that declares no permissions can still read files. The declaration is not a runtime restriction but review evidence: we cross-check it against the JAR's static scan. Declaring no network while referencing network APIs — or the reverse — gets the submission rejected.

06

What review looks at

Every version is reviewed by a human, usually within one to two business days. An automated scan runs first, and its report sits next to your permissions declaration on the reviewer's desk.

These are rejected outright:

  • Declared permissions don't match the APIs actually called
  • Custom TrustManager or any other way of bypassing certificate validation
  • Hardcoded IP addresses, or data sent out over plaintext HTTP
  • Reflection into the host's internal objects (database connections, config services, etc.)
  • Obfuscated or packed code, or anything that hides what the code does
  • Version number not higher than the previous one

Once approved, the platform signs the whole package with its private key and clients verify the signature on install. After that, nobody — including us — can alter the package contents without re-signing.

If a problem surfaces after release, we revoke that version. Clients pick up the revocation list, disable it automatically and notify the user.

07

A promise to users — and a constraint on you

Our users are lawyers, and their machines hold clients' confidential material. A plugin gets the same access as the host app — far beyond what it needs for itself.

So review errs on the strict side, and rejections come with reasons. If your plugin genuinely needs a sensitive-looking capability, explain why in the submission notes — it makes review much faster.

Ready to go

Zip it up and submit — we'll review it as soon as we can.