Skip to content

Language templates ​

Don't want to build the skeleton by hand? The template repos for six languages already ship the manifest, the entry point, the host SDK and a packaging script. Clone one, change the id, and you are ready to write logic. Each repo has README.md (English) and README-CN.md (Simplified Chinese).

LanguageTemplate repoOutputWhat you need
Javatemplate-tml-extension-javacom.tywstudio.example.java.jarJDK (javac, jar)
Pythontemplate-tml-extension-python*.tmlextPython 3
Node.jstemplate-tml-extension-node*.tmlextNode.js 18+
Ctemplate-tml-extension-c*.tmlext (contains a native binary)Any C compiler (gcc / clang / MSVC cl) + Python 3
Rusttemplate-tml-extension-rust*.tmlext (contains a native binary)Rust toolchain (Cargo) + Python 3
Gotemplate-tml-extension-go*.tmlext (contains a native binary)Go 1.21+ + Python 3

No Zig template yet

Follow the C or Go layout: set runtime to zig, point entry at the binary produced by zig build-exe, and keep everything else (manifest fields, stdio protocol, zipping) identical.

Three ways to start ​

All six repos are template repositories. Open one and click Use this template → Create a new repository — the new repo is yours, with no parent link and no forced sync with the template.

2. git clone ​

bash
git clone https://github.com/TYWStudio/template-tml-extension-go.git my-ext
cd my-ext

Add --depth 1 if you only want the latest snapshot:

bash
git clone --depth 1 https://github.com/TYWStudio/template-tml-extension-go.git my-ext

3. Download the zip ​

On machines without git, use Code → Download ZIP on the repo page and unpack it.

Change these three things first ​

  1. id — in manifest.json (or META-INF/tml-extension.json for Java). It cannot change after installation, so use something like yourname.feature. Update name, version and author too.
  2. Entry logic — src/main.*, main.py, main.js. The template only logs one line and calls host.info; replace it with your own code.
  3. permissions — declare exactly what you use. Every extra permission is shown to the user and makes installation more likely to be rejected.

Per language ​

Java ​

You need a JDK (java -version must work). The host launches the extension with java -cp "<jar>" com.tywstudio.example.Main, so the entry class must match the manifest.

bash
git clone https://github.com/TYWStudio/template-tml-extension-java.git my-ext
cd my-ext
bash build.sh          # Windows: build.bat
# output: com.tywstudio.example.java.jar

The Java template produces a plain .jar, not a .tmlext — import that jar.

Python ​

Python 3 only, no third-party packages.

bash
git clone https://github.com/TYWStudio/template-tml-extension-python.git my-ext
cd my-ext
python3 build.py       # Windows: python build.py
# output: com.tywstudio.example.python.tmlext

Running python3 main.py directly blocks forever waiting for the handshake — that is expected, the launcher has to start it.

Node.js ​

bash
git clone https://github.com/TYWStudio/template-tml-extension-node.git my-ext
cd my-ext
node build.js          # or: npm run pack
# output: com.tywstudio.example.node.tmlext

package.json has no runtime dependencies, so npm install is not needed.

C ​

Any C compiler (gcc / clang / MSVC cl) plus Python 3 for packaging.

bash
git clone https://github.com/TYWStudio/template-tml-extension-c.git my-ext
cd my-ext
./build.sh             # Windows: build.bat
# output: template-tml-extension-c.tmlext

build.sh compiles, build.py packs the manifest, sources and binary into the .tmlext.

Rust ​

The SDK is a git dependency (tml-ext, tag sdk-rust-v1.0.0), so the first build clones the TML repository once; afterwards it comes from the Cargo cache. Never copy lib.rs into your project.

bash
git clone https://github.com/TYWStudio/template-tml-extension-rust.git my-ext
cd my-ext
./build.sh             # Windows: build.bat
# output: template-tml-extension-rust.tmlext

Internally: cargo build --release → binary copied to bin/tml_ext → build.py packs it.

Go ​

The SDK lives in extensions/sdk/go of the TML repository; build.sh runs go mod tidy first, which fetches it (network needed on the first run).

bash
git clone https://github.com/TYWStudio/template-tml-extension-go.git my-ext
cd my-ext
./build.sh             # Windows: build.bat
# output: template-tml-extension-go.tmlext

The command is CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o bin/tml_ext ./src. CGO_ENABLED=0 keeps the binary statically linked and makes cross-compiling trivial:

bash
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o bin/tml_ext.exe ./src
GOOS=linux   GOARCH=arm64 CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o bin/tml_ext ./src
GOOS=darwin  GOARCH=arm64 CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o bin/tml_ext ./src

Install the result ​

  1. Run the build script, get a .jar or .tmlext.
  2. Launcher → Settings → Extensions → Import, pick the file; or just drop it onto the window (multi-file works).
  3. Review the permission list and enable it. A package you confirmed once is remembered — no repeat prompt; a different package asks again.
  4. After code changes, rebuild and re-import; if the file was just replaced, click Refresh.

Details / Enable / Uninstall, state badges and auto-start are covered in Import & manage.

The first load stores the package SHA-256 in extensions/trusted.json. Change the content and the launcher reports "extension was modified" — delete that entry and trust it again.

Pitfalls ​

SymptomCause
Not listed after importInvalid manifest JSON, or duplicate id
"Runtime unavailable"Interpreter not on PATH (Java/Python/Node), wrong architecture, or no exec bit
Exits immediatelyEntry does not read stdin, or never replies {"ready": true}
First Rust/Go build seems stuckFetching the SDK from the TML repo on GitHub; cached afterwards
Works on one machine onlyNative packages (C / Rust / Go) are tied to the build platform — rebuild per target
macOS refuses to openThe bundled binary needs signing; use xattr -cr locally, sign for release

See also ​