# Daily developer workflow: Things3, one worktree per task, Claude Code
> [!summary] TL;DR
> Capture everything in Things3 (Monday query: `P0 + High Mental Energy`), isolate each task as one git worktree plus one tmux session plus one Claude Code session, and gate every change with `make check` (`gofumpt`, `goimports`, `golangci-lint`, `go test -race -count=1 ./...`). The shell function `cf` grew into `af`, a Go CLI that manages the worktree-tmux-agent triple as a workstream with a suspend/resume/done lifecycle. The AI's output is a draft; the test suite is the ground truth.
## Key points
- This is a snapshot of the version of the setup that works in May 2026.
- Everything possible goes into Things3, a capture-first inbox triaged on weekends, not a real-time tracker; the inbox currently holds around 970 items.
- Tags do the actual work: `P0` / `P1` / `P2` (because "Today" can't be trusted; every snoozed thing looks like today), `High Mental Energy` / `Low Mental Energy`, and role tags (`architect`, `coder`, `mentor`, `communicator`, `researcher`) for batching context.
- The query opened on Monday morning: `P0 + High Mental Energy`. Everything else can wait.
- A task is a branch, and a branch gets its own file tree and its own AI conversation.
- Git worktrees check out one branch per directory at `~/Workspace/.worktrees/<repo>/<branch>/`; tmux runs one named session per task.
- Claude Code gets a deterministic session ID (uuid5 over `repo/branch`), so the same task always resumes the same conversation, even after a reboot.
- `cf issue-42` does the whole setup, `cfr` resumes, `cfd` tears it down; the shell function is now growing a Go successor called `af`.
- `af` calls the worktree-plus-tmux-plus-agent triple a workstream; state lives at `~/.local/share/af/v1/sessions/<name>/state.toml`, so there are no hidden tmux env vars and no fragile shell state.
- The worktree layout, including subagent sub-worktrees at `<branch>--<slot>` on sibling branches, is pinned in ADR-038; the multiplexer is tmux-only; agents are `claude`, `pi` (default), or `codex` behind a single Go interface.
- `make check` runs `gofumpt`, `goimports`, `golangci-lint` (every linter on, no exceptions), and `go test -race -count=1 ./...`. If any of it is red, the work isn't done.
- Claude Code accelerates the middle TDD step; the AI's output is a draft and the test suite is the ground truth. No unread code ships.
- Two Obsidian vaults (personal and work, PARA-style) are searched with `qmd`: BM25 keyword search, vector embeddings, and LLM reranking, via CLI or MCP.
- `af`'s core is implementation-complete and runs the day; heavy development is in agent-session sync between VM and host, PR-state TTL caching, and an `af review` command (ADR-073).
- `af` is single-user, single-machine, and not packaged for release.
## Capture: Things3
Everything possible goes into Things3. It's a capture-first inbox triaged on weekends, not a real-time tracker. The inbox currently holds around 970 items, which is somewhere between "honest capture" and "avoidance."
The tags do the actual work:
- `P0` / `P1` / `P2`: I don't trust "Today" because every snoozed thing looks like today.
- `High Mental Energy` / `Low Mental Energy`: important-but-hard tasks die when you lie to yourself about which is which.
- Role tags (`architect`, `coder`, `mentor`, `communicator`, `researcher`): useful for batching context.
The query I open on Monday morning: `P0 + High Mental Energy`. Everything else can wait.
## Isolation: one worktree per task
A task is a branch, and a branch gets its own file tree and its own AI conversation:
- Git worktrees check out one branch per directory at `~/Workspace/.worktrees/<repo>/<branch>/`.
- tmux runs one named session per task.
- Claude Code gets a deterministic session ID (uuid5 over `repo/branch`), so the same task always resumes the same conversation, even after a reboot.
This started as a shell function called `cf` (claude-focus), documented in [[resources/documentation/Claude Focus Workflow|Claude Focus Workflow]]. `cf issue-42` does the whole setup; `cfr` resumes; `cfd` tears it down.
The shell function is now growing a Go successor called `af` (agentic-flow / automatic-flow / as-fuck, pick your mood). Same job, but with proper lifecycle semantics, layered config, and a test suite instead of accumulating bash edge cases.
`af` calls the worktree-plus-tmux-plus-agent triple a **workstream**. The lifecycle commands:
```
af create issue-42 → active
af suspend issue-42 → suspended (tmux down, VM destroyed if any)
af resume issue-42 → active again
af done issue-42 → completed (or abandoned)
```
State lives at `~/.local/share/af/v1/sessions/<name>/state.toml`, so there are no hidden tmux env vars and no fragile shell state to babysit. The worktree layout, including subagent sub-worktrees at `<branch>--<slot>` on sibling branches, is pinned in ADR-038. Multiplexer is tmux-only; agents are `claude`, `pi` (default), or `codex` behind a single Go interface.
`af`'s core is implementation-complete and runs my day. The heavy development is in newer areas: agent-session sync between VM and host, PR-state TTL caching, and an `af review` command (ADR-073) that drives a configurable PR review through any agent.
## Development: TDD with Claude as draft generator
Inside a worktree, the loop is intentionally boring:
1. Write the failing test.
2. Write the minimum implementation.
3. Refactor.
4. Run `make check`.
`make check` runs `gofumpt`, `goimports`, `golangci-lint` (every linter on, no exceptions), and `go test -race -count=1 ./...`. If any of it is red, the work isn't done.
Claude Code accelerates the middle step: I describe the problem, it sketches an approach, I push back on the sketch, it implements, I read every diff. The AI's output is a draft; the test suite is the ground truth. I don't ship code I haven't read.
For multi-issue work, `af` spawns subagents in their own sub-worktrees so they don't fight over files. Overkill most days; essential a few times a month.
## Notes: Obsidian plus qmd
Two Obsidian vaults, personal and work, structured PARA-style. I search across them with `qmd`, a local-first tool run via CLI or MCP that combines BM25 keyword search, vector embeddings, and LLM reranking. In practice it's `grep` for a corpus I can't remember the shape of: "find the note where I was thinking about GLS leak detection" gives three results, pick the right one, full document in hand.
The piece not built yet: `af create` should stub out a note per workstream in the work vault, linked from `state.toml`. Right now I keep the link manually, which means I sometimes don't.
## What is still rough
- Inbox triage. Capture is working; triage is not. No tool fixes this, only doing it does.
- `af` and `cf` overlap. Both exist on my machine; long-lived `cf` sessions are not migrated to `af` yet, so I run both.
- Obsidian linking is designed but not implemented.
- Notes-to-blog pipeline. Getting from a good Obsidian note to a published post has enough manual friction that this post is its own counterexample: three drafts and a slop-cleaning pass before shipping.
`af` is single-user, single-machine, and not packaged for release. It solves my problem and the design is settled enough that I'd rather build the remaining features than productize the parts that work.
## FAQ
### How do I keep AI coding tasks from interfering with each other?
One task, one branch, one worktree, one tmux session, one agent conversation. Worktrees check out one branch per directory at `~/Workspace/.worktrees/<repo>/<branch>/`, and for multi-issue work `af` spawns subagents in their own sub-worktrees so they don't fight over files.
### What is a workstream in af?
The worktree-plus-tmux-plus-agent triple. `af create` makes it active, `af suspend` takes it down (tmux down, VM destroyed if any), `af resume` brings it back, `af done` completes or abandons it. State lives at `~/.local/share/af/v1/sessions/<name>/state.toml`.
### How does af resume the same Claude Code conversation after a reboot?
Claude Code gets a deterministic session ID computed as uuid5 over `repo/branch`, so the same task always resumes the same conversation, even after a reboot.
### What does make check run?
`gofumpt`, `goimports`, `golangci-lint` (every linter on, no exceptions), and `go test -race -count=1 ./...`. If any of it is red, the work isn't done.
### How do you search across two Obsidian vaults?
Two PARA-style vaults, personal and work, searched with `qmd` via CLI or MCP: BM25 keyword search, vector embeddings, and LLM reranking. It's `grep` for a corpus you can't remember the shape of.
### Is af available to install?
No. `af` is single-user, single-machine, and not packaged for release. It solves one person's problem, and the design is settled enough that the remaining features are worth more than productizing the parts that work.
### Should I still read every diff when Claude Code writes the code?
Yes. The AI's output is a draft; the test suite is the ground truth. I don't ship code I haven't read.
## Related
- [[resources/documentation/Agents/Agents Workflow|Agents Workflow]] (series hub)
- [[resources/documentation/Agents/Agents - One Workstream per Task|One Workstream per Task]] (one workstream per task)
- [[resources/documentation/Agents/Agents - Plan First, Fresh Sessions, Write It Down|Plan First, Fresh Sessions, Write It Down]] (the on-disk canon: `PROGRESS.md`, `TODO.md`, `CLAUDE.md`)
- [[resources/documentation/Agents/Agents - Second Brain with Obsidian and AI|Second Brain with Obsidian and AI]] (the Obsidian and `qmd` retrieval side)
- [[resources/documentation/Claude Focus Workflow|Claude Focus Workflow]] (the `cf` command this system grew out of)
## Sources