A modern lighting-control application for club/DJ operators running small live shows, built in Go with a Wails desktop interface.
GOLC combines a fast, modular show-authoring workflow with TypeScript scripting, autonomous LLM control, and a well-documented API, so people, scripts, external programs, and AI agents can all create and operate fixture patches, scenes, chases, and show playback through the same system. The first release targets Windows and outputs Art-Net.
Status: early development, pre-alpha. GOLC ships in dependency-ordered phases; see Roadmap. v1.0 (Phases 1–8) shipped 2026-07-27 — the deterministic core: offline configuration and delivery traceability, modular fixtures and deployments, deterministic show programming and playback, observable Art-Net output, durable show storage/recovery, the full Wails authoring and operator surface (on-screen and keyboard playback, the safety cluster, the operator-surface builder, and generic MIDI Note/CC learn with soft takeover, verified against real hardware), the versioned external
/v1control API (Chi+Huma, scoped API-key auth, revision-checked/dry-run/idempotent mutations and atomic batching, revisioned SSE, and a drift-checked generated OpenAPI contract), and isolated capability-limited TypeScript scripting (sandboxed Deno runtime, generated typed SDK, Monaco editor, and a real CDP source-mapped step debugger) are implemented and tested. Phases 9–11 (provider-neutral AI autonomy, Windows release qualification, telemetry) are planned next; see.planning/MILESTONES.md.
No installer exists yet (pre-alpha) — this builds and runs GOLC from source. Requires Go already installed.
# 1. Install Mage once (needs GOPATH/bin, usually ~/go/bin, on your PATH)
go install github.com/magefile/mage@v1.17.2
# 2. Provision everything else and build the CLI + desktop app
mage Bootstrap
mage Build
# 3. Run it. `mage Bootstrap` already provisioned the midicat helper
# golc-desktop needs on PATH just to START (not just to use MIDI — see
# "MIDI requires midicat" below); `mage Run` is what actually puts it
# on PATH for the process that needs it.
mage RunIf mage "isn't recognized" after step 1, your shell's PATH doesn't include Go's bin directory yet — open a new terminal (PATH changes don't apply retroactively), or check go env GOPATH and add <that path>\bin to PATH yourself.
MIDI hardware itself is optional — GOLC's full playback workflow works from keyboard and on-screen controls alone. But the underlying driver library (gomidi/midicatdrv) panics at process startup if its midicat helper binary isn't on PATH, even when you have no MIDI controller and never touch the MIDI UI. This is a known upstream limitation (a hard crash from a package init(), not a recoverable error — see internal/midi/driver.go's doc comment for the full analysis). mage Bootstrap provisions midicat automatically (config/toolchain.toml's [go_install.midicat]) into the project-local .tools/cache/go-bin, and mage Run is the launcher that actually puts that directory on PATH for golc-desktop's own process — nothing inside golc-desktop itself can do this, since the panic happens in a package init() that runs before its main() ever gets a chance to fix PATH.
Running the compiled binary directly instead of mage Run (./golc-desktop / .\golc-desktop.exe, e.g. after copying it out of the repo) is not covered by this fix: it inherits whatever PATH the invoking shell already has, same as any other program. If you go that route, make sure .tools/cache/go-bin (or wherever go install gitlab.com/gomidi/tools/midicat@v1.0.7 put the binary) is on PATH yourself first. This is a real, currently-open gap for a future packaged end-user launcher — see .planning/phases/06-wails-authoring-and-operator-surface/deferred-items.md.
That's the whole app. For the CLI's config/test/docs commands, the full command surface, and every Mage target, see Getting started and Running GOLC below.
- TL;DR
- Why GOLC
- Planned capabilities (v1)
- Architecture principles
- Getting started (contributors)
- Running GOLC
- Installing on Linux
- Configuration model
- Repository layout
- Roadmap
- Tech stack
- Contributing
- License
The project is motivated by frustration with QLC+: show setup takes too long, the workflow feels clunky, and it lacks real scripting. GOLC's core value proposition:
An operator can author a modular show once, adapt its fixture pools to different deployments in one or two actions, and hand a simple controller surface to another person for reliable playback.
The primary workflow is front-loaded show authoring followed by repeated deployment. A show is reusable with all or a subset of the available fixtures, and pool-size changes update dependents through a reviewable impact plan instead of manual reprogramming.
- Complete show workflow — patch fixtures, organize attributes, build looks/scenes and chases, play them back, save and restore shows.
- Modular fixture pools — shows model reusable logical pools independently of a deployment's concrete fixture count and addresses; replacement fixtures map by semantic capability (intensity, color, position, beam) rather than raw channel numbers, with review before commit.
- Human-readable fixture definitions — a strict, schema-validated YAML 1.2 subset with duplicate-key rejection and deterministic normalization; import from Open Fixture Library plus first-class custom definitions.
- Tempo-aware scenes — bar-based loops synchronized to a global BPM (typed or tap tempo), with independently swappable color themes, chases, and motion presets blended through reusable transition presets.
- Reliable Art-Net output — deterministic playback and frame output that never depend on UI rendering, storage, scripts, API clients, or LLM inference.
- Operator surfaces — full keyboard and on-screen playback, plus a constrained generic MIDI surface (Note/CC learn, soft takeover) that a less-experienced operator can learn quickly.
- TypeScript automation — create, run, and debug capability-limited scripts in a supervised, isolated runtime using a generated typed SDK.
- Versioned external API — external programs inspect and control every public capability through
/api/v1, with the same typed command model as the desktop app. - Provider-neutral AI — hosted or local LLMs can draft fixture definitions and, under an explicitly armed, time-bounded lease, operate the application — always validated, audited, and subject to immediate operator override (Revoke Automation).
Out of scope for v1: protocols beyond Art-Net, multi-user/distributed operation, browser or mobile clients, and official macOS/Linux support (portability is preserved architecturally; Windows is qualified first).
- One typed command model. UI actions, TypeScript scripts, API clients, and LLM tools all route through shared domain commands, so every control surface behaves consistently.
- Deterministic output path. Playback timing and Art-Net output are isolated from everything else — a stalled UI, slow script, or unreachable LLM provider cannot delay or corrupt frames.
- Review before structural change. Pool resizing and fixture substitution default to a deterministic impact preview before anything is applied; nothing is approximated silently.
- Operator authority is local. Revoke Automation blocks AI and scripts, cancels their queued actions, and freezes the current look without waiting on any runtime or provider. Blackout is a separate immediate intensity control.
- Offline-safe delivery tracking. Planning artifacts keep durable local identities; Linear reconciliation runs through credential-external tooling and never blocks local work.
The sole supported entrypoint is Mage (magefiles/magefile.go), run from the repository root. No ecosystem tool — npm or anything else — is invoked directly, and after the first bootstrap everything works offline. The build/dev tooling itself is genuinely cross-platform: mage Bootstrap/Build/Test/PackageFoundation are verified working on Windows, Linux, and macOS in CI (.github/workflows/cross-platform-mage.yml) — see the platform note below for what that does and doesn't mean for the GOLC application.
# One-time (ambient install): Go plus Mage pinned to config/toolchain.toml's version
go install github.com/magefile/mage@v1.17.2
# One-time: provision the rest of the pinned project-local toolchain
mage BootstrapBootstrap verifies every tool archive against committed SHA-256 pins in config/toolchain.toml, installs into a repository-local .tools/ directory with atomic promotion, and never rewrites go.mod, go.sum, or the pin manifest. A second bootstrap with matching install manifests makes zero network calls.
| Target | What it does |
|---|---|
mage Bootstrap |
Provisions every pinned project-local tool (Go, Node, Mage itself) and builds golc-project. Set GOLC_BOOTSTRAP_INCLUDE_LINEAR_SYNC=1 first to also build the isolated Linear-sync Node workspace. |
mage Generate |
Writes every registered schema (schemas/*.json, docs/reference/*) to its committed path. |
mage GenerateCheck |
Reports generated-file drift without writing — what CI runs. |
mage Check |
Runs the strict project configuration concern check. |
mage CheckOffline |
Runs generate, check, build, and test --quick in order with network access denied — the offline core graph. |
mage Build |
Compiles every project package, including cmd/golc-desktop; rebuilds the embedded frontend first if any frontend source changed. |
mage Lint |
Runs golangci-lint over every project Go package with the project-local pinned toolchain. |
mage Govulncheck |
Runs govulncheck over every project Go package with the project-local pinned toolchain, reporting known vulnerabilities in the module's dependency graph. |
mage Dev |
Runs wails dev (hot-reload desktop dev loop) with the pinned Go/Node/Wails toolchains prepended onto its PATH. |
mage Run |
Launches the already-built golc-desktop[.exe] with .tools/cache/go-bin (where midicat is provisioned) prepended onto the PATH of that child process — see MIDI requires midicat. |
mage Test |
Runs the complete test route: the full Go suite plus every registered Node scope (requires the Linear-sync workspace bootstrap above). |
mage TestQuick |
Fast go vet-only quick test route — never touches Node scopes or the Linear process-transport tests, so it works without the Linear-sync bootstrap opt-in. |
mage Package / mage PackageFoundation |
Builds the deterministic developer-tool foundation ZIP (dist/foundation/) — see Configuration model's commands.toml. Windows-AMD64-specific by design (a developer-tool bundle, not a cross-platform release artifact). |
mage Pr |
Runs the exact ordered graph config/commands.toml's commands.pr.steps declares, serially — what check.yml's CI job does step by step, runnable locally. |
mage -l lists all targets from any checkout; golc_list_mage_targets (via tools/golc-mcp) gives the same inventory, plus route/argument/network-policy detail, to MCP-aware tools.
A handful of routes (config inspect/set/explain, test --quick --scope <name>, docs, linear preview/drift/apply) take open-ended arguments (any concern name, any dotted key, any registered scope) that no fixed Mage target can model — Mage targets are fixed, no-argument Go functions — so they go directly through the pinned CLI binary Bootstrap just compiled, at .tools/installs/golc_project/<platform>/bin/golc-project[.exe] (<platform> is windows-amd64, linux-amd64, linux-arm64, darwin-amd64, or darwin-arm64). Alias it once per shell session instead of retyping the full path:
# bash/zsh
alias golc="$(pwd)/.tools/installs/golc_project/<platform>/bin/golc-project"# PowerShell
function golc { & "$PWD\.tools\installs\golc_project\windows-amd64\bin\golc-project.exe" @args }# Inspect committed configuration (deterministic JSON)
golc config inspect runtime --format json
# Set a machine-local override (written to git-ignored golc.local.toml)
golc config set --local runtime.log_level debug
# Explain which layer wins for an effective value
golc config explain runtime.log_level --format json
# Run quick tests for a registered scope
golc test --quick --scope config-localSee docs/development.md for the full contributor walkthrough.
GOLC is pre-alpha (see the status note at the top of this README) — there is no installer or release build yet. "Running it" today means building from source and launching the binaries yourself.
mage Build # compiles every project package, including cmd/golc-desktop
mage Run # launches golc-desktop[.exe] with midicat correctly on PATHmage Build (via mage Bootstrap, which always builds the frontend first) produces golc-desktop[.exe] — the Wails desktop shell with the operator surface, safety cluster, and playback controls. Prefer mage Run to launch it: it prepends the project-local .tools/cache/go-bin (where mage Bootstrap installs midicat) onto the child process's own PATH before exec, which is what actually keeps golc-desktop from panicking on startup — see MIDI requires midicat in the TL;DR. Launching the compiled binary directly (./golc-desktop / .\golc-desktop.exe) instead skips that PATH fixup entirely and is only safe if you've put midicat on PATH yourself first.
golc-project (the same binary Getting started above uses for config/test/docs) also exposes the full show-authoring and control surface as scriptable routes: fixture patching (fixture), pools and deployments (pool, deployment), scenes and chases (scene, programming), playback (playback), operator surfaces (operatorsurface), and Art-Net output (artnet). This is the same typed command model the desktop UI, TypeScript scripts, and (later) the external API all route through — see Architecture principles. Every route is self-registered and discoverable live rather than hand-documented in a second place:
golc docs # generates docs/reference/*.md from source (see the alias set up above)docs/reference/ (regenerated by the command above) has the per-package reference; golc_list_command_routes and golc_list_mage_targets (via tools/golc-mcp, a read-only MCP server over this repository) give the same inventory to MCP-aware tools without grepping source.
Windows is the only platform this project's ROADMAP qualifies for a v1 release — that's a product-support decision (Phase 10), not a build limitation. The Go code and CLI build and pass their full test suite on Windows, Linux, and macOS (proven continuously in CI); the desktop app's platform-specific pieces (global hotkeys, packaging) are written per-OS, but macOS/Linux builds of it are unqualified and untested end-to-end — build and run them yourself at your own risk, don't expect support. See Installing on Linux below for the system-package requirements and a known unpatched upstream limitation.
As noted in Platform note above, Linux is not a qualified v1 platform — this is "how to build it yourself," not a supported install path. The CLI (
golc-project) is fully buildable and testable on Linux with no GTK/WebKit dependency; the desktop app (golc-desktop) additionally needs system packages, one of which (webkit2gtk-4.0) is unavailable on several current distributions with no confirmed fix — see Desktop app: thewebkit2gtk-4.0problem below before investing time in it.
golc-project never imports internal/wails (the Wails/hotkey package) at all, so it has no system-package dependency whatsoever — not X11, not GTK, not WebKit. mage Bootstrap builds exactly this binary (see Every Mage target — it never touches cmd/golc-desktop), so on a bare Linux box with nothing but Go available:
go install github.com/magefile/mage@v1.17.2
mage Bootstrapleaves you a working CLI at .tools/installs/golc_project/linux-<arch>/bin/golc-project, ready to alias per Getting started (contributors). No further steps, no system packages, and it works identically whether or not the packages in the next two sections are ever installed.
mage Build (and mage Test, mage Dev, mage Run) is a different story: those compile or link every project package, including cmd/golc-desktop, so they pull in everything below even if you only care about the CLI.
golang.design/x/hotkey's Linux backend (used by internal/wails for the safety-cluster global shortcuts) cgo-links against X11/Xlib.h at build time and connects to a real X11 DISPLAY from a package init() at process start time.
# Debian/Ubuntu
sudo apt-get update
sudo apt-get install -y libx11-dev xvfb
# Fedora/RHEL
sudo dnf install -y libX11-devel xorg-x11-server-Xvfb
# Arch
sudo pacman -S --needed libx11 xorg-server-xvfbIf you're on a headless machine (CI, SSH, containers) with no real X server, start a virtual one before running golc-desktop or mage Test:
Xvfb :99 -screen 0 1024x768x24 &
export DISPLAY=:99This exact sequence (libx11-dev + Xvfb) is what .github/workflows/cross-platform-mage.yml runs on ubuntu-latest for every PR — see that file for the always-current, CI-verified command.
GOLC pins Wails v2 (v2.13.0), which links against webkit2gtk-4.0 via pkg-config. On a distribution that still ships it:
# Debian 12 / Ubuntu 22.04 and earlier
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev
# Fedora 39 and earlier
sudo dnf install -y gtk3-devel webkit2gtk3-develSeveral current distributions (NixOS unstable, Ubuntu 24.04+, Fedora 40+, Linux Mint 22+) have dropped webkit2gtk-4.0 in favor of webkit2gtk-4.1 (upstream WebKitGTK deprecated the 4.0 API series, which depends on the also-deprecated libsoup2). Wails does have a -tags webkit2_41 build flag intended for this, but as of this writing it lands only on the Wails v3 (alpha) line, not v2 — a v2.10.2 user confirmed in October 2025 that -tags webkit2_41 did not fix the build on a webkit2gtk-4.1-only system (wailsapp/wails#4661; the flag's origin: wailsapp/wails#3345). There is currently no confirmed working fix for building GOLC's desktop app against webkit2gtk-4.1 on Wails v2. If your distribution has already removed webkit2gtk-4.0, the only known workaround is providing an older package snapshot that still has it (e.g. on Nix, pinning a nixpkgs channel/commit that predates the removal). This is also why .github/workflows/cross-platform-mage.yml's ubuntu-latest job doesn't install GTK/WebKit at all — the hosted runner's current Ubuntu image has already dropped webkit2gtk-4.0, so there is nothing to install that would fix it, and the job is continue-on-error: true for exactly this reason (see Platform note).
Once the GTK/WebKit and X11 packages above are installed, building and running the desktop app works the same as Running GOLC describes for any platform:
mage Build
mage RunIf webkit2gtk-4.0 genuinely isn't available on your system, building the CLI (above) is the only currently-working option.
golc.project.toml is the root configuration index. It holds only schema and index metadata and points at logically separated concern files, each of which alone owns its values:
| Concern | File |
|---|---|
| Toolchain pins | config/toolchain.toml |
| Commands | config/commands.toml |
| Generation | config/generation.toml |
| Application defaults | config/application-defaults.toml |
| Runtime | config/runtime.toml |
| Linear integration | config/integrations/linear.toml |
Machine-local overrides live in golc.local.toml (git-ignored, atomically written, strictly validated). Cross-concern values use typed ref:<canonical.key> references so no authoritative value is duplicated. A clean checkout contains no secrets or machine-local state.
cmd/golc-project/ Project CLI Mage bootstraps/delegates to
cmd/golc-desktop/ Wails desktop entrypoint
frontend/ React/TypeScript operator surface (Wails UI)
config/ Committed configuration concern files
docs/ Contributor documentation
internal/bootstrap Pinned-toolchain bootstrap (checksum-verified, atomic)
internal/command Command router, config and test routes
internal/projectconfig Strict concern decoding, layered resolution
internal/trace Planning identity catalog (Linear traceability)
internal/fixture Fixture definitions, pools, deployments
internal/show Show authoring, storage, and recovery
internal/programming Scenes, chases, and playback programming
internal/playback Deterministic show-state and playback loader
internal/artnet Art-Net output and daemon supervision
internal/midi Generic MIDI Note/CC learn and soft takeover
internal/operatorsurface Shared operator-facing command surface
internal/wails Wails host lifecycle and daemon supervision
tests/ Acceptance tests and data-only fixtures
.planning/ GSD planning artifacts (project, roadmap, state, phases)
| # | Phase | Status |
|---|---|---|
| 1 | Offline Foundation and Delivery Traceability | Complete |
| 2 | Modular Fixtures and Deployments | Complete |
| 3 | Deterministic Show Programming and Playback | Complete |
| 4 | Observable Art-Net Live Output | Complete |
| 5 | Durable Shows and Recovery | Complete |
| 6 | Wails Authoring and Operator Surface | Complete |
| 7 | Versioned External Control API | Complete |
| 8 | Isolated TypeScript Automation | Complete |
| 9 | Provider-Neutral AI and Bounded Autonomy | Not started |
| 10 | Windows Release Qualification | Not started |
| 11 | Telemetry, Usage Statistics, and Auto Crash Submission Pipeline | Not started |
Full phase goals and success criteria live in .planning/ROADMAP.md.
- Core: Go (module
github.com/lnorton89/golc) - Desktop UI: Wails, React, TypeScript, Zustand (delivered, Phase 6)
- Output protocol: Art-Net 4 (delivered, Phase 4)
- Operator input: generic MIDI Note/CC learn with soft takeover (delivered, Phase 6 — verified against real hardware)
- External control: versioned HTTP API (Chi + Huma, OpenAPI-generated) (delivered, Phase 7)
- Scripting: TypeScript in an isolated, capability-limited runtime (delivered, Phase 8)
- Fixture format: strict YAML 1.2 subset with versioned schemas
- Show storage: single-file, versioned SQLite
.golcstore with rotating recovery points and verified-backup schema migration (delivered, Phase 5) - Delivery tracking: Linear, reconciled offline-safe from repository-owned identities
Bug reports and design discussion are welcome via issues. GOLC is pre-alpha and the architecture is still settling each phase, so please open an issue before sending a large pull request. See docs/development.md for the contributor walkthrough and AGENTS.md for repository conventions.
GOLC is licensed under the GNU General Public License v3.0.