Skip to content

feat(setup): make a fresh install land in Flock, not plain Zellij - #27

Closed
abeljim8am wants to merge 4 commits into
mainfrom
feat/default-setup-phase-0
Closed

feat(setup): make a fresh install land in Flock, not plain Zellij#27
abeljim8am wants to merge 4 commits into
mainfrom
feat/default-setup-phase-0

Conversation

@abeljim8am

@abeljim8am abeljim8am commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Why

A fresh flock install is byte-for-byte plain Zellij. Everything that makes it Flock — the sidebar dock, the project selector, agent status — is opt-in through KDL the user has to know to write. The working setup lived entirely in personal config outside the repo, reached through a shell alias.

This is Phase 0 of the plan added in the first commit (.ai-workspace/flock-default-setup-plan.md), which covers phases 0–4. Phase 0 is the independently shippable slice: it moves a fresh install from "plain Zellij" to "sidebar + working selector".

What changed

  • The built-in flock layout is the startup fallback, so the sidebar is docked on a fresh install.
  • Super s opens the project selector. There was previously no binding at all.
  • flock-selector and flock-sidebar are registered as plugin aliases, and the bundled flock.kdl / flock-selector.kdl now reference those aliases instead of restating args. Folder args are stated once in config.kdl and reach the layouts, the keybinding, and each project session's sidebar alike.
  • Selector-created sessions default to the flock layout. They previously got Zellij's default, so a project opened through Flock had no sidebar and no way back to the selector. Remote sessions already had a dock-bearing fallback; this makes local ones agree.
  • README's "Enable Flock" section rewritten — it taught the arg-pasting shape this PR replaces.

Your own layouts still win

Not a breaking change. default_layout is deliberately left unset and the flock layout is a fallback:

situation startup layout
you have layouts/default.kdl your layout, untouched
you have none built-in flock (sidebar docked)
default_layout "default" plain upstream Zellij chrome

The first commit got this wrong — it shipped default_layout "flock", which skips the default.kdl lookup and would have silently ignored a layout the user wrote. The second commit fixes it. The rule now lives in two places that must agree (LayoutInfo::from_config, which decides what the session records it started from, and the loader in layout.rs), both keyed off data::FALLBACK_BUILTIN_LAYOUT and checking the same extensionless-then-.kdl candidates, so they cannot disagree about whether a user file exists. All three rows above are covered by tests.

The part worth reviewing

The alias indirection is not just tidiness — it removes an existing bug class by construction instead of by discipline. A keybinding whose arg set disagreed with the layout's used to miss the running selector and launch a second one; that near-miss has its own regression test in plugins/plugin_map.rs. With one source of truth the sets cannot disagree.

The tradeoff is that alias resolution is late and silent: an unresolved alias loads no plugin and renders an empty dock, with no error. So both bundled layouts get a test asserting they actually resolve against the shipped default config.

Verification

  • cargo xtask test — 2339 passing, 0 failures. cargo xtask format --check clean. (Clippy is not a CI gate here and has a large pre-existing baseline.)
  • Snapshot updates reviewed line-by-line; every touched line is one of the intended changes.
  • Checked against the built binary, not just unit tests — which is what caught the default_layout mistake. A fresh config dir with a default.kdl still came up with the dock, contradicting a passing unit test. Two traps behind that, both now recorded in the plan doc:
    • the client re-derives LayoutInfo from config_options.layout_dir (unset here) rather than the config-dir-derived path;
    • on a config dir with no config.kdl, the first-run setup wizard overrides the layout and writes a config.kdl into that directory — which silently polluted a test fixture I had pointed the binary at, flipping a correct test from pass to fail. Fixture restored; verification redone with a pre-seeded config.kdl.
  • Final end-to-end result: a config dir with layouts/default.kdl starts with that layout and no dock; one without starts with the flock layout and the dock. With root_dirs set only on the alias, action dump-layout shows them resolved onto the sidebar inside the layout, which the layout never mentions.
  • The README's rebind snippet was run through setup --check ([CONFIG FILE]: Well defined.) rather than shipped untested.

Notes for follow-up phases

flock setup --check still does not report the resolved layout or Flock config, which is exactly what made verifying this by hand hard — that is Phase 4. Phase 1 (flock { } config block) would also let the generated remote layouts stop emitting sidebar_args explicitly, which this PR deliberately left alone to avoid touching the remote path.

🤖 Generated with Claude Code

A fresh install currently behaves exactly like upstream Zellij — the sidebar,
selector and agent status are all opt-in through hand-authored KDL. Records the
gaps and a five-phase plan for closing them, with the locked decisions: bare
flock opens the selector, Super s is the selector key, no filesystem
auto-discovery, and no dependency on any external config manager.
Everything that distinguishes Flock — the sidebar dock, the project selector,
agent status — was opt-in through hand-authored KDL, so `flock` with no config
was byte-for-byte upstream `zellij`. Phase 0 of the out-of-the-box plan:

- default_layout ships as "flock" instead of being unset, so the sidebar is
  docked on startup.
- Super s opens the project selector. Super is swallowed by some terminals
  before Flock sees it; documented, with the rebind.
- flock-selector and flock-sidebar are registered as plugin aliases, and the
  bundled layouts now reference those aliases instead of restating args. Folder
  args are therefore stated once in config.kdl and reach the layouts, the
  keybinding, and each project session's sidebar alike.
- Sessions created from the selector default to the `flock` layout. They
  previously got Zellij's `default`, leaving a project opened *through* Flock
  with no sidebar and no way back to the selector.

The alias indirection removes an existing bug class by construction rather than
by discipline: a keybinding whose arg set disagreed with the layout's used to
miss the running selector and launch a second one (see the subset-match test in
plugins/plugin_map.rs). With one source of truth the sets cannot disagree.

Because the alias is resolved late and silently — an unresolved alias just loads
no plugin and renders an empty dock — both bundled layouts get a test asserting
they resolve against the shipped default config.

BREAKING: a custom ~/.config/flock/layouts/default.kdl is no longer loaded on
startup, since resolution now looks for the name "flock". Set
default_layout "default" to restore it, or rename the file to flock.kdl. Pinned
by tests in both directions.
Shipping `default_layout "flock"` was the wrong lever. Setting that option
skips the `layouts/default.kdl` lookup entirely, so anyone who had written their
own default layout silently stopped getting it — a breaking change bought for no
benefit.

Make the flock layout a startup *fallback* instead. `default_layout` goes back
to unset, and the fallback applies only when the caller named no layout at all
*and* the user has no `default.kdl` of their own:

- user has layouts/default.kdl  -> their layout (no dock)
- user has none                 -> built-in flock layout (sidebar docked)
- default_layout "default"      -> plain upstream Zellij chrome

The rule lives in two places that must agree — LayoutInfo::from_config, which
decides what the session records it started from, and the loader in layout.rs,
which reads the KDL. Both key off data::FALLBACK_BUILTIN_LAYOUT and check the
same extensionless-then-.kdl candidates, so they cannot disagree about whether
a user file exists. Tests cover all three rows above.

Found by checking the built binary rather than trusting the unit tests: a fresh
config dir with a default.kdl still came up with the dock. Two traps worth
recording, both now noted in the plan doc — the client re-derives LayoutInfo
from config_options.layout_dir (unset here) rather than the config-dir-derived
path, and on a config dir with no config.kdl the first-run setup wizard both
overrides the layout and writes a config.kdl into that directory, which
pollutes any fixture you point it at.
@abeljim

abeljim commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

Superseded by mega PR #35

@abeljim abeljim closed this Aug 22, 2026
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.

2 participants