Skip to content

feat: rules for where an app's windows open, and auto-filled zones - #113

Merged
ostapondo merged 2 commits into
mainfrom
feat/app-rules
Aug 26, 2026
Merged

ostapondo merged 2 commits into
mainfrom
feat/app-rules

Conversation

@ostapondo

@ostapondo ostapondo commented Aug 25, 2026

Copy link
Copy Markdown
Owner

What changed, and why

Rules for where an app's windows open. Pick an app on the Zones page, a zone, and if you want a monitor, and every new window of that app lands there. Stored by display UUID, so it survives a relaunch and a reboot that renumbers the screens. Wins over the "where the last one went" habit when both apply.

Also a switch that drops a new window with no rule and no habit into the first empty zone. Off by default.

Agents get set_app_rule and clear_app_rule, and app_rules in get_state. README tool count goes from 20 to 22.

Two side changes: the app picker from the exclusions list is now AppAdder so the rules list can reuse it, and mcp/src/api.ts was at the 300-line limit, so its response types moved to types.ts.

What you ran

(cd App && swift build)
./scripts/test.sh                 497 pass, 16 new
./scripts/lint.sh
(cd mcp && npm ci && npm test)    32 pass
node scripts/check-strings.mjs

Checks

  • swift build passes on every commit in the branch
  • New logic is covered: AppRuleTests, AppRuleRoutesTests
  • Conventional commits
  • Nothing touches the network, permissions, entitlements or the update path
  • No screenshots yet; the new card is "Where apps open" on the Zones page

If this moves windows

Setup: macOS 26, one built-in display at 2x, Halves.

  • One screen. Rule TextEdit to zone 2 over the API, then testbench.sh up 1: the window landed in zone 2.
  • Put it back: not touched.
  • Second monitor: no hardware. A rule for a display that is not attached falls back to the screen the window opened on.
  • Mixed scale factors: no hardware.
  • Unplug and plug back in: no hardware.
  • Excluded app: the watcher checks the exclusion list before placing, as before.
screen 0  1728x1084
  plonk-bench-1.txt      screen 0  x 0.510  y 0.010  w 0.490  h 0.980

@ostapondo
ostapondo force-pushed the feat/app-rules branch 2 times, most recently from 491b1c6 to 4929a6f Compare August 26, 2026 00:06
A rule is the "where the last window went" habit written down: app,
zone, optional display, kept in config so it survives a relaunch. A
second switch drops a window with no rule and no habit into the first
empty zone.

Routes: /zones/rules and /zones/rules/delete, tools set_app_rule and
clear_app_rule, app_rules in /state. The app picker from the exclusions
list is now AppAdder so the rules list can use it. mcp/src/api.ts hit
the 300-line limit, so its response types moved to types.ts.
# Conflicts:
#	App/Sources/plonk/Router+Zones.swift
#	App/Sources/plonk/Zones.swift
#	mcp/src/api.ts
#	mcp/src/tools/state.ts
@ostapondo
ostapondo merged commit a61e8ca into main Aug 26, 2026
7 checks passed
@ostapondo
ostapondo deleted the feat/app-rules branch August 26, 2026 11:58
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