Skip to content

feat: virtual Operations board (non-git, cross-project Kanban)#725

Merged
h0x91b merged 19 commits into
mainfrom
feat/dev3-virtual-operations-board
Jun 24, 2026
Merged

feat: virtual Operations board (non-git, cross-project Kanban)#725
h0x91b merged 19 commits into
mainfrom
feat/dev3-virtual-operations-board

Conversation

@h0x91b

@h0x91b h0x91b commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Hey, Claude here — the AI assistant that worked on this branch.

Summary

Adds a virtual Operations board: a non-git, cross-project Kanban for ad-hoc, code-driven tasks (back up prod, stop a server, mail/Slack triage, throwaway experiments) that still persist in history.

  • Modeled as Project.kind: "virtual", stored in a separate ~/.dev3.0/virtual-projects.json so older app versions stay fully compatible — no on-disk format break.
  • Each operation runs an AI agent + a split-right shell in a managed temp folder (or a folder you pick) — no git worktree, branch, diff, PR, or review columns.
  • The single home terminal is replaced by a built-in Operations board; ⇧⌘` opens a "Quick Shell" operation in your home dir.
  • The built-in board is pinned first everywhere, reachable with ⌘0, and marked as a system object ("[ Operations ]" + SYSTEM badge). Inside an operation the inspector hides git, Dev Server, and Scripts.

Hardening (parity with git tasks)

Several review sweeps closed git-only assumptions that had leaked into virtual boards:

  • Cross-project scans, dashboard active-tasks, CLI resolution, and dead-session restore all handle virtual boards.
  • Command palette / ⌘K switcher / branch-status & open-PR polls / git RPCs all skip or reject virtual boards.
  • updateProjectWith routes virtual ids to virtual-projects.json — creating labels/columns on the board no longer throws "Project not found".
  • Project Terminal + Open-in-Finder are hidden (header, tile, ⌘`, palette, native menu) and backend-guarded for virtual boards — no more "Project path does not exist" crash.
  • The pinned built-in board can no longer be deleted (it previously dead-ended ⌘0 until restart and orphaned its tasks).
  • The CLI resolves task context from the injected DEV3_TASK_ID for operations whose working dir is outside ~/.dev3.0/ops/ (fixed-folder ops, Quick shell in $HOME), so agent status hooks no longer silently no-op there.
  • The Quick shell hotkey reuses an inactive shell instead of spawning duplicates and is race-safe against rapid double-presses; the Quick Shell button and scratch-session card badge render their icon glyphs.

Decisions recorded in decisions/079-virtual-operations-board-identity.md and decisions/080-cli-context-env-fallback.md. Lint and the full test suite (mainview / bun / CLI) are green.

h0x91b added 18 commits June 24, 2026 14:03
- Project.kind ('git'|'virtual'), Project.builtin, Task.opsWorkDir
- virtual-projects.json load/save + dashboard merge in getProjects
- readable-slug allocation (unique, never-reused while data/ survives)
- addVirtualProject RPC + ensureBuiltinOperationsBoard provisioning
- getProject/updateProject/removeProject route by file
- CLI context resolves virtual ops work dirs (no slug-algorithm change)
- guard: reject git projects under ~/.dev3.0
- tests: data-virtual-projects, context-virtual, rpc-handlers
- decision 079
- activateTask branches to activateVirtualTask: mkdir managed work dir (or
  use task.opsWorkDir fixed folder), launch agent + split-right shell, no git
- moveTask completed/cancelled: skip removeWorktree for virtual, keep
  worktreePath as history
- deleteTask: rm work dir only if under ~/.dev3.0/ops/ (never fixed folders)
- launchTaskPty adds a split-right interactive shell pane for virtual ops
  (fresh sessions only; non-fatal)
- git.virtualWorkDir helper
- tests: virtual lifecycle (no worktree, fixed folder, keep-on-complete,
  delete-managed-only)
- KanbanBoard hides all review columns for virtual (todo → in-progress →
  user-questions → done)
- ActivityOverview: Operations badge + localized built-in board name, hides
  the synthetic on-disk path
- AddProjectModal: Git repository | Operations toggle → addVirtualProject RPC
- i18n ops.* keys (en/ru/es)
- tests: KanbanBoard virtual columns, ActivityOverview badge, modal ops flow
- TaskInfoPanel hides TaskGitActions (both rows), diff badge, diff-tests
  toggle, and bug-hunters for virtual tasks; Runtime bar (open-in/scripts/
  dev-server/ports) + spawn-agent remain
