Skip to content

Latest commit

 

History

History
355 lines (258 loc) · 16 KB

File metadata and controls

355 lines (258 loc) · 16 KB

vermilian

Validate Estimates, Requirements, and Milestones; Identify, Log Issues, Assign Next steps.

An Electron desktop application that provides an enhanced frontend for a self-hosted JetBrains YouTrack instance.

Vermilian features a high-density work queue for triaging and managing YouTrack tasks across table and Kanban views.

I decided not to design yet another project-management backend because YouTrack already manages the projects and workflows I need.

So I created Vermilian as a better frontend alternative with a dense work queue, table view, task popouts, and a Pomodoro timer.

Vermilian also features a fully functional Kanban board for quick task review.

Status

v1.2.9 — current release. Vermilian is feature-complete against its specification and available from GitHub Releases and package managers (see Installation). See the changelog for what changed in each release.

  • Built and working: the monday.com-style task board (table + Kanban) with grouping, filtering, and sorting; a top-bar issue search scoped to the active project (or the whole workspace when no project is selected); the task detail panel with inline field editing; the full Pomodoro focus timer (state machine, focus-mode lock, quit protection, crash-recovery checkpointing, and an automatic YouTrack worklog on stop); the AI and daily stand-up flows; layered credential storage; cross-machine workspace/project sync via a YouTrack Knowledge Base Article (self-healing against stale project ids, with a manual "Force resync from server" recovery action); workspace organisation, including an "+ Add projects" picker for moving projects between workspaces and a workspace delete that re-homes any projects it still holds; and light/dark themes.
  • Tested: over 175 unit tests cover the core logic (board grouping/sorting/filtering, the timer state machine, API transforms, search query building, and workspace-config sync), alongside an end-to-end (Playwright) suite over the board, detail panel, settings, timer, AI, stand-up, search, and workspace-config sync flows. Verified on Linux (Fedora 42) and macOS; the Windows build is published but less extensively exercised. Lint, the unit suite, and a full packaged build run in CI on every pull request into main; the end-to-end suite is run locally before a release, since it drives the packaged binary.

What it is

Vermilian is a cross-platform desktop app that connects to your self-hosted YouTrack via its REST API and provides a focused, opinionated interface for daily task and project management. YouTrack is the backend and source of truth; Vermilian is the client.

Installation

Each release is published to GitHub Releases and to a package manager per platform. Pick your platform below.

Linux — AppImage

Download Vermilian-*-x86_64.AppImage from the latest release, then:

chmod +x Vermilian-*-x86_64.AppImage
./Vermilian-*-x86_64.AppImage

An AppImage is one self-contained file that runs on any modern x86_64 distribution — no install step. For a desktop menu entry, use AppImageLauncher.

Raspberry Pi (arm64): the x86_64 AppImage will not run on a Pi. Build a native arm64 AppImage on a 64-bit Pi yourself — see Target platforms.

macOS — Homebrew Cask

Requires Homebrew. Add the tap once, then install the Cask:

brew tap kevinpinscoe/tap                 # add the tap (one time)
brew install --cask vermilian             # install Vermilian.app into /Applications

# later:
brew upgrade --cask vermilian             # update to the newest release
brew uninstall --cask vermilian           # remove

The tap + Cask in one line also works: brew install --cask kevinpinscoe/tap/vermilian.

Prefer a manual install? Download the Apple Silicon (arm64) .dmg from the release and drag Vermilian to Applications. (Intel Macs are not yet served — see Target platforms.)

Unsigned build: Vermilian is not yet notarized with an Apple Developer ID, so Gatekeeper reports that the app "cannot be opened" or "is damaged." The Homebrew Cask clears the quarantine flag for you automatically. For the manual .dmg, run this once after dragging it in:

xattr -dr com.apple.quarantine /Applications/Vermilian.app

Windows — Scoop

Requires Scoop. Add the bucket once, then install:

scoop bucket add kevinpinscoe https://github.com/kevinpinscoe/scoop-bucket   # add the bucket (one time)
scoop install vermilian                                                       # install

# later:
scoop update vermilian                                                        # update to the newest release
scoop uninstall vermilian                                                     # remove

Prefer a manual install? Download and run the Squirrel Vermilian-*Setup.exe from the release.

Highlights

