wake

package
v3.0.0-alpha2.113 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 4, 2026 License: MIT Imports: 16 Imported by: 0

README

Wake

⚠️ Experimental. Wake is opt-in behind WAILS_USE_WAKE=true and is not the default runtime. The default wails3 build / package / sign / task path is unchanged and runs on the embedded Task runtime as before. The API and feature coverage may change between releases. See Enabling Wake for what the env var actually toggles and what falls back automatically.

Wake is an experimental alternative build runner for wails3. It reads the same Taskfile.yml your project already has — same task/dep/var/ template/include/platform-namespace syntax — and runs it through a Wails-aware executor instead of the general-purpose Task runtime. The goal isn't to replace Task; it's to provide a runner that's purpose-built for the way Wails projects actually build, with semantics, output and defaults that match the rest of the wails3 CLI. If you only ever use Wake, your Taskfiles do not change.

How Wake differs from Task

Both Wake and the Task runtime are compiled into wails3 — neither requires a separate binary install. The differences are about what each one is for.

1. Tailored to the Wails build pipeline

Wake knows the shape of a Wails build: the frontend bundle gets embedded into the binary, the binary gets packaged into platform-specific artefacts, icons and bindings are generated alongside. The executor surfaces those as first-class concepts — for example, the final binary shows up as a labelled artefact at the end of the run instead of being inferred from generates: globs that may also include intermediates. Task is a general-purpose tool; Wake is a build runner with opinions about what a Wails build looks like.

2. Focused build semantics → faster incremental builds

Task only skips a task when its Taskfile declares sources:/generates:. The Wails templates don't declare these for go build / go mod tidy, so Task re-runs the Go compiler and linker on every build. Wake derives those inputs itself from the Go module graph and skips the subprocess when nothing changed:

Command Inputs Wake tracks
go mod tidy go.mod, go.sum
go build module .go files + go.mod/go.sum + the generates of the task's dep closure

The dep-closure tracking means a frontend change (which regenerates frontend/dist, embedded into the binary) still forces a re-link, while a no-op rebuild skips compilation entirely. The cache key includes the expanded command, so changing build flags (e.g. dev vs -tags production) invalidates correctly.

On a no-op rebuild of the badge example this is roughly ~20 ms (wake) vs ~316 ms (task). Cold builds land at the same wall time — they're dominated by npm install, Vite, and the Go compiler.

Cache lives in .wake/cache.json (Task uses .task/).

3. Structured output controlled by wails3

Wake renders through wails3's own Pulse reporter: a pre-painted skeleton of one row per planned step, live status, a colour-coded phase breakdown at the end, and clickable file:line links inside failure panels (via OSC 8 hyperlinks where the terminal supports them). Because output goes through one structured channel rather than raw subprocess stdout, NO_COLOR and non-TTY environments degrade cleanly (CI logs stay readable). The visual is the same identity as the rest of the wails3 CLI; nothing about it changes when the underlying task moves.

4. Parallel execution by default

A task's deps: are evaluated concurrently rather than sequentially. The verdict line shows the parallel speedup when one was earned — e.g. ✓ build succeeded 3.6s 11.6s cpu · 3.2× speedup. Opt out with WAKE_SERIAL=true when stdout interleaving from sibling steps would muddle a specific investigation.

5. Layered local overrides

Wake supports a base Taskfile plus local overrides. Drop a file next to your Taskfile.yml and its definitions take precedence:

File Purpose Precedence
Taskfile.yml base, committed lowest
Taskfile.override.yml / .yaml committed team-wide overrides middle
Taskfile.local.yml / .yaml personal, usually git-ignored highest

Merge semantics (local wins):

  • A task with the same name overrides the base task. List fields (cmds, deps, sources, generates, platforms, status, preconditions, aliases) replace the base when the override provides them; fields the override omits are kept from the base.
  • env and vars merge per key, with the override winning on collisions.
  • A task that exists only in an override file is added.
  • Top-level vars from an override layer over the base vars (override wins per key).

Example — base builds with dev flags, but your machine always builds production:

# Taskfile.yml (committed)
tasks:
  build:
    cmds:
      - go build -o bin/app .
# Taskfile.local.yml (git-ignored, yours)
tasks:
  build:
    cmds:
      - go build -tags production -o bin/app .
  smoke:
    cmds:
      - ./bin/app --selftest

