Repository navigation
Releases: Nonetss/playbook-runner
Release list
v0.11.4 — long-running tasks keep their stream alive
Highlights
Long-running tasks no longer drop their stream
Runs with a task that stays silent for minutes, such as apt upgrade, dnf update or a slow script, could end as failed with gRPC INTERNAL: Received RST_STREAM with code 2 (Internal server error), even well within the one-hour run limit. Ansible only reports when a task starts or ends, so the backend → gateway → Ansible stream carried no traffic in between, and it was reset.
- Heartbeats. While a run produces no events, the Ansible service sends a small heartbeat frame every 15 seconds. This also covers the Git fetch before the run. The backend discards these frames: they never reach the browser, the live run view or the stored job run events.
- HTTP/2 keepalive on both ends, so a dead connection is detected in seconds instead of at the run deadline.
- Clearer error when a stream is lost anyway. For example, the gateway may restart mid-run. The run now says that the connection to the Ansible service was lost and that the execution may have continued or finished on the hosts, instead of showing a bare
gRPC INTERNAL. Interactive runs get it as a502.
Upgrade notes
Pull the new images and restart. Update the backend and Ansible images together, because the gRPC contract changed on both sides:
docker compose pull && docker compose up -dNo compose changes and no database migration in this release. A new optional variable, RUN_HEARTBEAT_INTERVAL_S on the Ansible service (default 15), tunes the heartbeat interval.
Other changes since v0.11.0
- Built-in "All" inventory group (v0.11.3): it always contains every device and is resolved at run time. Runs, commands, scripts and scheduled jobs can target the whole fleet and pick up devices added later. It is pinned first in Groups (read-only, with its own detail page), in the inventory pickers and in ⌘K search. The group name
all(any case) is now reserved. - Run history loads with infinite scroll instead of a "Load more" button (v0.11.1).
- Section sidebar: the collapse control is a full-width "Collapse menu" / "Expand menu" row (v0.11.1).
- Fixes:
- On phones, the command palette is anchored to the top so the keyboard no longer covers it.
- The page hero keeps its icon on the title's line.
- The active navbar section stays highlighted after picking a menu link.
- Tests:
- API unit tests moved to
packages/api/testsand the Playwright suite toapps/frontend/tests/e2e. - New end-to-end coverage for the All group.
- API unit tests moved to
- Docs, AGENTS.md and OpenSpec specs updated.
v0.11.0 — navbar search & API keys entry
Highlights
Navbar search
Press ⌘K (macOS) or Ctrl+K anywhere in the app, or use the search field next to the account button, to jump to any page without opening the section menus.
- Every page is listed, grouped like the navigation: a General group, then Inventario, Ansible and Bash.
- Records too. Once you type, it lists your playbooks, scripts, scheduled jobs and inventory groups, and opens their edit or detail page. Typing a section name, such as "playbooks", lists all of that section's records. The records come from the same lists the pages already load, so they cost no extra requests once cached.
- Forgiving matching. It ignores case and accents, and every word must match: "ansible historial" finds the run history.
- Recent pages. With an empty query, your last five pages are suggested first. They are stored per user in the browser.
- The search follows the interface language. On small screens it is an icon button next to the account menu.
Navbar layout
- On desktop, the sections now sit on the left, right after the brand and a thin separator. The actions (language, theme, search and account) sit on the right.
- Settings is now the "API keys" entry in the navbar and the mobile menu, since the page only holds API keys. The gear button is gone. The URL is still
/config.
Upgrade notes
Pull the new images and restart:
docker compose pull && docker compose up -dNo new environment variables, no compose changes and no database migration in this release.
Other changes since v0.10.0
- SSO: the sign-in page shows the SSO button only when the backend has SSO configured. A new public auth-config endpoint tells it whether SSO is on.
- Project website at https://nonetss.github.io/playbook-runner/: a guided tour of the app and bilingual docs (English and Spanish), published by GitHub Pages. It includes a full-screen screenshot viewer, copy buttons on code blocks and an architecture diagram with the gateway routing table.
- Tests and CI: unit tests for the API (
bun test) and the Ansible service (pytest), plus Playwright coverage for the navbar search. Lint, type checks and unit tests run on every pull request, and the GitHub Actions are on their Node 24 releases. - Frontend: link prefetching moved off the
prefetchQueryAPI, which is deprecated in TanStack Query 5.104. - README, AGENTS.md and OpenSpec specs updated.
v0.10.0 — standalone gateway & Docker dev environment
⚠️ Deployment change. The frontend image no longer publishes the site: a new gateway image does. Refresh yourcompose.ymlbefore pulling — if you tracklatestwith the old compose file, the site stops answering after a pull. See Upgrade notes.
Highlights
Standalone gateway
Caddy moved out of the frontend image into its own playbook-runner-gateway image, the only place that decides which app serves each request:
- Public HTTP entry point — the only published port.
/rpc,/api,/scalarand/openapi.jsongo to the backend; everything else goes to the frontend, so the browser still sees a single origin. - Internal gRPC router on
:50050(never published). The backend reaches the Ansible service through it; calls are routed by proto package (run.*→ Ansible), events stream through one by one, and cancelling a run still stops Ansible on the runner. Unknown services answerUNIMPLEMENTED. - The frontend image now runs only Astro SSR on
:4321, reachable only inside the Docker network.
Docker dev environment
bun run dev now builds and starts the whole stack in Docker with hot reload — frontend, backend, Ansible service and gateway — using docker compose watch (no bind mounts) on the host network, so every service keeps the same localhost ports as native development. The gateway's production-like site is on http://localhost:8080.
bun run dev:downremoves the dev containers.- The native Turbo workflow is now
bun run dev:local; pair it withbun run gatewayto run only the gateway. - PostgreSQL is not included: point
DATABASE_URLat your own.
Upgrade notes
-
Refresh the compose file, then pull and restart:
curl -fsSL https://raw.githubusercontent.com/Nonetss/playbook-runner/v0.10.0/compose.prod.yml -o compose.yml docker compose pull && docker compose up -d -
No new required variables. The gateway is published on
GATEWAY_PORTand falls back to your existingFRONTEND_PORT, so the public port does not change. Optionally renameFRONTEND_PORT→GATEWAY_PORTin.env. -
ANSIBLE_GRPC_TARGETnow defaults tolocalhost:50050(the gateway); the compose files setgateway:50050. If you run the apps natively without the gateway, setANSIBLE_GRPC_TARGET=localhost:50051inapps/backend/.env.
No database migration in this release.
New optional environment variables
| Variable | Default | Purpose |
|---|---|---|
GATEWAY_PORT |
FRONTEND_PORT, else 4321 |
Host port the gateway is published on |
GATEWAY_IMAGE_TAG |
latest |
Gateway image tag in compose.prod.yml |
Other changes
- CI builds and publishes the gateway image (amd64 + arm64).
- Frontend and gateway healthchecks; the backend waits for the gateway.
scripts/bootstrap.shwritesGATEWAY_PORTandGATEWAY_IMAGE_TAG.- Fixed a syntax error in the cron schedule builder.
- README, AGENTS.md, architecture diagram and OpenSpec specs updated.
v0.9.1 — typography system, job run pagination & UI polish
Highlights
Job run history pagination
jobs.runs.list (/api/v1/jobs/runs/list) accepts optional limit (1–100) and offset parameters. Omitting both still returns every run, so existing API clients keep working. The job detail page now loads its run history in pages as you scroll instead of fetching every run at once.
Searchable playbook picker in the job form
The job form uses the same searchable playbook picker as the run switcher, which makes it easier to pick a playbook in large catalogues.
Typography system rollout
The typography system gained new roles and utilities, and it is now applied across shared components, navigation, auth, dashboard, jobs, playbooks and run screens. Technical inputs use the data typeface consistently.
Other changes
- New
TerminalPanelcomponent shared by the run consoles. - Consistent
focus-ringkeyboard focus styling across shared, app-shell and feature components. - Accessibility: aria labels for extra-variable inputs and better command-input labelling.
- Better responsive wrapping; more compact script form (the language hint now sits next to the content label).
- README updated for Git repository integration and upgrade instructions.
No new environment variables, database migrations or proto changes in this release.
v0.9.0 — Git repositories as a playbook source
Upgrading from v0.7.x? v0.8.0 added the required
CREDENTIALS_ENCRYPTION_KEYenvironment variable. See the v0.8.0 upgrade notes before deploying.
Highlights
Git repositories as a playbook source
Prefer to keep your playbooks in Git instead of the browser? Register a repository from the Playbooks page and press Sync:
- Public HTTPS repositories, or private over SSH using one of your stored credentials as a deploy key.
- Pick a branch — the form lists the remote's branches and preselects the default one — and optionally a subdirectory to scan.
- Every playbook file on the branch shows up as a read-only playbook you can run and schedule. New repositories sync automatically when you save them.
- Runs execute from a checkout of the synced commit, so roles, templates,
group_varsandfiles/next to the playbook just work. The repository'sansible.cfgis ignored. - Job runs record the commit they ran at, shown in the job's run history.
- Copy to Playbook Runner turns a Git playbook into a regular, editable one (only that file is copied).
- Files removed upstream disappear on the next sync; they are only kept (hidden) while a job still uses them, so that job fails with a clear message.
Not supported yet: webhooks/auto-sync, HTTPS token auth and installing Galaxy requirements.yml.
Collapsible sections
Folders and repositories in the playbooks browser can be collapsed; the state is remembered per browser.
Upgrade notes
- Database migration — adds
playbook_repositoriesand new columns onplaybooksandjob_runs. The backend applies it on startup; no manual step. - Update the backend and Ansible images together — the gRPC contract gained
SyncRepository,ListBranchesandDeleteRepository, and the Ansible image now shipsgit. - Repository mirrors are stored in the Ansible state volume (
STATE_DIR/repos).
New optional environment variables (Ansible service)
| Variable | Default | Purpose |
|---|---|---|
GIT_TIMEOUT_S |
120 |
Timeout per git command |
GIT_MAX_REPO_MB |
512 |
Maximum size of a repository mirror |
MAX_CONCURRENT_SYNCS |
2 |
Concurrent repository syncs |
Other changes
- README, AGENTS.md and OpenSpec specs updated.
- Refreshed playbooks and cron screenshots.
v0.8.2 — installable PWA & layout polish
Upgrading from v0.7.x? v0.8.0 added the required
CREDENTIALS_ENCRYPTION_KEYenvironment variable. See the v0.8.0 upgrade notes before deploying.
Highlights
Installable PWA
The frontend can now be installed on mobile: web manifest, theme colour, apple-touch-icon, generated icons, and a network-first service worker that never caches /rpc, /api, /scalar or /openapi.json.
Layout polish
Feature components, forms and UI utilities were aligned for a consistent geometric layout. The dashboard and config pages gained responsive grids (including the API key cards).
Other changes
- Translations and design documentation updated.
No new environment variables in this release.
v0.8.1 — frontend design system overhaul
Highlights
Frontend design system
The whole frontend was rebuilt on a documented design system (apps/frontend/DESIGN.md): one terracotta accent, hierarchy through type, flat surfaces with hairlines, status shown as dot + word, and Space Grotesk / Space Mono typography.
Redesigned pages
Admin, app shell navigation, auth, config, credentials, commands, dashboard, history, inventory, jobs, playbooks, scripts, run and profile were all redesigned on the new shared primitives.
Shared components & resource framework
New shared components (MetadataCell, InlineAlert, QueryState, FieldLabel, SegmentedPicker, DetailFrame, navigation menu, checkbox, table, tabs, textarea) and a definition-driven resource framework (EntityCardGrid/EntityList, ResourceOverview, per-feature definitions). Deprecated card/list components were removed.
Navigation & layouts
A persistent section sidebar, scroll restoration, a scroll-to-top button and reworked layouts and page routes. The run console uses the refreshed terminal frame.
Other changes
- API: credential endpoints relaxed from admin-only to any authenticated user; job metrics use proper SQL aliases.
- i18n translations updated for the redesigned UI.
- E2E tests updated for the new component structure.
- OpenSpec design-system specifications applied and archived.
No new environment variables in this release.
v0.8.0 — admin & RBAC, encrypted credentials, API restructuring
⚠️ Upgrade notes — new required environment variable
The backend now refuses to start without CREDENTIALS_ENCRYPTION_KEY, the AES-256-GCM key used to encrypt SSH private keys at rest (base64 of exactly 32 bytes).
openssl rand -base64 32- Add
CREDENTIALS_ENCRYPTION_KEY=<value>to the backend environment (apps/backend/.envlocally, the backend service incompose). - Back the key up like
BETTER_AUTH_SECRET: losing it makes every stored private key unrecoverable. - Coming from v0.7.x, credentials stored in plaintext must be encrypted once:
- local:
bun run --filter backend credentials:encrypt - Docker:
docker compose exec backend bun dist/encrypt-credentials.mjs(--decryptrolls back)
- local:
Other deployment changes:
- The Ansible service keeps its persistent state (SSH
known_hosts) in the newansible_statevolume at/app/state; the old./.data/ansible-runner:/app/playbookmount andANSIBLE_PLAYBOOK_PATHare gone. - The backend no longer runs a gRPC server (
BACKEND_GRPC_TARGET/ port50052removed). - The Ansible service no longer publishes port
8000on the host; add-f compose.debug.ymlwhen you need it. - SSH host keys are verified according to
SSH_HOST_KEY_POLICY(accept-newby default,strict,off). Optional.
Highlights
Admin & role-based access control
New admin dashboard with user management and role assignment. Procedures are gated by role, and users in the pending role can no longer reach protected endpoints until an admin approves them.
Encrypted credentials
SSH private keys are encrypted at rest with AES-256-GCM (v1: prefix), are never returned by the API, and are decrypted only when a run is built.
API restructuring
The run, credentials, inventory, jobs, playbooks, scripts and health endpoints were reorganised into per-feature modules with dedicated input/output schemas, central schema definitions and shared scheduling/execution utilities.
Ansible runner hardening
New SSH host-key policy module, cleaner event handling and a leaner gRPC surface (the gRPC demo was removed).
Other changes
- Auth: dedicated hooks and an improved sign-in flow; generic OAuth stays optional.
- Frontend: improvements across inventory, jobs, playbooks, scripts, credentials and config; extra actions on
ResourcePage; redesigned job form. - Docker: smaller images (
oven/bun:1.3.14-slimbackend runtime), healthchecks that also probe gRPC:50051, andcompose.debug.yml. - Build:
tsdownwithdeps.alwaysBundle, so the production image ships onlydist/; per-package TypeScript configuration. - Dependencies updated (oRPC, Hono, TypeScript, Pino, …).
- i18n (English/Spanish), README architecture section and AGENTS documentation updated; OpenSpec changes archived.
v0.7.1 — i18n, resource hooks & safer run consoles
Highlights
Internationalization across the product surface
Modals, dialogs, forms, page chrome, and run consoles now pull copy through translation hooks instead of hard-coded strings. English and Spanish locale files were expanded in step, so labels, confirmations, empty states, and error messages stay consistent as new UI is added. Navbar overflow menus and the API key card actions menu were also tightened for accessibility and clearer context (e.g. action labels that include the resource name).
Standardised resource data hooks
Every major resource type — API keys, credentials, device groups, devices, groups, jobs, playbooks, and scripts — now has a dedicated feature hook built on useHydratedQuery and TanStack Query mutations. Hooks follow a uniform kebab-case file naming convention, include optimistic updates where it improves responsiveness, and integrate translation for user-facing feedback. Feature code no longer scatters raw oRPC calls and cache invalidation logic across page components.
Safer, more predictable run consoles
Starting a run from commands, playbooks, scripts, or jobs now opens a confirmation step that summarises targets, forks, sudo state, and extra variables before anything is sent to the runner. While a stream is active, a shared stop-watching control lets you detach from the live feed without cancelling the underlying job, and the playbook run modal warns when closing mid-run. Live-run lifecycle is centralised behind a shared stream hook with generation-based detachment, so ping, playbook, script, command, and job watchers all behave the same way.
Shared resource card & inventory picker
Resource cards across credentials, devices, groups, playbooks, scripts, and related listings now share a single card shell component, and run surfaces (commands, playbooks, scripts, jobs) share one inventory selection picker. Named product typography utilities (type-page-title, type-section-heading, etc.) replace ad-hoc heading classes so hierarchy stays consistent page to page.
Run status visuals & shared stream banner
Status components gained a terminal variant tuned for console-adjacent phases, giving live-run feedback a distinct look from generic badges. The run-stream status banner is reused across ping and job detail consoles so watching, stopping, and error states read the same everywhere.
Other changes
- Refine inventory and jobs section routing so
/inventoryand/jobsact as proper section entry points with dedicated sub-routes and legacy redirects preserved. - Rework the job form around the
Jobtype, native<select>controls, and explicit null handling for optional fields. - Consolidate job feature imports behind a barrel
indexand remove unused diagnostics components (ApiStatus,DashboardContent). - Add a
useIsMobilehook for viewport-aware layout decisions. - Improve layout and styling consistency across dashboard, profile, commands, history, playbook, and script pages (padding, height calculations, viewport meta).
- Route device and script icons through the semantic icon registry (
device,fileCode). - Document the shared resource card shell and inventory picker under
docs/design/.
v0.7.0 — shared UI patterns, section navigation & cron builder fix
Highlights
Frontend consolidation around shared UI primitives
Resource pages, lists, dialogs, and the navbar were each re-implementing the same interaction decisions. This release introduces shared data-display, form, and layout primitives (plus the small shadcn primitives they need) and reworks every resource surface to use them. Result: more coherent visual language, less duplication, and a single place to evolve interaction behaviour.
Section landings & split routes for Inventory and Jobs
The Inventory root used to be a tabbed page that jumped straight to Devices, and Jobs opened the scheduler directly while run history lived on a separate top-level route. /inventory and /jobs are now proper section landings with a reusable WithSidebar layout, and each gets dedicated sub-routes:
- Inventory →
/inventory/credentials,/inventory/devices, and/inventory/groups(with/inventorykept as a section overview and legacy/credentialsredirecting to its canonical home). - Jobs →
/jobs/schedulerand/jobs/history(with the legacy/historyroute redirecting to its canonical home).
Site navigation is now metadata-driven with localized labels, icons, descriptions, nested sub-items, and a dropdown for sections with related routes.
Graphical cron builder fixed
The cron schedule dialog would silently reset its schedule mode whenever you edited a minute/hour or weekday field, which made it feel broken when tweaking an existing schedule. Editing time fields now leaves the frequency choice stable, and the hour/minute and weekday controls are now dedicated NumberStepper and SegmentedPicker primitives — building a schedule visually behaves predictably.
Run consoles get jump-to-latest
All run consoles (playbook, command, script, and job detail) share a new jump-to-latest control with sticky-tail scroll behaviour, so following a live run no longer requires manual scrolling.
Backend ↔ runner service: response types & event handling
The gRPC runner service got updated response types and a refactor of its event handling across the Python service, the generated TypeScript stubs, and the run.proto contract.
Other changes
- Centralise every lucide icon behind a semantic registry keyed by intent (
actions,controls,resources,status,scheduling, …) so feature code depends on names, not on a particular icon library. - Nest Credentials under Inventory navigation and route it through the shared primitives.
- Use semantic colours for play recap outcomes and tidy run-status metadata formatting.
- Ignore
.agents/and.claude/directories and configure VS Code to format proto files via the.codextooling.