Writing a plugin
Use the SDK. It gives you types, a local test harness, bundling and one-command install:
npx @walisayu/plugin-sdk init my-plugin
cd my-plugin && npm install
npx walis-plugin render --input target=stg-01 # see what it produces
npm test
WALIS_API_KEY=... npx walis-plugin install # needs an admin keyimport { definePlugin } from '@walisayu/plugin-sdk'
export default definePlugin({
manifest: {
id: 'acme.deploy',
name: 'Deploy to staging',
parameters: [{ name: 'target', label: 'Host', required: true }]
},
render(inputs, ctx) {
return `scripts/deploy.sh ${ctx.shell.quote(inputs.target)}`
}
})Always quote
// right
return `echo ${ctx.shell.quote(inputs.message)}`
// wrong — a user typing '; rm -rf / #' owns your machine
return `echo ${inputs.message}`ctx.shell.quote implements the same rule as the server, and both sides have tests pinning it, so what you see locally is what actually runs.
Testing
const { script, logs, fetches } = renderPlugin(plugin, { target: 'stg-01' })The harness reproduces the host: parameter defaults, the empty-string semantics of boolean, and the rule that an undeclared domain cannot be reached. fetches lets you assert that a plugin does not call APIs it has no business calling.
Build-time checks
walis-plugin build scans the bundle for things the host does not have — require, process, fs, setTimeout, bare fetch, await, Promise — and for code over 20,000 characters. install refuses to upload while any warning stands, so you find out now rather than halfway through a production build.
Generating a draft with AI
The admin UI can generate a draft from a description. Two rules make that safe to offer:
- Your description is treated as data, not instructions — the model is told to ignore anything inside it that tries to change the output format or widen permissions.
- The model's output is not trusted either. Permissions are stripped, kind and API version are forced, the identifier is re-validated, and nothing is ever installed automatically.
Even if the prompt is fully bypassed, the best an attacker gets is a script you will see on screen and have to install yourself.