Skip to content

Feature list

Everything Walis does today, grouped by what you would go looking for. Each line is a feature that exists in the shipping build — not a roadmap.

Jobs and scripts

FeatureNotes
Two authoring modesScript mode is a shell buffer you edit directly. Flow mode builds the script from actions.
29 built-in actionsEight categories: general, files, Git, Node, .NET, containers, deployment, checks. See Actions.
Custom actionsA parameter declaration plus a shell template, stored as JSON. No code.
Compiled, not interpretedA flow compiles into Jobs.Command on save, so runners never need to know actions exist.
AI script reviewSends the script to your configured provider and reports back what looks wrong.
Import and exportJobs and custom actions as JSON, matched by name, with an overwrite switch. Identifiers and build history stay put.

Switching from flow mode back to script mode keeps the compiled script; switching the other way restores the steps. Manual edits made in script mode are not preserved across a switch back to flow.

Builds and steps

FeatureNotes
Per-step statusEvery step keeps its own status, output, exit code and duration.
Independent shellsSteps share a working directory but not environment variables. Append KEY=VALUE to $WALIS_ENV_FILE to pass values on.
Parallel groupsMark a step "run alongside the previous step"; consecutive marks form one group run with Task.WhenAll.
Build matrix{"NODE":["20","22"],"OS":["mac"]} fans out into one build per combination, capped at 50.
Build cacheNamed paths are saved on success and restored before the next run — after the workspace is cleaned, not before.
ArtifactsCopied out on success, capped at 200 files / 64 MB, downloadable from the log window.
Live outputstdout and stderr interleave in real order; the log window re-fetches every two seconds and follows the tail until you scroll up.
TimeoutA whole-build budget. Each step receives whatever time is left.
RetentionBuilds, artifacts and audit entries share one retention setting, swept hourly.

continueOnError on an action lets the build carry on past a failure; without it, later steps are marked Skipped.

Triggers

  • Manual — a button on the job list and job detail.
  • PushPOST /api/webhooks/push accepts GitHub, GitLab and a plain {repository, branch} body, matched against jobs by branch and normalised repository address. Signatures verified via X-Hub-Signature-256, X-Gitlab-Token or X-Walis-Token once a webhook secret is set.
  • Cron — five-field expressions evaluated once a minute in the configured time zone.

All three can be enabled on the same job.

Runners

FeatureNotes
Built-in local runnerRuns in the API process. Concurrency comes from the system setting.
Remote agentswalis-runner polls, claims work, and reports back. No runtime to install — it is a self-contained binary.
Shared step loopBuildStepSequence is the same code locally and remotely; only the sink differs (database vs HTTP).
Labels and slotsFree-form labels, plus a slot count per runner.
HeartbeatReported every minute; runners silent for five minutes are marked offline and can raise a notification.

Databases and high availability

ProviderMultiple nodesNotes
SQLiteNoThe default. One file, nothing to run.
PostgreSQLYes
MySQL / MariaDBYes
SQL ServerYesAzure SQL included.

Point several API nodes at one server database and they share the work:

  • Atomic build claiming — two nodes can race for the same queued build; exactly one wins the QueuedRunning transition.
  • Lease-based leader election — cron evaluation, offline detection, retention cleanup and scheduled backups run on one node at a time. Leases expire, so a dead holder is replaced without a separate coordination service.
  • Cross-node polling — a build queued on one node is picked up by whichever node has capacity.
  • Per-node recovery — a restarting node recovers only its own interrupted builds.

GET /health reports the provider, the node name and whether the deployment is clustered. Migrating from SQLite is a backup and a restore, because the archive is engine-agnostic. See High availability.

Isolation and build safety

Builds run as the same user as the service, so these are the defences that matter.

On every platform:

  • Allowed working directories — when the list is non-empty, a build whose working directory is outside it fails immediately rather than running somewhere unexpected.
  • Environment scrubbingConnectionStrings__* is removed from the build environment, so a build cannot discover where the database lives.
  • Workspace cleaning — clears directory contents only, and refuses disk roots, home directories and suspiciously shallow paths.

On macOS, additionally:

  • Sandbox — with IsolateBuilds on (the default), each step is wrapped in sandbox-exec and cannot read or write the Walis data directory or any path you list. This layer is macOS-only: sandbox-exec has no equivalent that Walis uses on Windows or Linux, and on those platforms the setting simply has no effect.
  • Symlink resolution — sandbox paths are resolved segment by segment, so rules on /tmp and /var/folders actually bite.

Neither layer is real isolation — same user, same machine. They stop a build script from casually reading the database or credentials. For stronger boundaries, run builds on a dedicated runner under its own account, or in a container your script starts.

Access control

FeatureNotes
Optional sign-inOff by default. With it off, everyone is treated as an administrator.
Password storagePBKDF2-SHA256. Sessions live in the database.
One-time passwordsTOTP with backup codes; can be required for all accounts.
Rolesviewer, operator, administrator.
Per-job permissionsEach job has a view role and a run role.
Quiet 404sA job you cannot see returns 404, not 403 — the identifier does not confirm the job exists.
API keyswalis_<prefix>_<secret>, PBKDF2-hashed, shown once. A key cannot mint another key.

Plugins

Action plugins run in Jint, a pure-C# JavaScript interpreter, and return a shell snippet rather than behaviour — so you can read what a plugin will run before installing it.

  • Declared capabilities only — network access is limited to named domains; secrets can only be injected into headers via withSecret, never read by the plugin.
  • Resource ceilings — 10 s timeout, 8 MB memory, 500 000 statements, 64 recursion levels.
  • AI drafting — generated plugins have permissions cleared, type and version forced, and are never auto-installed.
  • Administrator only — installing a plugin means adding code that will run.

Notifications

Email, Slack (incoming webhook) and a custom JSON webhook, each independently switchable and testable. Five events: build failed, build recovered, every successful build, build timed out, runner offline. Quiet hours suppress everything except failures. Delivery history is kept.

AI assistance

Claude, Gemini and Codex. Claude uses the official Anthropic SDK; the other two use their REST endpoints. Used for script review, build failure analysis and plugin drafting. Every call is logged with provider, model, purpose, duration, token usage and result — prompt content is never stored.

Backup and restore

  • Scheduled by cron, encrypted with AES-256-CBC in OpenSSL's Salted__ format — restoring does not require Walis.
  • Packs the database (VACUUM INTO), artifacts, extra paths you list, and optionally PostgreSQL via pg_dump.
  • Destinations: local path, S3-compatible (self-signed SigV4), Dropbox, Google Drive, OneDrive. None shell out to an external binary.
  • Restore is database-agnostic and can target a different database engine than the source.

A passphrase is mandatory once a remote destination exists, because the archive contains password hashes and credentials.

Observability

  • Dashboard — active jobs, 7-day success rate, running count, failure count, build trend, recent builds, runner load and per-job success rate.
  • PrometheusGET /metrics, outside /api, so scrapers need no key.
  • Audit log — jobs, builds, runners, environment variables, settings, notifications and translations, sharing the retention setting.

Integrations

  • REST API for everything the UI does.
  • MCP served at /mcp by the API itself, so an agent needs only a URL and a key — nothing installed locally. Source/Walis.Mcp is a stdio bridge for clients that cannot speak HTTP MCP.
  • Portability — export and import jobs and custom actions as reviewable JSON.

Localization

Traditional Chinese is the source language; English and Japanese ship as dictionaries, overlaid at load time with any overrides you set. Translations are editable in the app, importable and exportable as JSON, with an auto-translate pass for missing entries.

Deployment

deploy/release.sh publishes self-contained binaries — the target machine needs no .NET — for Windows (x64, arm64), macOS (Intel, Apple Silicon) and Linux (x64, arm64, 32-bit arm for Raspberry Pi, and musl/Alpine for both architectures). Each target gets an archive containing the API with the admin UI built in, plus the runner, and the release ships a SHA256SUMS.txt.

On macOS, deploy/install.sh registers two LaunchDaemons: the service (running as an ordinary account, not root) and a restarter watching a trigger file. On other platforms, run the binary under whatever init system you already use. The built-in self-update job pulls, builds, swaps a symlink and touches that file — restarts happen outside the build's process tree, so the build survives long enough to record its own result.

The API serves the admin UI from wwwroot, so the interface and the API share an origin and a port.

Released under the MIT License.