- TaskCard shows a shell glyph on scratch tasks (live session marker)
- i18n task.scratchSession (en/ru/es)
- tests: inspector git-hiding for virtual vs git
- createTask RPC + data.addTask carry opsWorkDir; CreateTaskModal shows a
  managed/choose-folder selector for virtual projects (branch selector hidden)
- non-blocking inline warning when the chosen folder is used by another active
  operation
- i18n ops.create.workDir* (en/ru/es)
- tests: virtual create flow (selector visible, managed create)
…Shell

- new openQuickShell RPC: opens/focuses a prompt-less 'Quick shell' op in the
  built-in Operations board, running in $HOME (replaces the single home terminal)
- ⇧⌘` hotkey, command palette, native menu, and a header button now trigger it
- removed HomeTerminal.tsx/HomeTerminalIcon.tsx, the home-terminal route,
  getHomePtyUrl/destroyHomeTerminal RPC, homePtyDied push, PtySessionType 'home'
  + HOME_TERMINAL_* constants, and all home-session event/listing branches
- listTmuxSessions, bell/idle auto-status now also scan virtual projects so
  Operations sessions resolve and auto-transition correctly
- i18n quickShell.* / command.openQuickShell / keymap.shortcut.openQuickShell
  (en/ru/es); README + landing-page shortcut copy updated
- tests updated (openQuickShell, menu, state, GlobalHeader)
- two feature tips (Operations board, operations keep history) + i18n
- concept.md status-tracker flipped to done (loops still deferred)
- changelog: planning entry → shipped feature entry
- manifest: Project.kind marked Observed in ux-architecture.yaml + Bible §3,
  home-terminal destination removed; UX decision → Implemented;
  UX_MANIFEST_CHANGELOG entry
The Run button and Create-and-Run funnel through
spawnVariants → prepareTaskInBackground, which always created a git
worktree. On a virtual (Operations) board that folder is not a git repo,
so launching failed with ENOENT 'git' and the task bounced back to To Do.

- prepareTaskInBackground now early-branches for project.kind 'virtual':
  mkdir the managed/chosen work dir + launchTaskPty, no git pipeline,
  reusing the same preparation-stage and cancellation machinery.
- spawnVariants carries the source task's opsWorkDir onto each variant.
- LaunchVariantsModal hides '+ Add Variant' for virtual boards (an
  operation is one agent + one folder; a shared fixed folder with N
  agents would clobber).
- GlobalHeader hides the Git Pull button for virtual boards.
…inspector cleanup

The single hardcoded Operations board (builtin + virtual) is now a visibly
special, pinned system object — distinct from user-created virtual boards.

- Pin-first: new pure orderProjectsForDisplay()/isBuiltinOpsProject() helpers
  render the built-in board first on the dashboard and the project switcher;
  its tile is non-draggable and move-locked, and the project below it cannot
  move up past the pin. Other virtual boards sort normally.
- ⌘0 jumps to the built-in board (the natural 'slot 0' of the ⌘1-9 project
  family, which now skips it). Zoom-reset relocated ⌘0 → ⇧⌘0 (renderer-owned;
  native Reset-Zoom menu item drops its accelerator and hints the chord, since
  Electrobun menu accelerators are single-char only).
- Identity: the built-in board renders bracketed ('[ Operations ]') with a
  leading accent bolt glyph, a neutral SYSTEM badge, and a ⌘0 hint chip; the
  switcher row and breadcrumb mirror the bracketed name. User-created virtual
  boards keep their literal name + plain Operations badge.
- Inspector: for virtual tasks the empty Git quickbar slot now shows a muted
  'Git is not available in operations tasks' note, and the Dev Server + Scripts
  controls are removed (Open in… and exposed ports stay).

i18n (en/ru/es): ops.boardName bracketed, new ops.badgeSystem + ops.gitUnavailable,
keymap.shortcut.jumpOperations; keymap registry + native menu updated. Tests
cover the helpers, pin order, ⌘0/⇧⌘0, identity rendering, and inspector cleanup.
Docs: UX decision 2026-06-24 + manifest changelog + feature changelog.
…ion restore, dashboard, CLI)

Several cross-project scans iterated only git projects (data.loadProjects),
silently skipping virtual (Operations) boards — so operations were second-class
in those paths. Most visibly: an active operation whose tmux session died showed
a dead '[session ended]' terminal with no recovery, because findTaskAcrossProjects
could not find the task and getPtyUrl never relaunched it.

Fixed every offending scan to also load virtual projects:
- findTaskAcrossProjects (tmux-pty): getPtyUrl now restores/relaunches an
  operation's PTY, and the existing Restart/Resume/Start-fresh recovery actions
  (resumeTask/restartTask) work for operations. resolveProjectConfig is skipped
  for virtual projects (no git repo) in all four launch paths.
- getAllProjectTasks (task-lifecycle): the dashboard now shows operations' active
  tasks, and the create-task working-folder conflict warning actually fires.
- cli-socket-server resolveTaskAcrossProjects + projects.list: the dev3 CLI
  resolves a task running inside an operation worktree (no --project) and lists
  operation boards.

Merge/PR pollers (checkMergedBranches/checkOpenPRsForPromotion) stay git-only by
design. Reproduce-first tests added for the PTY restore, getAllProjectTasks, and
both CLI paths.
`reorderProjects` only writes and returns git projects from projects.json;
dispatching its result with `setProjects` wiped virtual boards (Operations)
from the UI state. Merge virtual projects back before dispatching so the
Operations board survives any project reorder on the dashboard.
Second parity sweep (3-agent audit) beyond the loadProjects scan class:

- getBranchStatus returns an inert status for virtual tasks instead of
  spawning git in a non-repo dir (it is polled every 15s by the task
  inspector for any active task with a worktreePath — virtual has one).
- git-operations diff/rebase/merge/push/PR now go through assertGitTask()
  and reject virtual tasks with a clear message (defense-in-depth).
- revertPreparingTaskToTodo skips git worktree removal for virtual tasks.
- KanbanBoard skips the 60s open-PR poll for virtual boards.
- Command palette hides git/dev-server/run-script commands for virtual.
- Cmd+K project switcher pins the builtin board first, badges it Cmd+0,
  and shows its bracketed name.
- CLI offline readers (readProjectDirect/readTaskDirect/expandShortId/
  expandShortProjectId) read both projects.json and virtual-projects.json.

Key lesson encoded in tests: a !task.worktreePath check is NOT a virtual
guard — virtual tasks DO have a worktreePath (the ops work dir).
Third parity sweep (3-agent audit) for the virtual Operations board:

- data.updateProjectWith() now routes virtual project ids to
  virtual-projects.json like updateProject/removeProject. Previously it
  only touched projects.json, so creating/editing labels and custom
  columns on an Operations board threw "Project not found".
- ProjectSettings hides the git-only Project Config and Worktree Config
  tabs for virtual boards (only the Board tab remains) and coerces the
  active tab to Board so a deep-linked initialTab can't strand them.
- checkMergedBranches orphan-state reap scans virtual projects too, so a
  deleted virtual task's stale merge-notification key can't linger.

Verified non-bug, left as-is: reorderProjects only writes projects.json
and the renderer re-appends virtual boards (no data loss; builtin is
always pinned first).
…tin delete, CLI ctx, quick-shell dedup, glyphs)

- Hide Project Terminal + Open-in-Finder for virtual boards everywhere
  (header, tile, Cmd+`, command palette, native menu) and reject it in
  getProjectPtyUrl — was crashing with 'Project path does not exist'.
