Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/blog-images/flock-commands.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/blog-images/flock-hero.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
54 changes: 54 additions & 0 deletions src/content/blog/flock-fish-worktree-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
title: 'flock: my worktree functions, now a fisher plugin'
description: 'The fish functions from my AI dev setup are now a proper, installable fisher plugin. One command to create a worktree, set up a layout, and launch an agent.'
pubDate: 2026-03-29
heroImage: /blog-images/flock-hero.jpg
tags: ['ai', 'fish', 'tooling', 'open-source', 'worktrees']
---

In [How I Stopped Babysitting Claude Code](/blog/remote-ai-development-stack/) I described a set of fish shell functions that wrap my entire worktree workflow — create a branch from a Linear ticket, set up a terminal layout, launch an AI coding agent. One command from ticket to agent working on it. Those functions lived in [my dotfiles](https://github.com/roderik/dotfiles-2026), which meant anyone who wanted to try them had to copy the right files into the right places and hope their setup was close enough to mine.

That's not really sharing something. It's "here, debug this."

I've packaged them as a proper fisher plugin: [roderik/flock](https://github.com/roderik/flock).

```fish
fisher install roderik/flock
```

## What you get

flock wraps the full git worktree lifecycle. Create a branch and worktree from a ticket number, set up your terminal layout with the right panes, launch your AI coding agent, do your work, tear everything down when the PR merges.

![flock commands overview](/blog-images/flock-commands.png)

```fish
flock new PRD-1234 # fetch ticket, create worktree, set up layout, launch agent
flock delete # remove current worktree + branch + remote ref
flock orchestrator # jump to your main project directory
```

Abbreviations ship with it — `fn` / `fd` / `fo` for the short versions, and `wtn` / `wtd` / `wto` as backward-compat aliases for anyone already on the dotfiles originals.

If you're using zellij, a layout file ships with the plugin and gets symlinked on shell start. That's what gives you the three-pane setup — main editor pane, lazygit on the right, spare terminal below. Not using zellij? This layer is entirely inert. The layout helpers are behind zellij checks, so nothing breaks.

Required: `git`, `gh`, `fzf`, `worktrunk`. Optional: `zellij`, `lazygit`, `linear` CLI, `claude` or `codex`.

## Making it portable

The original functions had my machine hardcoded everywhere. The orchestrator directory was `~/Development/dalp`. The remote hostname was `daystrom`. The zellij layout assumed a file that only existed because I'd put it there by hand.

Two environment variables replace all of that:

```fish
set -U FLOCK_ORCHESTRATOR_DIR ~/Development/my-project # default: ~/Development/dalp
set -U FLOCK_REMOTE_HOST my-server # default: daystrom
```

`FLOCK_ORCHESTRATOR_DIR` is the repo everything else orbits around — where `flock orchestrator` drops you. `FLOCK_REMOTE_HOST` is for the zellij helpers that manage remote sessions.

The actual work of packaging wasn't the fisher plugin structure — that's just a repo with functions in `functions/` and completions in `completions/`. It was sitting with each function and asking: what here is behavior, and what here is my specific machine? `daystrom` wasn't just a hostname. It appeared in conditional logic that assumed certain tools were installed remotely but not locally. Pulling that apart meant understanding decisions I'd made implicitly months earlier.

I'm not sure the variable names are final. `FLOCK_ORCHESTRATOR_DIR` is a mouthful. But the seam between "this is what the tool does" and "this is where I happen to run it" — that felt like the thing worth getting right.

**GitHub:** [github.com/roderik/flock](https://github.com/roderik/flock)
2 changes: 2 additions & 0 deletions src/content/blog/remote-ai-development-stack.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Everything is controllable over the socket: create workspaces, split panes, send

## The fish functions

> **Update:** These functions are now packaged as [flock](https://github.com/roderik/flock), a fisher plugin. `fisher install roderik/flock` installs everything described in this section. [Read the announcement.](/blog/flock-fish-worktree-plugin)

The actual entry point to my workflow is a [63-line fish function](https://github.com/roderik/dotfiles-2026/blob/main/.config/fish/functions/__wt_cmux_setup.fish) called `__wt_cmux_setup`. When [worktrunk](https://github.com/max-sixty/worktrunk) (my git worktree manager) drops me into a project directory, this fires automatically. It detects the cmux workspace, reads the pane topology, creates a right split with lazygit, a bottom split for a spare terminal, resizes everything to sensible proportions, and launches Claude Code or Codex in the main pane. It's idempotent — if the layout already exists, it skips. Every project gets the same three-pane setup without me touching anything.

On top of that, I have [wrapper functions](https://github.com/roderik/dotfiles-2026/tree/main/.config/fish/functions) that tie worktrees, cmux, and agents together:
Expand Down