The kernel is designed to:
- Interface with plugins (GitHub Actions) for longer running processes.
- Run on Cloudflare Workers.
-
APP_PRIVATE_KEY
Obtain a private key from your GitHub App settings and convert it to the Public-Key Cryptography Standards #8 (PKCS#8) format. A new private key in PEM format can be generated and downloaded from https://github.com/organizations/{your-organization-name}/settings/apps/{your-github-app-name}. Use the following command to perform PEM to PKCS#8 conversion and append the result to your.dev.vars
file:echo "APP_PRIVATE_KEY=\"$(openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in YOUR_APP_PRIVATE_KEY.PEM | awk 'BEGIN{ORS="\\n"} 1')\"" >> .dev.vars
Note: Replace
YOUR_APP_PRIVATE_KEY.PEM
with the path to your actual PEM file when running the command. -
WEBHOOK_SECRET
Set this value in both your GitHub App settings and here. -
APP_ID
Retrieve this from your GitHub App settings. -
WEBHOOK_PROXY_URL
(only for development) Obtain a webhook URL at smee.io and set it in your GitHub App settings.
git clone https://github.com/ubiquity/ubiquibot-kernel
cd ubiquibot-kernel
bun install
bun dev
-
Install Dependencies:
- Execute
bun install
to install the required dependencies.
- Execute
-
Create a GitHub App:
-
Generate a GitHub App and configure its settings.
-
Navigate to app settings and click
Permissions & events
. -
Ensure the app is subscribed to all events with the following permissions:
Repository permissions:
- Actions: Read & Write
- Contents: Read & Write
- Issues: Read & Write
- Pull Requests: Read & Write
Organization permissions:
- Members: Read only
-
-
Cloudflare Account Setup:
- If not done already, create a Cloudflare account.
- Run
npx wrangler login
to log in.
-
Create a KV Namespace:
- Generate a KV namespace using
npx wrangler kv:namespace create PLUGIN_CHAIN_STATE
. - Copy the generated ID and paste it under
[env.dev]
inwrangler.toml
.
- Generate a KV namespace using
-
Manage Secrets:
-
Add (env) secrets using
npx wrangler secret put <KEY> --env dev
. -
For the private key, execute the following (replace
YOUR_APP_PRIVATE_KEY.PEM
with the actual PEM file path):echo $(openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in YOUR_APP_PRIVATE_KEY.PEM) | npx wrangler secret put APP_PRIVATE_KEY --env dev
-
-
Deploy the Kernel:
- Execute
bun run deploy-dev
to deploy the kernel.
- Execute
Inputs are received within the workflow, triggered by the workflow_dispatch
event. The plugin is designed to handle the following inputs:
interface PluginInput {
stateId: string; // An identifier used to track the state of plugin chain execution in Cloudflare KV
eventName: string; // The complete name of the event (e.g., `issue_comment.created`)
eventPayload: any; // The payload associated with the event
settings: string; // A string containing JSON with settings specific to your plugin
authToken: string; // A JWT token for accessing GitHub's API to the repository where the event occurred
ref: string; // A reference (branch, tag, commit SHA) indicating the version of the plugin to be utilized
}
Example usage:
const input: PluginInput = {
stateId: "abc123",
eventName: "issue_comment.created",
eventPayload: {
/* ... */
},
settings: '{ "key": "value" }',
authToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
ref: "refs/heads/main",
};
Data is returned using the repository_dispatch
event on the plugin's repository, and the output is structured within the client_payload
.
The event_type
must be set to return_data_to_ubiquibot_kernel
.
interface PluginOutput {
state_id: string; // The state ID passed in the inputs must be included here
output: string; // A string containing JSON with custom output, defined by the plugin itself
}
Example usage:
const output: PluginOutput = {
state_id: "abc123",
output: '{ "result": "success", "message": "Plugin executed successfully" }',
};
The kernel supports 2 types of plugins:
- GitHub actions (wiki)
- Cloudflare Workers (which are simple backend servers with a single API route)
How to run a "hello-world" plugin the Cloudflare way:
- Run
bun dev
to spin up the kernel - Run
bun plugin:hello-world
to spin up a local server for the "hello-world" plugin - Update the bot's config file in the repository where you use the bot (
OWNER/REPOSITORY/.github/.ubiquibot-config.yml
):
plugins:
- skipBotEvents: true
uses:
# hello-world-plugin
- plugin: http://127.0.0.1:9090
runsOn: [ "issue_comment.created" ]
with:
response: world
- Post a
/hello
comment in any issue - The bot should respond with the
world
message (example)
How it works:
- When you post the
/hello
command the kernel receives theissue_comment.created
event - The kernel matches the
/hello
command to the plugin that should be executed (i.e. the API method that should be called) - The kernel passes GitHub event payload, bot's access token and plugin settings (from
.ubiquibot-config.yml
) to the plugin endpoint - The plugin performs all the required actions and returns the result
A screencast tutorial on how to set up and run a hello world plugin is available at wiki.
To start Jest tests, run
bun test