Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
870cff5
feat(app): TUI actions as buttons, and complete menus
vishr Oct 25, 2026
b96a973
feat(panels): dashboard spec, panel engine and MCP tools
vishr Oct 25, 2026
92580a2
feat(app): dashboard home with docked chat, panels as MCP App cards
vishr Oct 25, 2026
32fdd0c
feat(app): Flow, Projects and Machines as built-in dashboards
vishr Oct 25, 2026
3797311
feat(app): row actions and permission prompts on panels
vishr Oct 25, 2026
4520ff8
feat(app): Chat with a metrics header replaces the web pages
vishr Oct 25, 2026
bcaa1f9
feat(app): Home fills the window with Chat docked beside it
vishr Oct 25, 2026
7480785
feat(app): rebuild the UI on Mantine with Driga's Catppuccin theme
vishr Oct 25, 2026
8954b1b
feat: the Driga service, drigad, owns collection; app and TUI are cli…
vishr Oct 25, 2026
a8d1153
feat(app): borderless header metrics with icons, change badges and sp…
vishr Oct 25, 2026
b9b7a28
fix: start the driga CLI, never drigad, from inside the service
vishr Oct 25, 2026
3cfcbde
feat(app): rows run their main action on click, the rest from a ⋯ menu
vishr Oct 25, 2026
84dc5cc
fix(chat): log failed turns
vishr Oct 25, 2026
2bbb4b2
feat: just dev develops the app's UI in a browser with hot reload
vishr Oct 25, 2026
cfb54bb
feat(app): act on the first UX review
vishr Oct 25, 2026
54d1305
feat(app): review queue, session search, and honest status
vishr Oct 25, 2026
f3f7047
fix(chat): offer Chat only the tools it accepts
vishr Oct 25, 2026
7c5f340
feat(app): act on the second UX review
vishr Oct 25, 2026
ec32698
fix: what a Chat demo turned up
vishr Oct 25, 2026
eb6235a
feat(app): Chat cards summarize; panels open full width
vishr Oct 25, 2026
d4b3fac
feat(app): keep Chat views by asking Chat, as Fanout does
vishr Oct 25, 2026
897990a
feat(app): Chat results expand in place; Chat deletes dashboards
vishr Oct 25, 2026
13d49a2
feat(chat): Chat reads files but never runs commands or writes them
vishr Oct 25, 2026
b30829e
feat(app): drag the line between the board and Chat to resize Chat
vishr Oct 25, 2026
c11f067
feat(ui): a Storybook of every component, panel, page and flow
vishr Oct 25, 2026
e214d83
fix(app): Chat's brief shows no inbox copy while Home loads
vishr Oct 25, 2026
a8716ae
test(ui): stories must render the app's own components
vishr Oct 25, 2026
db85632
chore(ui): a Drafts group for designs awaiting a choice
vishr Oct 26, 2026
6f72c89
ui: two header drafts, clusters with fleet pulse and an attention bar
vishr Oct 26, 2026
f822f55
feat(ui): Fleet view drafts, a sankey and a topology, for the owner t…
vishr Oct 26, 2026
235aaeb
feat(ui): widget drafts for the dashboard
vishr Oct 26, 2026
04652a1
chore(ui): prebundle React Flow and ELK for Storybook
vishr Oct 26, 2026
c0e5554
feat(ui): promote the header, the Fleet page and the widgets from the…
vishr Oct 26, 2026
3951ba0
fix(ui): keep scrollbars off the text they scroll
vishr Oct 26, 2026
283a973
fix(ui): Chat cards keep their actions in the header and stop countin…
vishr Oct 26, 2026
6af4a71
feat: serve machine resources and persistent Fleet activity
vishr Oct 26, 2026
9494b38
test(ui): header stories end with the pointer off every control
vishr Oct 26, 2026
f604214
Fix collected evidence and align terminal attention with the app
vishr Oct 26, 2026
d14f8f9
Secure desktop actions and repair app and service lifecycle
vishr Oct 26, 2026
700a3db
Fix UI lifecycle, Fleet identity and catalog assertions
vishr Oct 26, 2026
40a746e
Align documentation with reviewed service and MCP behavior
vishr Oct 26, 2026
b93fec8
Count waiting sessions consistently in Need you
vishr Oct 26, 2026
dfdae93
Use one live wait rule for the inbox and board
vishr Oct 26, 2026
05d172e
Sanitize Flow session text before laying out cards
vishr Oct 26, 2026
ab54e93
ci: install Chromium with bun x, since the runner has no bunx
vishr Oct 26, 2026
0cbd13d
Fix Windows CI paths and service command expectations
vishr Oct 26, 2026
a33c51b
Fix Linux catalog text layout
vishr Oct 26, 2026
2381205
build: ship drigad without upsetting the release archives
vishr Oct 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 3 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Driga reads the process environment, never dotenv files.
# Precedence: explicit flags > environment > TOML file > defaults.
# Empty environment values are unset. All settings are optional unless stated.
# Restart collector after changing its configuration; CLI/hooks reload per invocation.
# Restart the Driga service after changing its configuration; CLI/hooks reload per invocation.

# motion: string; default=on; optional. Event-bound motion in the terminal Flow map.
# Allowed: on or off.
Expand All @@ -20,9 +20,9 @@
# Allowed: file-only; empty = no exclusions.
# File-only structured list; no environment separator.

# stalled_after: duration; default=10m; optional. Quiet busy-session threshold.
# stuck_after: duration; default=10m; optional. Quiet busy-session threshold.
# Allowed: 0..2562047h47m16.854775807s; zero = default 10m.
# DRIGA_STALLED_AFTER=
# DRIGA_STUCK_AFTER=

# orphan_min_age: duration; default=10m; optional. Minimum orphan candidate age.
# Allowed: 0..2562047h47m16.854775807s; zero = no age minimum.
Expand Down
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# Desktop entries are parsed line by line on Linux; keep them LF on every checkout.
*.desktop text eol=lf
# Generated JSON is compared byte for byte with Go output on every OS.
ui/src/fixtures/fragments.json text eol=lf
ui/src/theme/palette.json text eol=lf
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,20 @@ jobs:
tar -xzf "$archive" just
sudo install -m 0755 just /usr/local/bin/just
rm -f "$archive" just
bun=1.4.3
curl -fsSL --retry 3 -o bun.zip "https://github.com/oven-sh/bun/releases/download/bun-v${bun}/bun-linux-x64.zip"
echo "3e730528d89775f03f87f05c06787c4df4099d0a37f3f252e7b829cb23816e18 bun.zip" | sha256sum --check --strict -
unzip -q bun.zip
sudo install -m 0755 bun-linux-x64/bun /usr/local/bin/bun
rm -rf bun.zip bun-linux-x64
go install golang.org/x/vuln/cmd/[email protected]
go install github.com/rhysd/actionlint/cmd/[email protected]
echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"
# The catalog check runs stories in Chromium; the pinned Playwright
# installs the browser it was built against.
- name: Install Chromium for the catalog check
timeout-minutes: 10
run: cd ui && bun install --frozen-lockfile && bun x playwright install --with-deps chromium
- uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
distribution: goreleaser
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@
.env*
!.env.example
.playwright-mcp/
/ui/storybook-static/
/ui/node_modules/.cache/
61 changes: 50 additions & 11 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,31 @@ builds:
- cmd: 'bash scripts/build-macos-app.sh "{{ .Path }}" "{{ .Os }}" "{{ .Version }}" "{{ .IsSnapshot }}"'
output: true

# Driga.exe, the Windows desktop app: a GUI-subsystem binary that supervises
# the CLI next to it. Other platforms have a single binary.
# drigad, the Driga service: the same program under the name it runs as the
# service by. On macOS the bundle script copies it into the app before
# signing; here it is built for Linux and Windows, beside driga.
- id: drigad
main: ./cmd/driga
binary: '{{ if eq .Os "windows" }}bin/{{ end }}drigad'
env:
- CGO_ENABLED=0
goos:
- linux
- windows
goarch:
- amd64
- arm64
flags:
- -trimpath
ldflags:
- >-
-s -w
-X main.version={{ .Version }}
-X main.commit={{ .FullCommit }}
-X main.date={{ .CommitDate }}

# Driga.exe, the Windows desktop app: a GUI-subsystem binary that installs
# the Driga service and shows its data.
- id: driga-app
main: ./cmd/driga-app
binary: Driga
Expand All @@ -65,6 +88,10 @@ archives:
- id: driga
ids:
- driga
- drigad
# macOS ships drigad inside Driga.app, so its archive has one binary
# where Linux has two.
allow_different_binary_count: true
name_template: "driga_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
formats:
- tar.gz
Expand All @@ -79,8 +106,10 @@ archives:
- README.md
- LICENSE
- NOTICE
- src: internal/web/static/vendor/LICENSES.txt
dst: third-party/vendor-LICENSES.txt
- src: internal/web/app/THIRD-PARTY.txt
dst: third-party/app-THIRD-PARTY.txt
- src: internal/mcp/apps/THIRD-PARTY.txt
dst: third-party/panels-THIRD-PARTY.txt
- src: internal/web/static/fonts/LICENSE.txt
dst: third-party/fonts-LICENSE.txt

Expand All @@ -98,15 +127,21 @@ archives:
formats: [none]
- goos: darwin
formats: [none]
# drigad.exe is a plain file too, so Scoop shims no service binary.
files:
- src: '{{ dir (dir (dir .ArtifactPath)) }}/driga-app_windows_{{ .Arch }}_*/Driga.exe'
dst: .
strip_parent: true
- src: '{{ dir (dir (dir .ArtifactPath)) }}/drigad_windows_{{ .Arch }}_*/bin/drigad.exe'
dst: bin
strip_parent: true
- README.md
- LICENSE
- NOTICE
- src: internal/web/static/vendor/LICENSES.txt
dst: third-party/vendor-LICENSES.txt
- src: internal/web/app/THIRD-PARTY.txt
dst: third-party/app-THIRD-PARTY.txt
- src: internal/mcp/apps/THIRD-PARTY.txt
dst: third-party/panels-THIRD-PARTY.txt
- src: internal/web/static/fonts/LICENSE.txt
dst: third-party/fonts-LICENSE.txt

Expand All @@ -130,15 +165,18 @@ archives:
- README.md
- LICENSE
- NOTICE
- src: internal/web/static/vendor/LICENSES.txt
dst: third-party/vendor-LICENSES.txt
- src: internal/web/app/THIRD-PARTY.txt
dst: third-party/app-THIRD-PARTY.txt
- src: internal/mcp/apps/THIRD-PARTY.txt
dst: third-party/panels-THIRD-PARTY.txt
- src: internal/web/static/fonts/LICENSE.txt
dst: third-party/fonts-LICENSE.txt

