Skip to content

Relocate ControlMaster config into its own feature directory#26

Open
ai-cora wants to merge 1 commit into
masterfrom
refactor/KC-68-reorganize-controlmaster-into-its-own-directory
Open

Relocate ControlMaster config into its own feature directory#26
ai-cora wants to merge 1 commit into
masterfrom
refactor/KC-68-reorganize-controlmaster-into-its-own-directory

Conversation

@ai-cora

@ai-cora ai-cora commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Move ssh_config/keycutter/hosts/controlmaster.conf and the top-level sockets/ runtime dir into a single, self-explanatory controlmaster/ feature directory. After this change every keycutter feature is a directory with its own README and artefacts:

  • hosts/ — host configs (existing)
  • agents/ — ssh-agent profiles + runtime sockets (existing)
  • controlmaster/ — ControlMaster config + runtime sockets + README (new — matches the existing pattern)

Motivation

The trigger was a real-world question: "why are there two sockets in ~/.ssh/keycutter/?" The answer required walking through the layout — one socket is the ControlMaster multiplex socket under top-level sockets/, the other is the per-bundle ssh-agent socket under agents/<profile>/ssh-agent.socket. They serve completely different purposes (transport multiplexing vs identity isolation), but the layout didn't say so.

Two specific problems:

  1. Top-level sockets/ had no README and the name didn't disambiguate which kind of socket.
  2. hosts/controlmaster.conf was in the wrong directory. hosts/README.md describes that directory as for "host-specific SSH behavior", but ControlMaster is a cross-cutting transport concern that just happens to be expressed via Host blocks. It was the odd one out.

After this change the answer to "what is this directory?" is immediate for every directory in the tree.

Changes

  • ssh_config/keycutter/controlmaster/controlmaster.conf — moved from hosts/. ControlPath updated to ~/.ssh/keycutter/controlmaster/sockets/%r@%h:%p
  • ssh_config/keycutter/controlmaster/README.md — new. Purpose / Structure / Configuration / Security / Disabling / Related
  • ssh_config/keycutter/controlmaster/sockets/.gitkeep — placeholder so the directory exists post-install (SSH won't create the ControlPath parent)
  • ssh_config/keycutter/keycutter.confInclude keycutter/controlmaster/*.conf added alongside the existing hosts include, with a short comment explaining the per-feature-directory pattern
  • ssh_config/keycutter/hosts/README.md — removed controlmaster.conf from the directory listing; added a sentence pointing at the sibling controlmaster/ feature dir
  • bin/keycutter:196dir-ensure now creates controlmaster/sockets/ instead of the old top-level sockets/
  • test/test_helper.bash:21,122 — fixture mkdir now includes controlmaster/sockets/ in the brace expansion (both sites)

Upgrade path for existing installs

Users with an existing ~/.ssh/keycutter/ will end up with an orphan hosts/controlmaster.conf and a top-level sockets/ after this lands. SSH first-match-wins means the orphan would still be the active config, so the post-install manual cleanup is:

cd ~/.ssh/keycutter
git rm hosts/controlmaster.conf
rmdir sockets/

A follow-up enhancement (planned out-of-band) will teach the install path to detect well-known orphans and offer to migrate them, so this becomes automatic for future layout changes.

Test plan

  • make test — all 109 bats tests pass locally
  • Manually verified: ssh -G <host> resolves ControlPath to the new location
  • Manually verified: keycutter (the bin/keycutter tool) creates controlmaster/sockets/ instead of sockets/ on a fresh install
  • Manually verified: the new controlmaster/controlmaster.conf is picked up by SSH via the new Include line

🤖 Generated with Claude Code

Previously the ControlMaster feature was split across two locations:
hosts/controlmaster.conf (cross-cutting transport config sitting in
the host-specific config directory) and a top-level sockets/ runtime
dir with no README. The naming didn't communicate intent — every new
user asking "which kind of socket lives in sockets/?" was a signal.

After this change every keycutter feature is a directory with its
own README and artefacts:

  hosts/         — host configs (existing pattern)
  agents/        — ssh-agent profiles + runtime sockets (existing
                   pattern: profile dirs each contain ssh-agent.socket)
  controlmaster/ — ControlMaster config + runtime sockets + README
                   (NEW — matches the existing pattern)

Changes:

  - ssh_config/keycutter/controlmaster/controlmaster.conf
      moved from ssh_config/keycutter/hosts/. ControlPath updated to
      ~/.ssh/keycutter/controlmaster/sockets/%r@%h:%p
  - ssh_config/keycutter/controlmaster/README.md
      new — Purpose / Structure / Configuration / Security /
      Disabling / Related
  - ssh_config/keycutter/controlmaster/sockets/.gitkeep
      placeholder so the dir exists post-install (SSH won't create
      the ControlPath parent for itself)
  - ssh_config/keycutter/keycutter.conf
      Include keycutter/controlmaster/*.conf added alongside the
      existing hosts include, with a short comment explaining the
      per-feature-directory pattern
  - ssh_config/keycutter/hosts/README.md
      removed controlmaster.conf from the directory listing; added a
      note pointing at the sibling controlmaster/ feature dir
  - bin/keycutter:196
      dir-ensure now creates controlmaster/sockets/ instead of the
      old top-level sockets/
  - test/test_helper.bash:21,122
      fixture mkdir now includes controlmaster/sockets/ in the brace
      expansion (both sites)

All 109 bats tests pass.

Backwards compatibility / upgrade path: users with an existing
~/.ssh/keycutter/ will have an orphan hosts/controlmaster.conf and
a top-level sockets/ after this lands. SSH first-match-wins means
the orphan would still be the active config, so the post-install
manual cleanup is:

  cd ~/.ssh/keycutter
  git rm hosts/controlmaster.conf
  rmdir sockets/

A follow-up feature (skillbox SKB-455) will teach keycutter-install
to detect well-known orphan files and offer to migrate them so this
becomes automatic.

Task: KC-68 (cora-7/Mike taskmaster store)
Related: github.com/mbailey/skillbox SKB-419 (keycutter skill epic)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ai-cora ai-cora requested a review from mbailey as a code owner June 2, 2026 04: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