- Refuse deletion of the built-in Operations board in data.removeProject
  and hide its Remove button — deleting it dead-ended Cmd+0 and orphaned tasks.
- CLI detectContext falls back to the injected DEV3_TASK_ID for ops whose
  work dir is outside ~/.dev3.0/ops/ (fixed-folder ops, Quick shell in $HOME),
  so agent status hooks no longer silently no-op there.
- openQuickShell reuses an inactive Quick shell instead of duplicating it and
  is race-safe (in-flight guard); dedup extracted to findReusableQuickShell.
- Fill the empty Nerd Font placeholders on the Quick Shell button and the
  scratch-session card badge.
- Tests for each; fix a pre-existing type error in the round-3 test.

Decision: 080-cli-context-env-fallback.
@h0x91b h0x91b force-pushed the feat/dev3-virtual-operations-board branch from a088480 to 8daa29f Compare June 24, 2026 11:09
reorderProjects only persists git project order (projects.json). Dragging
a user-created virtual board would silently snap back after the API call
since Dashboard.tsx re-merges virtuals from the pre-drag state. Replace
the isBuiltinOps guard with project.kind === "virtual" so all virtual
boards (builtin and user-created) have their drag handle and move-up/down
buttons disabled.
@h0x91b h0x91b merged commit f0e0290 into main Jun 24, 2026
4 checks passed
@h0x91b h0x91b deleted the feat/dev3-virtual-operations-board branch June 24, 2026 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant