A local, single-binary manager for Linak / IKEA IDÅSEN sit-stand desks over Bluetooth LE. It remembers your desks and height presets in an embedded database and drives them — move up/down, stop, go to an absolute height or a saved preset — through either an interactive terminal UI or an MCP stdio server.
It is the stateful successor to the godesk CLI: where godesk was stateless (a fresh BLE
connection and a MAC on every invocation), deskbluez persists your desks and presets and reuses
godesk's proven Linak GATT protocol.
The product contract lives in docs/SPECIFICATIONS.md; the code follows
the spec, and the two change together in the same commit.
- Persist desks (name, MAC, model, calibration, display unit) and named height presets per desk in one embedded bbolt file.
- Scan for nearby BLE desks and save them for repeated use.
- Hold a persistent BLE session and drive the desk: up, down, stop, goto absolute height, goto preset, read live status — clamping targets to the desk's range and aborting on detected resistance.
- Two surfaces over the same data, selected at launch:
deskbluez tui— interactive terminal UI (tview).deskbluez serve— MCP stdio server (mark3labs/mcp-go), so an AI assistant can drive the desk.
Local-only by design: one executable, no network services, no cloud, no daemon. The single system dependency is the OS Bluetooth stack (BlueZ via D-Bus on Linux, the primary supported platform).
- Go 1.26+
- Linux with a working Bluetooth stack (BlueZ / D-Bus) — the primary supported platform.
- Dev tools:
gofumptandgolangci-lint(v2).
go install mvdan.cc/gofumpt@latest
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latestmake build # compile
make run # run (defaults to TUI mode)
make test # go test ./... -race -cover
make lint # golangci-lint run
make fmt # gofumpt -w .
make check # fmt + tidy + lint + testRun a specific surface directly:
go run . tui # interactive terminal UI
go run . serve # MCP stdio server
go run . version # print versionmain.go # thin entry point: pick a mode (tui/serve) and dispatch
internal/models/ # plain domain structs + pure helpers (no persistence imports)
internal/db/ # the only package that imports bbolt; repositories return models
internal/desk/ # BLE Controller: pure Linak protocol, tinygo-bluetooth impl, in-memory impl
internal/server/ # MCP server surface (tools, resources, prompts) over mark3labs/mcp-go
internal/tui/ # tview terminal UI (desk list, control, scan/add, presets, edit)
docs/SPECIFICATIONS.md # the product contract — single source of truth
.claude/rules/ # layer-specific conventions (db, mcp-server, tui, testing, CI, spec)
Status: all spec surfaces are implemented and tested —
internal/models,internal/db,internal/desk,internal/server(MCP), andinternal/tui. SetDESKBLUEZ_BACKEND=memoryto run either surface offline without a Bluetooth adapter;DESKBLUEZ_DBoverrides the database path.
See LICENSE if present.