nfpms:
- id: driga
ids:
- driga
- drigad
package_name: driga
file_name_template: "driga_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
vendor: LabStack
Expand Down Expand Up @@ -191,9 +229,10 @@ homebrew_casks:
app "Driga.app"
caveats: |
Driga.app is in /Applications, and driga links to the CLI inside it.
Open Driga from Finder, Spotlight or with driga app. The app collects in
the background and starts at login. After upgrading from an earlier
release, open Driga once: it replaces the old background service.
Open Driga from Finder, Spotlight or with driga app. Its first launch
installs the Driga service (drigad), which collects at login whether or
not the app is open. After upgrading from an earlier release, open Driga
once: it replaces the old collector.
url:
template: "https://github.com/labstack/driga/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
commit_msg_template: "chore: update driga to {{ .Tag }}"
Expand Down
37 changes: 36 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,45 @@ just build # builds ./bin/driga, which is not on PATH
just install # deliberately copies it to ~/.local/bin
```

### The app's UI

The app's page and the panels MCP App are built from `ui/` with [Bun](https://bun.sh):
`just ui` installs the pinned packages, type-checks and writes both bundles into
`internal/web/app` and `internal/mcp/apps`. The bundles are committed, so a Go
build needs no JavaScript toolchain, but `just check` needs Bun: it runs the UI
tests, rebuilds the bundles and fails when the committed ones are behind `ui/`.

`just design` opens the UI's Storybook at http://127.0.0.1:6506, for review
only: it is never published. The review convention covers every component,
every kind of panel, the Home page
and its flows, each with one Docs page of its states, over a fictional fleet
and a fake service, so no story reaches a real Driga. Stories render the
shipping components themselves. The panel data in `ui/src/fixtures` is Driga's
own engine run over that fleet; `DRIGA_WRITE_STORIES=1 go test ./internal/panel`
regenerates it, and `just check` fails when it is stale. `just design-check`
runs every story, its play, accessibility and the layout check in Chromium,
in both schemes at both review widths (1440 and 1024); `just check` runs it
too, and a unit test fails when a component or a kind of panel has no story. Agents writing or changing UI add the story
first. UI files keep the code's PascalCase names throughout the UI.

`just dev` develops the UI in a browser at http://127.0.0.1:5173/app/: Vite
hot-reloads it, and `driga dev serve` answers the API on 127.0.0.1:47801 from
the data directory your environment names, restarting on Go changes when
`watchexec` is installed. It is the app without its window: no native dialogs,
menus, tray or notifications, and the browser's own confirm instead.

The UI follows LabStack's Canon: Mantine components themed through
`ui/src/theme`, Phosphor icons, TanStack Table for tables and one ECharts
wrapper for charts. Its colors come from the console palette: after changing a
color in `internal/view`, run `DRIGA_WRITE_THEME=1 go test ./internal/view` to
regenerate `ui/src/theme/palette.json`. Style sheets name theme variables, never
colors. `@labstack/ui` is a private package this public repository cannot
install, so Driga composes its status badge and stat tile from Mantine instead.

## Verify

```sh
just check # gofmt, go mod tidy, vet (native and Windows), generated files, tests
just check # gofmt, go mod tidy, vet (native and Windows), generated files, UI, tests
just race # the suite under the race detector
just ci # what the Linux CI job runs: check, race, govulncheck, actionlint, release snapshot
```
Expand Down
58 changes: 56 additions & 2 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ build:
CGO_ENABLED=0 go build -trimpath \
-ldflags "-s -w -X main.version=${version} -X main.commit=$(git rev-parse HEAD) -X main.date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-o bin/driga ./cmd/driga
echo "built bin/driga (${version})"
# drigad, the Driga service, is the same program under its own name.
ln -f bin/driga bin/drigad
echo "built bin/driga and bin/drigad (${version})"

# Put the built binary on PATH, deliberately; it may shadow an installed release.
install: build
Expand All @@ -25,6 +27,7 @@ install: build
dir="${DRIGA_INSTALL_DIR:-${HOME}/.local/bin}"
mkdir -p "$dir"
install -m 0755 bin/driga "$dir/driga"
ln -f "$dir/driga" "$dir/drigad"
echo "installed $dir/driga ($("$dir/driga" version | head -1)); first on PATH: $(command -v driga)"

# Remove the checkout build (never the copy on PATH).
Expand All @@ -34,7 +37,7 @@ clean:
# ---------- Verification ----------

# Local pre-commit gate.
check: _fmt-check tidy-check vet generate-check docs-check test
check: _fmt-check tidy-check vet generate-check docs-check ui-check test
@echo "All checks passed"

# Adds race, vulnerability, workflow and release-snapshot checks.
Expand Down Expand Up @@ -84,6 +87,57 @@ docs:
docs-check:
go run ./cmd/driga-docgen --check

# ---------- App UI ----------

# Install the UI's dependencies from the lockfile.
ui-deps:
cd ui && bun install --frozen-lockfile

# Develop the app's UI in a browser at http://127.0.0.1:5173/app/: Vite
# hot-reloads the UI and sends the API to driga dev serve, which restarts when
# Go files change (with watchexec on PATH). It reads the data directory the
# environment names, as every driga command does.
dev: ui-deps
#!/usr/bin/env bash
set -euo pipefail
trap 'kill 0' EXIT
if command -v watchexec >/dev/null; then
watchexec --restart --exts go --watch cmd --watch internal -- go run ./cmd/driga dev serve &
else
go run ./cmd/driga dev serve &
fi
cd ui && bun --bun vite

# Typecheck and build the app's dashboard host and the panels MCP App into
# internal/web/app and internal/mcp/apps. Both are committed, so a Go build
# needs no JavaScript toolchain; rebuild after changing ui/.
ui: ui-deps
cd ui && bun run build

# Review the UI in Storybook, locally only (Canon design.md): every
# component, panel, page and flow over a fictional fleet. Never published.
design port="6506": ui-deps
cd ui && bun run design -p {{port}}

# The catalog check: every story, its play, accessibility and the layout
# check, in Chromium, in both schemes.
design-check: ui-deps
cd ui && bun run design-check

# Test and rebuild the UI, run the catalog, and fail when the build in git
# (staged counts) is behind ui/.
ui-check: ui design-check
#!/usr/bin/env bash
set -euo pipefail
(cd ui && bun run test)
built=(internal/web/app internal/mcp/apps)
stale="$(git diff --name-only -- "${built[@]}"; git ls-files --others --exclude-standard -- "${built[@]}")"
if [[ -n "$stale" ]]; then
echo "$stale" >&2
echo "The UI build in git is behind ui/; add the rebuilt files above." >&2
exit 1
fi

# ---------- Documentation site ----------

# Install the site's dependencies from the lockfile.
Expand Down
33 changes: 17 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
**See what your coding agents are doing, and what needs you.**

Driga is a desktop app and a CLI for AI coding agent sessions, like Docker
Desktop with `docker`. The app collects in the background, notifies you when an
agent waits, and shows the dashboard; the `driga` CLI comes with it and opens
the terminal UI. It runs on macOS and Linux. Windows: experimental, including
Desktop with `docker`. The Driga service, `drigad`, runs in the background from
login: it collects, notifies you when an agent waits, hosts Chat and runs
actions, whether or not a window is open. The app and the `driga` terminal UI
are its views; the app installs the service on first launch. It runs on macOS and Linux. Windows: experimental, including
orphan kill and worktree cleanup.
It brings agent activity, project status, an attention inbox, orphaned helpers, and machine health into one place.

Expand Down Expand Up @@ -47,8 +48,8 @@ sends notifications under its own name. Hooks keep using the stable Homebrew
`driga` link. After `brew upgrade`, a running app restarts itself on
the new version.

If you installed the collector service with an earlier release, the app
removes it on its first launch, says so once, and runs the collector itself.
If you installed the Driga service with an earlier release, the app
removes it on its first launch, says so once, and runs the Driga service itself.

On Windows (experimental), use Scoop:

Expand Down Expand Up @@ -76,7 +77,7 @@ CGO_ENABLED=0 go build ./cmd/driga

Keep Git on PATH and the installed binary at a stable absolute path before
setting up hooks or a service. On a machine without a desktop, install the CLI
alone and run the collector as a service with `driga service install`. CalVer
alone and run the Driga service as a service with `driga service install`. CalVer
tags use the year as their major number; Go module major-version rules prevent
`go install ...@<tag>` with this module path. Use a package, archive, or source checkout.

Expand All @@ -85,12 +86,12 @@ tags use the year as their major number; Go module major-version rules prevent
Windows 10 1809+ and Windows 11 have native snapshots, foreground collection,
read commands, the TUI, MCP, OTLP intake and fleet interfaces, plus:

- The `Driga.exe` app, which runs the collector, sits in the notification
- The `Driga.exe` app, which installs the Driga service, sits in the notification
area and starts at logon; Scoop adds a Start menu shortcut and puts the CLI,
`bin\driga.exe`, on PATH.
- For a machine without the app, a per-user Task Scheduler collector at logon:
`driga service install`, `uninstall`, `start`, `stop`, `status`, `restart`,
and `logs [-f]`; no elevation.
- The Driga service, `bin\drigad.exe`, as a per-user Task Scheduler task at
logon: `driga service install`, `uninstall`, `start`, `stop`, `status`,
`restart`, and `logs [-f]`; no elevation.
- Previewed Claude, Codex and Copilot hook installation with absolute executable paths.
- Native plain toast alerts (no PowerShell); doctor reports availability.
- Terminal jumps/open in Windows Terminal, falling back to a new Command Prompt.
Expand All @@ -99,7 +100,7 @@ read commands, the TUI, MCP, OTLP intake and fleet interfaces, plus:
- Confirmed cleanup of verified linked worktrees into the Recycle Bin, with
the same revalidation and audit logging as Unix cleanup.

Logs live at `%LOCALAPPDATA%\driga\logs\collector.log`. Keep `driga.exe` at a
Logs live at `%LOCALAPPDATA%\driga\logs\service.log`. Keep `driga.exe` at a
stable path before installing. Phase 3 is feature-complete pending real-hardware
verification; Windows remains **experimental**. TCP/UDP probes cover IPv4 and IPv6;
open-file evidence uses bounded Restart Manager queries. Claude scratch cleanup
Expand All @@ -114,15 +115,15 @@ See [Windows setup details](docs/usage.md#windows-experimental).
## Quick start

```sh
driga app # open the desktop app: collector, notifications, dashboard
driga app # open the desktop app; its first launch installs the Driga service
driga # opens the terminal viewer (driga top)
driga doctor # check setup
```

On a headless machine, `driga service install` runs the same collector as a
per-user service instead of the app.
On a headless machine, `driga service install` installs the Driga service
without the app.

Without a collector, Driga takes a disposable snapshot and shows
Without the Driga service, Driga takes a disposable snapshot and shows
`snapshot · no history`. That collection writes no persistent database. One
agent in one repository works without configuring roots or a service.

Expand All @@ -131,7 +132,7 @@ are optional steps. On macOS and Windows it points to the app for collection;
on Linux it offers to install the service. Session working directories also
contribute to repository discovery; there are no default scanning roots.

The collector's first import marks older events as already seen. Reading an
The Driga service's first import marks older events as already seen. Reading an
inbox item never acknowledges it; use the Flow Activity controls in the TUI or `driga inbox ack <item-id>`.

### Scripting and agents
Expand Down
Loading
Loading