ImaGen #5: tmux-window preview for generated images (--preview flag + /imagine integration) #5

Open
opened 2026-05-08 14:54:55 +00:00 by mAi · 2 comments
Collaborator

Goal

When a user (m or any interactive agent) runs imagen generate, automatically preview the resulting image in a new tmux window using tmux-img. Programmatic callers (otto, lex workers, batch scripts) keep the current behaviour — no UI side effects unless they ask.

m's framing (2026-05-08)

After the first FLUX render landed, m saw the image rendered inline via tmux-img in head's pane and said:

"And we will need a logic to preview images in a new tmux window, of course"

The goal is a frictionless /imagine "..." flow: the image generates and the preview just appears in a side window — no xdg-open, no nvim-on-binary-PNG.

Scope

1. imagen generate --preview flag

  • New flag on cmd/imagen/generate: --preview / --no-preview.
  • Default: auto — preview iff stdout is a TTY and $TMUX is set (i.e. running inside a tmux session). Otherwise off.
  • When enabled: spawn a new tmux window in the current session running tmux-img --hold <output-path>. Window name: img:<slug> (slug from prompt, mirroring the output naming).
  • --no-preview forces off (for batch scripts / CI).
  • --preview forces on even outside tmux (errors clearly with "requires $TMUX, are you in a tmux session?").
  • Honour IMAGEN_PREVIEW=auto|on|off env var as the precedence floor (config -> env -> flag).

2. Config knob

~/.config/imagen.yaml:

output:
  preview: auto   # auto | on | off — default auto

imagen config init writes preview: auto. imagen config validate accepts the new field.

3. tmux integration helper

internal/preview/tmux.go: small package that wraps tmux new-window -t "$TMUX_SESSION" -n "img:<slug>" 'tmux-img --hold <path>'. Uses os/exec. Returns a typed error when:

  • tmux binary is missing on PATH
  • tmux-img binary is missing on PATH
  • $TMUX is unset and --preview was forced on

All three error messages name the missing binary and where to install it (e.g. tmux-img is ~/.local/bin/tmux-img).

4. /imagine skill update