These are the features that shape Vermilian. They are built and working; the app is feature-complete against its spec and shipping as of v1.0.0 (see Status):

  • Pomodoro focus timer — a single-task focus tool built around ADHD work patterns. Running a timer puts the app into a focus mode; stopping it logs the elapsed minutes as a YouTrack work item. Defaults to Pomodoro cycles (25-minute work blocks, breaks, long break every four), with an open-ended mode as well.
  • monday.com-style board — a high-density task board with colour-coded status, priority, and category chips, grouping, filtering, and sorting; table and Kanban views.
  • Layered credential sources — read your YouTrack token from a shell command (e.g. a secrets manager), a file path, or the OS keyring — whichever fits your setup.
  • Cross-platform desktop — Linux (x86_64 AppImage), macOS (Apple Silicon .dmg), and Windows. Intel macOS and Raspberry Pi / arm64 Linux can be built from source (see Target platforms).

Screenshots

Captured against built-in demo data — no real YouTrack instance required.

Task board — grouped by status, with priority and category chips:

Vermilian task board, light theme

Dark theme:

Vermilian task board, dark theme

Task detail panel — inline field editing and a built-in Pomodoro timer:

Vermilian task detail panel

Pomodoro focus timer — focus mode with a work-block countdown; stopping logs a YouTrack worklog:

Vermilian Pomodoro focus timer

Settings — the Connection section, with layered credential sources (shell command, file path, or OS keyring):

Vermilian settings — connection

Target platforms

Platform Artifact Architecture v1.0.0
Linux (Fedora / Ubuntu) AppImage x86_64 published
macOS (Apple Silicon) .dmg arm64 published
Windows 11 Squirrel installer + Scoop x86_64 published
macOS (Intel) .dmg x86_64 build from source
Raspberry Pi OS AppImage arm64 (64-bit only) build from source

CI currently publishes Linux x86_64, macOS arm64, and Windows x86_64. The other two architectures build natively from source with the same command (run on the target machine):

cd app
mise install && corepack enable pnpm
pnpm install
pnpm make
# Intel Mac  → app/out/make/Vermilian-<ver>-x64.dmg
# 64-bit Pi  → app/out/make/AppImage/x64/Vermilian-<ver>-arm64.AppImage

Automated Intel-macOS (macos-13) and arm64-Linux (ubuntu-24.04-arm) runners are planned for a follow-up release.

Tech stack

Layer Choice
App shell Electron (electron-forge)
UI framework React 18 + TypeScript
Design system monday.com Vibe — React component library for monday.com-style UI
Package manager pnpm
Diagramming D2, Mermaid (Kroki)

Local development

The app lives in app/. The toolchain is pinned by mise.toml (Node 24.15.0); pnpm comes from corepack, not the system. Neither is active in a stock non-interactive shell, so each session needs the mise node bin on PATH:

# one-time
mise trust                 # trust the pinned mise.toml
mise install               # install Node 24.15.0
corepack enable pnpm       # enable pnpm 11 (uses the mise node)

# every session
export PATH="$HOME/.local/share/mise/installs/node/24.15.0/bin:$PATH"

Then, from app/:

pnpm install
pnpm start                       # run app in development (Electron + Vite HMR)
pnpm lint                        # ESLint
pnpm package                     # electron-forge bundle (no GUI needed)
./node_modules/.bin/tsc --noEmit # type-check only

System /usr/bin/node on Fedora is v22 — too old. Always use the mise-managed v24.

pnpm 11.5 config gotcha: block-exotic-subdeps=false in app/.npmrc is silently ignored by pnpm 11.5+ and pnpm add fails with ERR_PNPM_EXOTIC_SUBDEP on @electron/rebuild's git subdep. The canonical form is blockExoticSubdeps: false in app/pnpm-workspace.yaml, mirroring how nodeLinker is configured there. The .npmrc line is kept as a legacy marker.

Look and feel

Vermilian targets a monday.com-style visual experience: high-density boards, strong colour-coded status and priority chips, left-rail navigation, and inline editing without full-page reloads. The monday.com Vibe Design System provides the React component library, theming tokens, and accessibility guidelines used throughout the app.

Tuning dark mode colours

Theme colours are defined in app/src/renderer/theme.ts. Two independent palettes let the left nav and the main board have different text colours:

Variable Where it applies
--nav-header-text-color Left rail — workspace name, "All tasks" link
--nav-primary-text-color Left rail — project names
--nav-secondary-text-color Left rail — folder names, issue-count badges
--primary-text-color Board — task titles, column headers
--secondary-text-color Board — issue IDs, secondary labels

To tune colours live without editing source, use the Electron DevTools colour picker:

  1. Run the app (pnpm start from app/).
  2. Press Cmd+Option+I (macOS) or Ctrl+Shift+I (Linux/Windows) to open DevTools.
  3. In the Elements panel, find <style id="vermilian-theme-overrides">.
  4. Click any hex colour value — the browser's built-in colour picker opens.
  5. Adjust until satisfied, then copy the final hex values back into DARK_PALETTE in theme.ts.

