Selfhosted web UI for running GitHub Actions workflows locally, via Docker — wraps act so you get a browser UI (secrets, env/vars, run history, live logs) instead of memorizing CLI flags.
Single user, no auth, no accounts. Meant to run on your own machine or a home server, bound to localhost only.
Download the latest .dmg, open it, drag LocalAction to Applications, launch it. Opens as a real app — Dock icon, native window — no separate browser tab. arm64 (Apple Silicon) only for now.
If your browser doesn't actually start the download (some silently swallow .dmg links), grab it with curl instead:
curl -L -o local-action.dmg https://github.com/adishM98/local-action/releases/latest/download/local-action_darwin_arm64.dmg
open local-action.dmgact ships bundled inside the app — nothing to install for it. Just needs Docker running.
Unsigned (no Apple Developer ID yet) — first launch will warn "Apple could not verify..."; right-click → Open once to bypass it.
brew install adishM98/local-action/local-actionInstalls act automatically as a dependency. Still needs Docker installed and running separately.
Then start it:
local-actionOpen http://localhost:8090.
curl -L -o local-action https://github.com/adishM98/local-action/releases/latest/download/local-action_darwin_arm64 # or _amd64 on Intel
chmod +x local-action
./local-actionNeeds act and Docker installed and running separately — see Requirements below (make bootstrap from a cloned checkout can install those even if you're not building the binary yourself). See docs/RELEASE.md for how releases are built.
For any other platform, or to hack on the source, see below.
- Go 1.25+ (only if building from source)
- Docker, installed and running
act, installed and on yourPATH(act --versionshould work)- Node.js + npm (only if rebuilding the frontend)
Don't have Go/Node/act installed? Run the bootstrap script first — installs whatever's missing (via Homebrew on macOS, apt/act's official installer on Linux), checks Docker is running, and stops with a link if it hits something it can't safely automate:
make bootstrapThen:
make runBuilds the frontend (first time only, or after web/src changes), builds the Go binary, and starts it. Open http://localhost:8090.
Other targets:
| Command | Does |
|---|---|
make bootstrap |
Install missing build dependencies (Go, Node, act); checks Docker |
make build |
Build frontend + binary, don't run |
make dev |
Backend (go run .) + frontend dev server (hot reload) together, Ctrl-C stops both |
make test |
go test ./... + frontend unit tests (npm test) |
make lint |
gofmt -l . + go vet ./... (check only, doesn't modify files) |
make fmt |
gofmt -w . — formats Go files in place |
make install |
Install Go + npm dependencies, no build |
make db-reset |
Remove the local SQLite DB (run history + secrets), keep the binary and built frontend |
make clean |
Remove the binary, local DB, built frontend, and node_modules |
make release-macos VERSION=x.y.z |
Build prebuilt macOS binaries (arm64+amd64) for a GitHub release — see docs/RELEASE.md |
make package-macos-app VERSION=x.y.z |
Build the double-click DMG app (arm64 only) — see docs/RELEASE.md |
Flags:
| Flag | Default | Meaning |
|---|---|---|
-addr |
127.0.0.1:8090 |
Listen address. Change only if you understand the risk — see Security. |
-db |
local-action.db |
Path to the SQLite database file (run history + encrypted secrets). |
-act-bin |
act |
Path to the act executable, if not on PATH. |
- Point it at a repo — enter the absolute path to a local repo (must contain
.github/workflows/) on the Overview page, which also shows Docker/actstatus inline so a missing prerequisite is obvious before you try to run anything, plus the three steps to find that path if you're not sure (cdinto the repo, runpwd, paste it in). Every repo you point it at is saved to a list behind the folder-stack icon (top right) — switch between repos instantly instead of retyping the path each time. - Overview — the landing page: repo health at a glance, currently-running and recent-failure widgets, a recent-runs feed, repository health (success rate, avg build/queue time, longest run), a 7-day success-rate trend, and any pinned (⭐) workflows.
- Workflow Explorer (sidebar) — workflows grouped into categories (CI/Build, Security, Testing, Deployment, Docs), auto-detected from name/path. Search (⌘K) or filter by status (running/failed/success/never run). Pin frequently-used workflows to Favorites. Drag the right edge to resize, or collapse it entirely.
- Run a workflow — pick the trigger event and fill in any
workflow_dispatchinputs (text, choice, or a checkbox for boolean inputs), then click Run. If a job'sif:condition depends on event data GitHub Actions can't auto-derive locally, an event-payload JSON field appears — pre-filled with a best-effort guess when derivable, otherwise blank for manual entry (or a label picker, when the condition is just a label check). A banner warns ifruns-ontargetswindows-*/macos-*—actonly emulates Linux runners. Aself-hostedjob instead offers a Run on picker if you've registered a matching machine under Settings → Runners (see below); otherwise it says so, with nothing to run it on yet. - Watch it run — a drawer with three views: Graph (the job dependency graph, live status per job/step), Logs (the raw stream, grouped by job/step), and Code (the workflow's YAML, syntax-highlighted, with the failed step's block highlighted). Re-run or cancel from the same view. Past runs stay in history for the repo.
- Secrets & variables — add secrets/vars scoped to the repo (optionally to one workflow). Each one is saved either write-only (GitHub-style, never viewable again) or editable — your choice per entry. Encrypted at rest, injected into the run as a temporary dotenv file, deleted immediately after.
- Settings (gear icon) — reset run history, and register Runners: real machines reached over SSH, for
windows-*/macos-*/self-hostedjobsactcan't run in Docker (run:steps only — seedocs/RUNNERS.mdfor what that does and doesn't cover). - Terminal (bottom bar) — a real shell in the repo's directory, multiple tabs, without leaving the app.
Runs execute one at a time, FIFO — triggering a second run while one is in progress queues it. The theme toggle (next to Docker/act status) switches dark/light; it otherwise follows your OS preference.
The UI is a Vite/React app at top-level web/, built to static assets and embedded into the Go binary via go:embed (declared in web/embed.go — go:embed can't reach outside the directory tree of the file that declares it, so the embed lives inside web/ itself, and cmd/local-action imports the resulting web.Dist as an ordinary package). make build/make run handle this automatically (only rebuilds when web/src actually changed). To do it by hand instead:
cd web
npm install # first time only
npm run build
cd ..
go build -o local-action ./cmd/local-actionFor frontend-only iteration with hot reload, use make dev, or by hand (backend must be running separately on :8090):
cd web
npm run devcmd/local-action/ entrypoint: main.go (flags, wiring, HTTP server startup) — plain CLI binary
cmd/local-action-gui/ entrypoint for the DMG app — same server, wrapped in a native webview window
web/ Vite/React frontend (src/, dist/ built output, package.json, embed.go)
internal/
db/ SQLite schema + OpenDB
secrets/ encrypted secrets/vars store, AES-GCM
workflows/ .github/workflows/*.yml parsing, category overrides, saved event payloads
runs/ run history/log storage, act invocation engine (FIFO queue) + the SSH runner executor
runners/ registered SSH runner targets (windows/macos/self-hosted jobs act can't run) — see docs/RUNNERS.md
workspaces/ saved repo list behind the workspace switcher (folder-stack icon)
ws/ WebSocket log-streaming hub for run output
terminal/ pty-backed shell sessions behind the in-app terminal panel
update/ checks GitHub releases for a newer version (check-only, never installs)
httpapi/ HTTP route wiring
assets/ source logo assets used to generate the DMG app's Dock icon
testdata/sample-repo/ a real workflow file, for manual end-to-end testing
docs/ architecture notes, design spec, user guide, release process
scripts/ bootstrap.sh (dev setup), release-macos.sh + package-macos-app.sh + release.sh
(prebuilt-binary + DMG releases), flatten-icon.swift (Dock icon generation)
homebrew-tap/ Formula/local-action.rb — synced into the separate homebrew-local-action tap repo on release
- No authentication. Anyone who can reach the listening address can trigger workflow runs (arbitrary code execution via Docker) and manage secrets. Keep
-addron127.0.0.1(the default) unless you understand and accept that risk — don't expose this to a network you don't fully trust. - Secrets/vars are encrypted at rest with AES-256-GCM. The encryption key lives at
$XDG_CONFIG_HOME/local-action/seed.key(or the OS equivalent), generated once on first run, permissions0600. - Decrypted secret values are written to short-lived temp dotenv files (
0600) only for the duration of a run, then deleted.
make test # go test ./... + npm test
make lint # gofmt -l . && go vet ./... (check only)
make fmt # gofmt -w . (formats in place)See docs/ARCHITECTURE.md for how the pieces fit together. See docs/USER_GUIDE.md for a full walkthrough of every screen and feature, docs/RELEASE.md for how prebuilt macOS binaries are built and published, and docs/RUNNERS.md for how custom windows/macos/self-hosted runner support works (and its run:-steps-only scope) beyond what act can emulate. Contributions welcome — see CONTRIBUTING.md.

