Appearance
Plugin structure
Under the hood, a .lia file is a ZIP archive with a fixed structure. Liatir validates the bundle signature before reading the manifest or executing any runtime payload.
Runtime variants
There are three supported runtimes: Node, Python, and WASM.
Node plugins should not maintain a hand-written .lia-manifest.json. liatir build generates the manifest from the exported definePlugin({...}) contract.
WASM plugins do use .lia-manifest.json, because Rust/WASM cannot export the JavaScript plugin contract at build time.
Python plugins also use .lia-manifest.json. The manifest declares the same Liatir I/O schema plus the Python entry point and optional Python dependency requirements.
Generated Node manifest
For Node plugins, the manifest is generated by liatir build after bundling and validating the default export.
Manifest example:
json
{
"name": "my-plugin",
"version": "1.0.0",
"description": "What this plugin does",
"runtime": "node",
"category": "Utilities",
"tags": ["text"],
"inputSchema": {
"text": {
"type": "string",
"label": "Text",
"description": "Field description.",
"required": true,
"default": "hello from Liatir"
}
},
"outputSchema": {
"length": {
"type": "number",
"label": "Length",
"description": "Field description.",
"format": "integer"
}
}
}Node entry point (index.ts or .js)
Keep the entry point clean and do not alter its structure, or Liatir will reject the plugin. Organize your source files in the project's src/ folder and keep the entry point as a thin wrapper that exports the plugin logic.
ts
import { definePlugin, field, type PluginContext } from "@liatir/api";
const liatirPlugin = definePlugin({
inputs: {
text: field.string({
label: "Text",
description: "Text to analyze.",
required: true,
default: "hello from Liatir",
}),
},
outputs: {
length: field.number({
label: "Length",
description: "Number of characters in the input text.",
format: "integer",
}),
},
});
export default liatirPlugin.main(async ({ input, Liatir }: PluginContext<typeof liatirPlugin>) => {
// Your logic
return {
length: input.text.length,
};
});liatir build rejects Node plugins that export an invalid contract.
Field schemas
Input fields can be of type:
stringnumberbooleanfile
Output fields can be of type:
stringnumberbooleanfilestatsjson
Shared field properties include:
| Property | Description |
|---|---|
label | Human-readable label shown in the UI. |
description | Short explanation shown near the field. |
required | Whether the field must be set before running. |
default | Default value applied by the UI and by liatir dev. |
accept | Accepted file extensions for file inputs. |
ext | Expected file extensions for file outputs. |
format | Numeric output display hint: integer, decimal, percent, or bytes. |
File outputs
If an output field has type: "file", the returned value can either reference an existing file path or provide inline content for Liatir to persist.
ts
return {
report: {
content: "sample,score\nA,0.92\n",
fileName: "report.csv",
},
};Liatir registers saved file outputs under the workspace's Results folder so they can be opened later or connected to downstream pipeline steps.
WASM manifest
WASM plugins keep their schema in .lia-manifest.json:
json
{
"name": "wasm-length",
"version": "1.0.0",
"description": "Count characters in text.",
"runtime": "wasm",
"inputSchema": {
"text": { "type": "string", "label": "Text", "required": true }
},
"outputSchema": {
"length": { "type": "number", "label": "Length", "format": "integer" }
}
}The WASM binary reads JSON input from stdin and writes JSON output to stdout. Liatir rejects WASM plugins that do not follow the I/O contract.
Python manifest
Python plugins keep their schema and runtime dependency metadata in .lia-manifest.json:
json
{
"name": "python-length",
"version": "1.0.0",
"description": "Count characters with Python.",
"runtime": "python",
"inputSchema": {
"text": {
"type": "string",
"label": "Text",
"required": true,
"default": "hello from Liatir"
}
},
"outputSchema": {
"length": {
"type": "number",
"label": "Length",
"format": "integer"
}
},
"python": {
"entry": "src/main.py",
"pythonRequirement": {
"minVersion": "3.10",
"maxVersionExclusive": "3.13",
"label": "Python >=3.10,<3.13"
},
"packages": [],
"requirements": []
}
}The Python entry point must define a callable main(input) function. Liatir passes the input object as JSON-compatible data and expects main to return a JSON-compatible object whose keys match the output schema.
python
def main(input):
text = str(input.get("text", ""))
return {
"length": len(text),
}When the packaged .lia runs, Liatir creates an isolated managed Python runtime for that plugin bundle and installs the declared packages or requirements there.