Development approach

Vermilian is built spec-first using Spec Driven Design (SDD). Feature specs in spec/features/ define what the app must do before any code is written. Claude Code implements against those specs.

See spec/README.md for the full SDD workflow.

Phases

Phase Goal
0 Dev environment — tools installed, YouTrack API verified
1 SDD design — specs, wireframes, ADRs, API contracts
2 Coding — implement from specs
3 Testing — unit + E2E tests, cross-platform smoke tests
4 Public release — GitHub migration, CI/CD, first versioned release

Implementation notes — current increment

Phase 2 increment 1 (Foundation + Settings) is shipped but has a few known deviations from the specs/wireframes that will be cleaned up in follow-up work:

  • Confirmations are inline AttentionBox panels, not Vibe Modal / AlertDialog. The Reset-to-defaults confirm is implemented; the Cancel-with-unsaved-credentials confirm is not yet (Cancel currently discards immediately).
  • Test connection messages show the raw API error string rather than the friendly 401-vs-network strings the Settings spec calls for (e.g. "Invalid token or insufficient permissions.").
  • Theme switching toggles light-app-theme / dark-app-theme classes on the app root div. These are the standard Vibe theme classes, but the visual switch has not been confirmed in a graphical session yet.
  • blockExoticSubdeps config moved (see Local development above) — app/.npmrc keeps the legacy entry for older pnpm; pnpm 11.5+ requires the canonical form in app/pnpm-workspace.yaml.

Repository Layout

vermilian/
├── app/                    # Electron app root (electron-forge, Vite, React 18, Vibe)
│   ├── src/
│   │   ├── main/           # Electron main process modules
│   │   ├── renderer/       # React renderer — components, hooks, stores, API client
│   │   ├── shared/         # Types and utilities shared across processes
│   │   ├── main.ts         # Electron main process entry
│   │   ├── preload.ts      # Electron preload (contextBridge IPC)
│   │   └── renderer.tsx    # React app entry — mounts <App>
│   ├── forge.config.ts     # electron-forge config
│   ├── vite.*.config.ts    # per-process Vite configs
│   ├── pnpm-workspace.yaml # pnpm compat settings (must not be removed)
│   └── package.json
├── spec/
│   ├── features/           # authoritative feature specs (SDD workflow)
│   └── phases/             # phase-level specs with exit criteria
├── docs/
│   ├── adr/                # Architecture Decision Records
│   ├── architecture/       # D2 component diagrams
│   ├── design/             # D2 / Mermaid UI wireframes
│   └── requirements.md
├── cli/YouTrack/           # planned Go CLI (in progress)
├── mise.toml               # Node 24.15.0 toolchain pin
├── CONTRIBUTING.md
├── LICENSE
├── README.md
└── RUNBOOK.md

Documentation

App icon

The default Electron icon can be replaced by dropping three files into app/build/ and updating the forge config.

Image requirements

Platform Format Minimum size
macOS .icns 1024×1024 source
Windows .ico 256×256 source (multi-resolution container)
Linux .png 512×512 (1024×1024 recommended)

Start with a single 1024×1024 PNG and convert to the platform formats. Tools: Iconset (macOS app), icotool (Linux CLI), or the npm package electron-icon-maker.

Wiring it up

1. Place the files:

app/build/
  icon.icns
  icon.ico
  icon.png

2. Update app/forge.config.ts:

packagerConfig: {
  asar: true,
  icon: './build/icon',   // no extension — forge picks the right format per platform
},
// ...
new MakerDMG({ icon: './build/icon.icns' }, ['darwin']),
new MakerAppImage({ options: { icon: './build/icon.png' } }, ['linux']),

3. Set the runtime window icon in app/src/main/window.ts (shown in the taskbar/dock while the app is running, independently of the packaged installer icon):

new BrowserWindow({
  icon: path.join(__dirname, '../build/icon.png'),
  // ...
})

pnpm start picks up the window icon immediately; pnpm make bakes it into the installer packages.

Contributing

See CONTRIBUTING.md for the PR workflow and diagram conventions.

License

Copyright © Kevin P. Inscoe.

Vermilian is licensed under the GNU General Public License v3.0 only (GPL-3.0-only). You may use, study, share, and modify it under the terms of that license; distributed modifications must also be released under the GPL-3.0. See the LICENSE file for the full text, or https://www.gnu.org/licenses/gpl-3.0.html.