Devo is a self-hosted, code-first automation builder. Think n8n or Activepieces, but without a workflow canvas: every automation is JavaScript/TypeScript code that you can generate with an AI agent, edit in the browser, and deploy behind a trigger.
It is built for complex automations where node graphs become hard to reason about. Instead of wiring boxes together, you describe what you want, review the generated main.ts, adjust .env and package.json, and run the task as normal code. Because each task has its own package.json, tasks can import npm packages like a regular JavaScript/TypeScript project.
Tasks can run from:
- Manual UI runs
- Opaque webhook endpoints
- Cron schedules with timezone support
Each task owns its own main.ts, .env, and package.json files. Task settings live in the local database and are edited with normal UI controls. Devo stores app data locally and runs task code as child processes.
Devo is early MVP software for local and self-hosted use by trusted users.
Do not treat the current runtime as a secure multi-tenant sandbox. Task code runs in a separate process with timeouts and output limits, but it still runs on the host with the permissions available to that process.
Run Devo with Docker:
docker run --rm \
-p 3000:3000 \
-v devo-data:/data \
-e AUTH_SECRET="$(openssl rand -base64 32)" \
-e ORIGIN="http://127.0.0.1:3000" \
sayem314/devo:latestOpen:
http://127.0.0.1:3000
The image stores Devo data in /data by default. Mount a persistent volume there for users, tasks, provider settings, task files, installed packages, and run history.
The first registered account becomes the admin account. After the first account exists, public registration is blocked. Admin users can add more users from the Users page.
Install dependencies:
bun installCreate a local env file:
cp .env.example .envUpdate .env:
AUTH_SECRET=replace-with-your-generated-secret
ORIGIN=http://127.0.0.1:5173Run the dev server:
bun run devOpen:
http://127.0.0.1:5173
App-level configuration lives in environment variables. For local development, copy .env.example to .env; Vite reads that file while running the dev server. For production, set the same variables in your process manager, container, or hosting environment.
| Variable | Default | Required | Description |
|---|---|---|---|
AUTH_SECRET |
none | Yes | Secret used by auth. Must be at least 16 characters. |
ORIGIN |
none | Yes | Public app origin for auth and SvelteKit form checks. |
DEVO_DATA_DIR |
.devo |
No | Local DB, task files, run files, and installed task packages. |
DEVO_TASK_RUNTIME |
auto |
No | Task runtime: auto, bun, or node. |
DEVO_WORKERS |
2 |
No | Number of task workers. |
DEVO_TASK_TIMEOUT_MS |
30000 |
No | Maximum runtime for a task process before it is killed. |
DEVO_TASK_MAX_OUTPUT_BYTES |
1048576 |
No | Maximum captured stdout/stderr per run. |
DEVO_TASK_MAX_LOG_LINE_BYTES |
16384 |
No | Maximum stored bytes for one log line. |
DEVO_TERMINAL_TIMEOUT_MS |
120000 |
No | Maximum time for an editor terminal command. |
DEVO_SCHEDULER_INTERVAL_MS |
15000 |
No | How often cron tasks are checked. |
DEVO_RUN_RETENTION_DAYS |
30 |
No | Run history retention by age. Use 0 to disable. |
DEVO_MAX_RUNS_PER_TASK |
100 |
No | Run history retention by count per task. Use 0 to disable. |
Use task-level .env files for task secrets such as API keys, database URLs, and integration tokens. Task env values are edited per task in the editor and are passed only to that task's run process.
Devo validates app-level environment variables at startup with Zod. If a required value is missing or malformed, startup fails with an Invalid Devo environment error.
Configure AI providers in Settings. API keys are stored in the local Devo database and are scoped to the user that saved them.
Supported provider entries:
- OpenAI
- Anthropic Claude
- DeepSeek
- Kimi
- GLM / Z.ai
- OpenRouter
- Custom OpenAI-compatible provider
Each provider can have its own API key, base URL, model list, and default model. Model lists use SDK metadata as a fallback and can be refreshed from the provider API after an API key is saved.
The task editor chat lets you switch provider and model before sending a prompt.
Each task is edited as files:
main.ts: task code.env: task environment variablespackage.json: task dependencies
Task name, description, trigger type, cron expression, timezone, and webhook URL are stored in the database and edited from the task editor settings panel.
If main.ts imports a package that is missing from package.json, Devo shows a warning in the editor. Install dependencies from the task Terminal, for example:
bun add zodFor Node task runtime, use the package manager you want for that task, such as npm install zod.
Task runs execute from that task directory, so dependencies installed from Terminal are available to later manual, cron, and webhook runs.
main.ts:
export async function run(payload: unknown, ctx: { run_id: string; task_id: string; trigger: string }) {
console.log("manual payload", payload);
return {
ok: true,
run_id: ctx.run_id,
at: new Date().toISOString()
};
}main.ts:
export async function webhook(req: Request, ctx: DevoWebhookContext) {
const raw_body = await req.text();
const body = JSON.parse(raw_body) as { id: string };
console.log("received order", {
id: body.id,
run_id: ctx.run_id,
signature: req.headers.get("x-shopify-hmac-sha256")
});
return Response.json({
ok: true,
orderId: body.id
});
}Webhook tasks get an opaque endpoint generated by Devo. Treat that URL like a secret. Rotate it if it is exposed. req is reconstructed with the original method, URL, query string, headers, and raw body. Use await req.text() when signature verification needs the raw body; otherwise use await req.json().
main.ts:
export async function cron(ctx: { run_id: string; task_id: string; trigger: string }) {
console.log("nightly sync started", ctx.run_id);
return {
ok: true,
syncedAt: new Date().toISOString()
};
}Cron tasks use five-field cron expressions. The scheduler runs inside the app process and checks due tasks every DEVO_SCHEDULER_INTERVAL_MS.
Task .env files use KEY=value lines:
DATABASE_URL=postgres://user:password@localhost:5432/app
SHOPIFY_TOKEN=shpat_xxxBlank lines and lines starting with # are ignored. App-level secrets such as AUTH_SECRET and ORIGIN are not passed into task processes.
By default Devo stores local runtime data under .devo:
devo.db- task source files
- per-task package installs
- run files and logs
Set DEVO_DATA_DIR to move this directory:
DEVO_DATA_DIR=/var/lib/devoBack up this directory if you care about tasks, users, AI provider settings, and run history.
For a basic self-hosted deployment:
- Install dependencies with
bun install. - Build the app with
bun run build. - Set
AUTH_SECRETto a strong random value. - Set
ORIGINto the exact public URL, for examplehttps://devo.example.com. - Set
DEVO_DATA_DIRto a persistent directory or mounted volume. - Set
DEVO_TASK_RUNTIMEif you want to forcebunornode; otherwise leave it asauto. - Run the built SvelteKit app with the Node adapter output.
- Put Devo behind HTTPS if it is reachable outside localhost.
Example runtime command:
NODE_ENV=production HOST=0.0.0.0 PORT=3000 node buildFor MVP deployments, run one Devo app instance. The scheduler and worker pool run inside the app process, and multiple app instances can duplicate scheduler work unless you add external coordination.
Keep DEVO_DATA_DIR on durable storage. If this directory is deleted, Devo loses users, tasks, provider settings, run history, installed packages, and local task files.
Current protections:
- Authentication is required for the app and internal APIs.
- The first user is admin; later public registration is blocked.
- Tasks and runs are scoped by owner in the app.
- Webhook URLs are opaque and can be rotated.
- Task processes run separately from the app process.
- The worker pool limits concurrent task runs.
- Per-run timeout kills long-running task processes.
- Output size caps prevent unlimited log capture.
- Stale running runs are cleaned up on startup.
Current limitations:
- Task code is not container-isolated.
- Task code can access the host permissions available to the task process.
- Network and filesystem access are not policy-restricted.
- Dependencies installed by tasks run package install scripts.
- Webhook URLs act like bearer secrets; anyone with the URL can trigger that task.
- This is not ready for untrusted third-party users.
Run Devo only for users you trust. For untrusted users or commercial hosted multi-tenant use, Devo needs a stronger isolation layer such as containers, microVMs, or a dedicated sandbox.
License is not finalized yet.