Now build runs your production command and smoke is available with no changes to the committed Taskfile.

Security & trust model

Override files are auto-discovered and applied with no prompt, so it's worth being explicit about what that does and doesn't change:

  • No new capability. A Taskfile already runs arbitrary shell commands, so an override can't do anything that editing Taskfile.yml couldn't. The blast radius is the same: whoever can write build files can run code at build time.
  • Same review path. Taskfile.override.* is committed, so it shows up in ls and PR diffs. Taskfile.local.* is created by the developer on their own machine (and usually git-ignored).
  • Symlinks are followed and includes resolve relative to the override file's directory (including ../), exactly like the base Taskfile — the local layer is not sandboxed.
  • Fail-closed. A malformed override file (bad YAML, missing non-optional include) aborts the run rather than being silently skipped.
  • Opt-out for CI / locked-down builds. Set WAILS_NO_OVERRIDES=true to skip override discovery entirely and build only from the committed base Taskfile, for guaranteed- deterministic behaviour.

Enabling Wake

Wake is gated entirely behind the WAILS_USE_WAKE=true environment variable. With the variable unset (or set to anything other than true), every wails3 command — wails3 build, wails3 package, wails3 sign, wails3 task <name> — uses the embedded Task runtime exactly as before. The default user path is unchanged.

# default: Task runtime, no wake involvement
wails3 build

# opt in: wake drives build / package / sign / `task <name>`
WAILS_USE_WAKE=true wails3 build
WAILS_USE_WAKE=true wails3 package
WAILS_USE_WAKE=true wails3 task <some-task-name>

What the gate covers:

  • commands.wrapTask (used by wails3 build / package / sign) routes through wake.Execute only when useWake() is true.
  • commands.RunTask (used by wails3 task <name>) does the same — wails3 task is consistent with the other verbs.
  • wails3 dev is not affected by this flag yet; the dev watcher still uses its own pipeline.

Falls back to Task automatically on unsupported features

If wake encounters a Taskfile feature it doesn't implement, it hands the whole run off to the embedded Task runtime. The Task runtime is compiled into wails3 — there is no external task binary to install — so the fallback is in-process and instant. Enabling wake is therefore always safe: at worst you get the same behaviour you'd get without the flag.

Features that trigger the fallback:

  • dotenv at the taskfile level
  • output modes other than interleaved
  • requires block
  • interval (taskfile or task level)
  • run modes other than always
  • short in a task
  • defer in a task

Environment variables

Variable Effect
WAILS_USE_WAKE true enables wake-routable wails3 verbs; anything else uses the Task runtime
WAILS_NO_OVERRIDES true skips Taskfile.local.* / .override.* discovery (deterministic builds)
WAKE_VERBOSE Stream subprocess stdout/stderr live instead of capturing it for failure-only display
WAKE_SILENT Suppress task output entirely
WAKE_SERIAL true disables the parallel deps: fanout (parallel is the default)
WAKE_FORCE true bypasses every cache (task + go-cache) for a true clean rebuild
WAKE_DEBUG Log resolver internals (DAG, deps, var refs, exec routing)
WAKE_NOTICE off to silence the per-run "wake (experimental)" notice

Internals

See AGENTS.md for the execution pipeline, cache design, and package-level architecture.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Execute

func Execute(name string, opts ExecuteOptions) error

func IsReported

func IsReported(err error) bool

IsReported reports whether err was already rendered to the build UI.

func Parse

func Parse(path string) (*ast.Taskfile, error)

Types

type ExecuteOptions

type ExecuteOptions struct {
	Dir      string
	Platform string
	Arch     string
	Dev      bool
	Verb     string // command the user ran (e.g. "build"); shown in the header
	Vars     map[string]string
	Silent   bool // show failures only
	Verbose  bool // show commands + live subprocess output
	Debug    bool // show resolver internals (implies verbose detail)
	Parallel bool
	Force    bool // ignore all task and Go caches; run every task from scratch
}

Directories

Path Synopsis
Package fallback drives the embedded Task runtime as a backstop when wake encounters a Taskfile feature it doesn't implement itself (dotenv, requires, interval, run modes other than "always", short, defer, non-interleaved output).
Package fallback drives the embedded Task runtime as a backstop when wake encounters a Taskfile feature it doesn't implement itself (dotenv, requires, interval, run modes other than "always", short, defer, non-interleaved output).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL