UbiquityOS Plugin Template
Ubiquity OS · 2024 · Standardized scaffold with dual entry points (Actions + Workers), Supabase adapters, TypeBox validation, and CI for tests and linting.
So what?
public template template adoption
public template template adoption
Problem
Plugin authors were cloning assorted repos and hand-assembling scaffolds, leading to inconsistent structures and wasted time. A standard template needed to encode the working patterns used across successful plugins.
Approach
- Base on
ubiquity/ts-template
but remove unused scaffolding (e.g., cypress, esbuild) - Provide dual entry points:
src/main.ts
(Actions) andsrc/worker.ts
(Workers) - Ship shared context/types/utils and a Supabase adapter layer
- Validate inputs with TypeBox; keep runtime checks explicit
- Include CI for Jest coverage, ESLint, and Knip dependency analysis
System diagram
flowchart LR Dev[Developer] --> Clone[Template Clone] Clone --> TS[TypeScript Setup] TS --> Ctx[Context Initialization] Ctx --> Impl[Plugin Logic Implementation] Impl --> Deploy[Dual Deploy] Deploy --> Actions[Actions] Deploy --> Workers[Workers] Workers --> Integrate[UbiquityOS Integration] Actions --> Integrate
Outcome
- Faster ramp for new plugins; authors focus on business logic
- Consistent project layout improves maintainability and reviews
- Tests and validation present from the start
Constraints
- Kernel-side validation reduced plugin defaults surface
- Token naming transitions required (
UBIQUIBOT_TOKEN
overGITHUB_TOKEN
) - Worker plugin direction tracked in a separate issue (blocked items managed)
Design choices
- Keep both entry paths thin; push logic into shared modules
- Prefer explicit runtime validation for external entry points
- Externalize all secrets via
.env.example
; no hardcoded tokens
Proof
Code excerpt — Actions entry with shared context
export async function plugin(inputs: PluginInputs) {
const {
eventName,
eventPayload: payload,
settings,
authToken: env.UBIQUIBOT_TOKEN,
} = inputs;
const context = {
eventName: payload.eventName,
eventPayload: JSON.parse(payload.eventPayload),
settings,
authToken: env.UBIQUIBOT_TOKEN,
};
return await runPlugin(context);
}
Code excerpt — Worker entry with TypeBox validation
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const webhookPayload = await request.text();
const parsed = Type.Object({ eventName: Type.String(), eventPayload: Type.String() });
const validation = Value.Check(parsed, JSON.parse(webhookPayload));
if (!validation) return new Response("Invalid payload", { status: 400 });
return await plugin(JSON.parse(webhookPayload));
},
};
CI evidence — Jest coverage workflow
name: Run Jest testing suite
on:
workflow_dispatch:
workflow_run:
workflows: ["Build"]
types: [completed]
jobs:
testing:
permissions: write-all
runs-on: ubuntu-latest
steps:
- uses: ArtiomTr/jest-coverage-report-action@v2
with:
package-manager: yarn
Release evidence — template init merged with CI in place
Merged 12 commits into main (template initialization and CI wiring).
References
- Repo — ubiquity-os/plugin-template
- PR — #1 - template init
- Issue — #9 - worker plugin direction