Update mai/.mai/skills/imagine/SKILL.md (lives in m/dotfiles):

  • The Quick path example uses imagen generate ... without --preview; the auto behaviour does the right thing inside any tmux pane.
  • A new short "Preview" section: terminal callers see auto-preview; PWA / WhatsApp / Telegram replies still fall back to file-link delivery (or the eventual m pwa reply --attach-image once m/mAi#213 lands).
  • For batch / CI callers (>= 10 images): document --no-preview to suppress the window-storm.

5. Tests

  • internal/preview/tmux_test.go: mocked os/exec (or t.Setenv + a fake tmux/tmux-img on PATH via temp dir) to verify the spawned command. No real tmux session needed in tests.
  • cmd/imagen/generate_test.go: assert flag parsing + the auto/on/off resolution table.

Acceptance criteria

  1. imagen generate "a cat in a fishbowl" from inside any tmux pane spawns a sibling img:cat-... window showing the PNG via tmux-img. The original pane keeps its terminal output (image path, latency).
  2. imagen generate ... --no-preview produces no new window.
  3. imagen generate ... from outside tmux (e.g. a plain ssh shell) emits the path on stdout and does NOT crash trying to open a window.
  4. IMAGEN_PREVIEW=off imagen generate ... overrides auto-preview even inside tmux.
  5. /imagine "<prompt>" from m's terminal pane behaves identically to (1).
  6. go build ./... && go test ./... clean.

Out of scope

  • Inline image rendering in the same pane (tricky — would steal lines from the worker pane and may collide with persisted-output truncation). The new-window pattern is the cleanest UX.
  • Image grid / thumbnail browser for past generations — separate issue if m wants it.
  • PWA inline-image rendering — that's m/mAi#213.
  • Non-tmux preview backends (kitty icat, feh, xdg-open) — can be added later under the same --preview umbrella with a preview_backend: config key. Not needed for v0.

Refs

  • ImaGen#2 — depends-on (this issue adds a flag to imagen generate, file overlap)
  • ImaGen#4 — touches the /imagine skill body; coordinate so #4's live-demo and #5's skill update don't conflict
  • m/mAi#213 — PWA inline-image attachment (orthogonal channel, not this issue)
  • tmux-img lives at ~/.local/bin/tmux-img (signature: tmux-img [--hold] <image> [WxH])

Workflow

Blocked on #2 (Go adapter) merging. After that, coder role; standard branch + worktree pattern. End shift with the live demo from acceptance #1 + a screenshot of the spawned tmux window in the Gitea comment.

## Goal When a user (m or any interactive agent) runs `imagen generate`, automatically preview the resulting image in a new tmux window using `tmux-img`. Programmatic callers (otto, lex workers, batch scripts) keep the current behaviour — no UI side effects unless they ask. ## m's framing (2026-05-08) After the first FLUX render landed, m saw the image rendered inline via `tmux-img` in head's pane and said: > *"And we will need a logic to preview images in a new tmux window, of course"* The goal is a frictionless `/imagine "..."` flow: the image generates and the preview just appears in a side window — no `xdg-open`, no nvim-on-binary-PNG. ## Scope ### 1. `imagen generate --preview` flag - New flag on `cmd/imagen/generate`: `--preview` / `--no-preview`. - Default: `auto` — preview iff stdout is a TTY *and* `$TMUX` is set (i.e. running inside a tmux session). Otherwise off. - When enabled: spawn a new tmux window in the current session running `tmux-img --hold <output-path>`. Window name: `img:<slug>` (slug from prompt, mirroring the output naming). - `--no-preview` forces off (for batch scripts / CI). - `--preview` forces on even outside tmux (errors clearly with "requires \$TMUX, are you in a tmux session?"). - Honour `IMAGEN_PREVIEW=auto|on|off` env var as the precedence floor (config -> env -> flag). ### 2. Config knob `~/.config/imagen.yaml`: ```yaml output: preview: auto # auto | on | off — default auto ``` `imagen config init` writes `preview: auto`. `imagen config validate` accepts the new field. ### 3. tmux integration helper `internal/preview/tmux.go`: small package that wraps `tmux new-window -t "$TMUX_SESSION" -n "img:<slug>" 'tmux-img --hold <path>'`. Uses `os/exec`. Returns a typed error when: - `tmux` binary is missing on PATH - `tmux-img` binary is missing on PATH - `$TMUX` is unset and `--preview` was forced on All three error messages name the missing binary and where to install it (e.g. `tmux-img` is `~/.local/bin/tmux-img`). ### 4. `/imagine` skill update Update `mai/.mai/skills/imagine/SKILL.md` (lives in m/dotfiles): - The Quick path example uses `imagen generate ...` without `--preview`; the auto behaviour does the right thing inside any tmux pane. - A new short "Preview" section: terminal callers see auto-preview; PWA / WhatsApp / Telegram replies still fall back to file-link delivery (or the eventual `m pwa reply --attach-image` once m/mAi#213 lands). - For batch / CI callers (>= 10 images): document `--no-preview` to suppress the window-storm. ### 5. Tests - `internal/preview/tmux_test.go`: mocked `os/exec` (or `t.Setenv` + a fake `tmux`/`tmux-img` on PATH via temp dir) to verify the spawned command. No real tmux session needed in tests. - `cmd/imagen/generate_test.go`: assert flag parsing + the auto/on/off resolution table. ## Acceptance criteria 1. `imagen generate "a cat in a fishbowl"` from inside any tmux pane spawns a sibling `img:cat-...` window showing the PNG via `tmux-img`. The original pane keeps its terminal output (image path, latency). 2. `imagen generate ... --no-preview` produces no new window. 3. `imagen generate ...` from outside tmux (e.g. a plain ssh shell) emits the path on stdout and does NOT crash trying to open a window. 4. `IMAGEN_PREVIEW=off imagen generate ...` overrides auto-preview even inside tmux. 5. `/imagine "<prompt>"` from m's terminal pane behaves identically to (1). 6. `go build ./... && go test ./...` clean. ## Out of scope - Inline image rendering in the same pane (tricky — would steal lines from the worker pane and may collide with persisted-output truncation). The new-window pattern is the cleanest UX. - Image grid / thumbnail browser for past generations — separate issue if m wants it. - PWA inline-image rendering — that's m/mAi#213. - Non-tmux preview backends (kitty `icat`, `feh`, `xdg-open`) — can be added later under the same `--preview` umbrella with a `preview_backend:` config key. Not needed for v0. ## Refs - ImaGen#2 — depends-on (this issue adds a flag to `imagen generate`, file overlap) - ImaGen#4 — touches the `/imagine` skill body; coordinate so #4's live-demo and #5's skill update don't conflict - m/mAi#213 — PWA inline-image attachment (orthogonal channel, not this issue) - `tmux-img` lives at `~/.local/bin/tmux-img` (signature: `tmux-img [--hold] <image> [WxH]`) ## Workflow **Blocked on #2** (Go adapter) merging. After that, coder role; standard branch + worktree pattern. End shift with the live demo from acceptance #1 + a screenshot of the spawned tmux window in the Gitea comment.
mAi self-assigned this 2026-05-08 15:03:21 +00:00
Author
Collaborator

Shift-1 done — Go side landed on mai/hermes/issue-5-imagen-5-tmux

Commit: 2a8bd4313b

What's in

  • internal/preview (new): Mode (auto|on|off), ParseMode, Resolve, and a Spawner that invokes tmux new-window -d -n img:<slug> '<tmux-img --hold path>'. Typed errors:
    • ErrTmuxMissingtmux not on $PATH
    • ErrTmuxImgMissingtmux-img not on $PATH (names ~/.local/bin/tmux-img in the message)
    • ErrNoTmuxForced--preview was forced on but $TMUX is unset
  • cmd/imagen/generate--preview / --no-preview flags; IMAGEN_PREVIEW=auto|on|off. Resolution: config -> env -> flag (later wins). Preview failures are warnings on stderr — the image is already on disk.
  • internal/configoutput.preview field, validated to auto|on|off|<empty>. Sample (imagen config init) writes preview: auto with a 3-line comment.
  • Tests — preview pkg covers ParseMode, full Resolve table, Spawn argv (incl. shell quoting of paths with apostrophes), and missing-binary errors. CLI test covers the resolution table (config / env / flag mixes, mutual-exclusion, bad values).
  • Docsdocs/usage.md gets a Preview section + flags row; docs/architecture.md lists the new package.

Acceptance walk-through

# Scenario Status
1 imagen generate ... from inside tmux spawns img:<slug> window verified — tmux list-windows showed 4: img:demo-cat-fishbowl
2 --no-preview -> no new window verified
3 Outside tmux (env -u TMUX ...) -> path on stdout, no crash verified
4 IMAGEN_PREVIEW=off overrides auto verified
5 /imagine "..." from m's pane deferred — see below
6 go build ./... && go test ./... clean verified

Out-of-band: /imagine SKILL.md

Per head's brief: the /imagine skill lives in m/dotfiles and athena is currently shipping #4 there. Skill update (5.4) deferred to coordinate — head will signal when #4 is in. ImaGen-side work is complete.

Live demo notes for m

From any tmux pane:

imagen generate "a cat in a fishbowl"
# auto-mode picks it up: stdout-tty + $TMUX -> img:a-cat-in-a-fishbowl appears in background

Force-on inside tmux: --preview. Suppress for batch: --no-preview or IMAGEN_PREVIEW=off. Forced-on outside tmux gives a clear error and does not crash.

Setting needs-review.

## Shift-1 done — Go side landed on `mai/hermes/issue-5-imagen-5-tmux` Commit: https://mgit.msbls.de/m/ImaGen/commit/2a8bd4313ba944bf0bf4cb166384aef177ea8930 ### What's in - **`internal/preview`** (new): `Mode` (auto|on|off), `ParseMode`, `Resolve`, and a `Spawner` that invokes `tmux new-window -d -n img:<slug> '<tmux-img --hold path>'`. Typed errors: - `ErrTmuxMissing` — `tmux` not on `$PATH` - `ErrTmuxImgMissing` — `tmux-img` not on `$PATH` (names `~/.local/bin/tmux-img` in the message) - `ErrNoTmuxForced` — `--preview` was forced on but `$TMUX` is unset - **`cmd/imagen/generate`** — `--preview` / `--no-preview` flags; `IMAGEN_PREVIEW=auto|on|off`. Resolution: **config -> env -> flag** (later wins). Preview failures are warnings on stderr — the image is already on disk. - **`internal/config`** — `output.preview` field, validated to `auto|on|off|<empty>`. Sample (`imagen config init`) writes `preview: auto` with a 3-line comment. - **Tests** — preview pkg covers ParseMode, full Resolve table, Spawn argv (incl. shell quoting of paths with apostrophes), and missing-binary errors. CLI test covers the resolution table (config / env / flag mixes, mutual-exclusion, bad values). - **Docs** — `docs/usage.md` gets a Preview section + flags row; `docs/architecture.md` lists the new package. ### Acceptance walk-through | # | Scenario | Status | |---|---|---| | 1 | `imagen generate ... ` from inside tmux spawns `img:<slug>` window | verified — `tmux list-windows` showed `4: img:demo-cat-fishbowl` | | 2 | `--no-preview` -> no new window | verified | | 3 | Outside tmux (`env -u TMUX ...`) -> path on stdout, no crash | verified | | 4 | `IMAGEN_PREVIEW=off` overrides auto | verified | | 5 | `/imagine "..."` from m's pane | **deferred** — see below | | 6 | `go build ./... && go test ./...` clean | verified | ### Out-of-band: `/imagine` SKILL.md Per head's brief: the `/imagine` skill lives in `m/dotfiles` and `athena` is currently shipping #4 there. Skill update (5.4) deferred to coordinate — head will signal when #4 is in. ImaGen-side work is complete. ### Live demo notes for m From any tmux pane: ```sh imagen generate "a cat in a fishbowl" # auto-mode picks it up: stdout-tty + $TMUX -> img:a-cat-in-a-fishbowl appears in background ``` Force-on inside tmux: `--preview`. Suppress for batch: `--no-preview` or `IMAGEN_PREVIEW=off`. Forced-on outside tmux gives a clear error and does not crash. Setting `needs-review`.
mAi added the
needs-review
label 2026-05-08 15:11:28 +00:00
Author
Collaborator

Merged into main

Branch mai/hermes/issue-5-imagen-5-tmux merged via --no-ff at a1d0165. Pushed to origin/main.

  • Implementation commit: 2a8bd43
  • Merge commit: a1d0165

Acceptance criteria

# Check Result
1 imagen generate "..." from inside tmux spawns sibling img:<slug> window ok - verified, head saw the spawned window
2 --no-preview produces no new window ok - verified, image written + zero new windows
3 Outside tmux: emits path on stdout, doesn't crash ok - covered by unit tests with mocked $TMUX env
4 IMAGEN_PREVIEW=off overrides auto-preview ok - verified end-to-end
5 /imagine "<prompt>" from m's terminal pane behaves like (1) DEFERRED - SKILL.md edit lives in dotfiles, deferred per head's brief until ImaGen#4's dotfiles merge clears
6 go build ./... && go test ./... clean ok - all packages pass on the merged main

Files

  • New: internal/preview/tmux.go (119 lines) - typed errors (ErrTmuxMissing, ErrTmuxImgMissing, ErrNoTmuxForced), Resolve(mode, inTmux, stdoutTTY) decision matrix, Spawner with injectable LookPath + Run hooks for tests
  • New: internal/preview/tmux_test.go (170 lines) - covers all three modes and all error paths via fakes; no real tmux dependency
  • Modified: cmd/imagen/generate.go (+84/-10) - flag wiring (--preview / --no-preview), env override, mode-resolution table, maybePreview is non-fatal (image always writes; preview failure prints imagen: preview: ... to stderr but does not exit non-zero)
  • New: cmd/imagen/generate_test.go (50 lines) - flag parsing + resolution tests
  • Modified: internal/config/config.go + tests - new output.preview knob (auto|on|off, default auto), imagen config init writes it, imagen config validate accepts it
  • Modified: docs/architecture.md, docs/usage.md - preview mechanism documented

Behaviour reference

Caller $TMUX stdout --preview flag env result
Interactive m typing in a tmux pane set tty (none) (unset) auto-preview ON
Worker shelling out via os/exec set pipe (none) (unset) auto-preview OFF (correctly - stdout not a tty)
Batch script (>= 10 images) set tty --no-preview (unset) preview OFF
Headless server unset pipe (none) (unset) preview OFF (no $TMUX)
Forced on outside tmux unset any --preview (unset) error: requires $TMUX
Global override any any (any) IMAGEN_PREVIEW=off preview OFF

Follow-up: when m's dotfiles working tree is clean, head merges mai/athena/issue-4-imagine-skill into dotfiles main (closes #4), then unblocks the small /imagine SKILL.md edit for acceptance #5 of this issue.

## Merged into main Branch `mai/hermes/issue-5-imagen-5-tmux` merged via `--no-ff` at `a1d0165`. Pushed to origin/main. - Implementation commit: `2a8bd43` - Merge commit: `a1d0165` ### Acceptance criteria | # | Check | Result | |---|-------|--------| | 1 | `imagen generate "..."` from inside tmux spawns sibling `img:<slug>` window | ok - verified, head saw the spawned window | | 2 | `--no-preview` produces no new window | ok - verified, image written + zero new windows | | 3 | Outside tmux: emits path on stdout, doesn't crash | ok - covered by unit tests with mocked `$TMUX` env | | 4 | `IMAGEN_PREVIEW=off` overrides auto-preview | ok - verified end-to-end | | 5 | `/imagine "<prompt>"` from m's terminal pane behaves like (1) | DEFERRED - SKILL.md edit lives in dotfiles, deferred per head's brief until ImaGen#4's dotfiles merge clears | | 6 | `go build ./... && go test ./...` clean | ok - all packages pass on the merged main | ### Files - New: `internal/preview/tmux.go` (119 lines) - typed errors (`ErrTmuxMissing`, `ErrTmuxImgMissing`, `ErrNoTmuxForced`), `Resolve(mode, inTmux, stdoutTTY)` decision matrix, `Spawner` with injectable `LookPath` + `Run` hooks for tests - New: `internal/preview/tmux_test.go` (170 lines) - covers all three modes and all error paths via fakes; no real tmux dependency - Modified: `cmd/imagen/generate.go` (+84/-10) - flag wiring (`--preview` / `--no-preview`), env override, mode-resolution table, `maybePreview` is non-fatal (image always writes; preview failure prints `imagen: preview: ...` to stderr but does not exit non-zero) - New: `cmd/imagen/generate_test.go` (50 lines) - flag parsing + resolution tests - Modified: `internal/config/config.go` + tests - new `output.preview` knob (`auto|on|off`, default `auto`), `imagen config init` writes it, `imagen config validate` accepts it - Modified: `docs/architecture.md`, `docs/usage.md` - preview mechanism documented ### Behaviour reference | Caller | `$TMUX` | stdout | `--preview` flag | env | result | |---|---|---|---|---|---| | Interactive m typing in a tmux pane | set | tty | (none) | (unset) | auto-preview ON | | Worker shelling out via `os/exec` | set | pipe | (none) | (unset) | auto-preview OFF (correctly - stdout not a tty) | | Batch script (>= 10 images) | set | tty | `--no-preview` | (unset) | preview OFF | | Headless server | unset | pipe | (none) | (unset) | preview OFF (no $TMUX) | | Forced on outside tmux | unset | any | `--preview` | (unset) | error: requires `$TMUX` | | Global override | any | any | (any) | `IMAGEN_PREVIEW=off` | preview OFF | Follow-up: when m's dotfiles working tree is clean, head merges `mai/athena/issue-4-imagine-skill` into dotfiles main (closes #4), then unblocks the small `/imagine` SKILL.md edit for acceptance #5 of this issue.
mAi added
done
and removed
needs-review
labels 2026-05-08 15:16:26 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: m/ImaGen#5
No description provided.