Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0d093dd
feat(agent): add favorites and recent-projects quick-nav header
kuchmenko May 16, 2026
d340c32
chore(docs): consolidate CLAUDE.md into AGENTS.md
kuchmenko May 16, 2026
e7a353f
docs(agents): adopt mechanical and architectural rules
kuchmenko May 16, 2026
9e4d86a
refactor(config): split config.go by domain
kuchmenko May 16, 2026
fde021e
refactor(cli): split worktree.go by subcommand
kuchmenko May 16, 2026
2c3f95f
refactor(migrate): split migrate.go by responsibility
kuchmenko May 16, 2026
b461747
refactor(cli): split migrate_tui.go into model/view
kuchmenko May 16, 2026
2c1e3c3
refactor(cli): split bootstrap.go into model/view
kuchmenko May 16, 2026
b24d38e
refactor(daemon): split reconciler.go by phase
kuchmenko May 16, 2026
0c35902
refactor(create): split tui.go into cmd/render/runner
kuchmenko May 16, 2026
3ea37b3
refactor(add): split tui.go by state and concern
kuchmenko May 16, 2026
8227823
refactor(agent): split tui.go by state and concern
kuchmenko May 16, 2026
0f1accb
docs(agents): add cyclomatic complexity rule (10 soft / 15 hard)
kuchmenko May 16, 2026
077ccce
feat(agent): pin compact quick-nav chips above the tree
kuchmenko May 16, 2026
a20b8b3
feat(agent): language-based project icons
kuchmenko May 16, 2026
f5226e0
feat(agent): number hotkeys 1-9 launch chip projects
kuchmenko May 16, 2026
483ff10
feat(explorer): rename ws agent → ws explorer
kuchmenko May 16, 2026
ca8bce1
style(explorer): drop expand arrow, lightning prefix on worktree count
kuchmenko May 16, 2026
8e204e6
feat(explorer): group favorites + chip action modal
kuchmenko May 16, 2026
e0fef1c
fix(lint): align golangci complexity with AGENTS.md (15 hard)
kuchmenko May 16, 2026
03a8b97
fix(lint): widen golangci path globs to cover split files
kuchmenko May 16, 2026
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
40 changes: 25 additions & 15 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,17 @@ linters:

settings:
gocognit:
# tkach's clippy.toml: cognitive-complexity-threshold = 7. Same
# metric as Sonar's cognitive complexity — penalizes nested control
# flow more heavily than cyclomatic. 7 is strict; offending files
# are path-excluded below (Bubble Tea reducers, MigrateProject,
# syncProject) where the switch-on-state pattern is the design.
min-complexity: 7
# Cognitive complexity threshold. AGENTS.md sets the policy:
# functions over 10 split on next touch, functions over 15
# split now. CI fails at the hard 15 line; the 10-line soft
# rule is enforced by reviewer/agent discipline, not gocognit.
min-complexity: 15

gocyclo:
# Cyclomatic complexity (decision-point count) — a secondary signal
# since gocognit is the primary cognitive-complexity check.
min-complexity: 20
# Cyclomatic complexity (decision-point count) — a secondary
# signal since gocognit is the primary cognitive-complexity
# check. Aligned with the AGENTS.md 15-hard / 10-soft policy.
min-complexity: 15

funlen:
# tkach's clippy.toml: too-many-lines-threshold = 200.
Expand Down Expand Up @@ -193,7 +193,11 @@ linters:
- gocyclo
- gocognit
- funlen
- path: internal/cli/.*tui.*\.go
# Bubble Tea reducer files under cli/. Covers the original
# *_tui.go files plus the model/view splits (migrate_model.go,
# migrate_view.go, bootstrap_model.go, bootstrap_view.go,
# bootstrap_clone.go).
- path: internal/cli/.*(tui|model|view|clone).*\.go
linters:
- gocyclo
- gocognit
Expand All @@ -214,15 +218,21 @@ linters:
- gocyclo
- gocognit
- funlen
- path: internal/daemon/reconciler\.go
# Daemon reconciler: the original reconciler.go was split into
# reconciler.go + projects.go + toml.go + conflicts.go + git.go.
# The state-machine fan-out lives in projects.go and toml.go now.
- path: internal/daemon/.*\.go
linters:
- gocyclo
- gocognit
- funlen
# Worktree add command resolves three input cases (existing
# worktree / existing branch / fresh) plus collision suffix and
# remote upstream wiring; the switch is the spec.
- path: internal/cli/worktree\.go
# Worktree commands resolve three input cases (existing worktree /
# existing branch / fresh) plus collision suffix and remote
# upstream wiring; the switch is the spec. Glob covers both the
# pre-split worktree.go and the per-subcommand splits
# (worktree_add.go, worktree_list.go, worktree_rm.go,
# worktree_push.go).
- path: internal/cli/worktree.*\.go
linters:
- gocyclo
- gocognit
Expand Down
646 changes: 627 additions & 19 deletions AGENTS.md

Large diffs are not rendered by default.

490 changes: 0 additions & 490 deletions CLAUDE.md

This file was deleted.

82 changes: 52 additions & 30 deletions docs/agent-tui.md → docs/explorer.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,58 @@
# Agent TUI
# Explorer TUI

`ws` (run with no arguments in a TTY) — or `ws agent` explicitly —
opens a Bubble Tea TUI nested-list launcher across every workspace
the daemon knows about. It is the fastest path from "I want to work
on something" to a shell or a Claude Code session in the right
directory.
`ws` (run with no arguments in a TTY) — or `ws explorer` explicitly —
opens a Bubble Tea TUI explorer across every workspace the daemon
knows about. It is the fastest path from "I want to work on something"
to a shell or a Claude Code session in the right directory.

```sh
ws # bare invocation; same as `ws agent`
ws agent # explicit
ws # bare invocation; same as `ws explorer`
ws explorer # explicit
ws agent # legacy alias, still works
```

When stdout is not a TTY, `ws` falls through to `cmd.Help()` so
piping / scripts get help instead of a TUI prompt.

## What you see

The agent reads `~/.config/ws/daemon.toml` to find every registered
The explorer reads `~/.config/ws/daemon.toml` to find every registered
workspace, walks each one for projects / groups / worktrees / Claude
sessions, and renders a single nested list:
sessions, and renders a pinned quick-nav header above a scrollable
tree.

```text
*1.myapp 2m 2.api 1h 3.docs 3h 4.experiments 1d 5.utils 2d
6.proj-a 5m 7.proj-b 1h 8.proj-c 4h 9.proj-d 1d

~/dev — workspace
├── personal
│ ├── dotfiles
│ ├── ws (workspace itself)
│ │ ├── main
│ │ ├── feat/foo (mine, ↑2)
│ │ └── feat/auth-refactor (shared with archlinux)
│ └── …
└── work
└── api-gateway
└── …
personal
dotfiles
workspace
main
feat/foo (mine, ↑2)
feat/auth-refactor (shared with archlinux)
work
api-gateway
```

Group / project rows expand and collapse. Worktrees show the same
ownership tags as `ws worktree list` (`main`, `mine`,
### Pinned chip header

Up to nine numbered chips, sorted favorites-first then
recently-touched. The leading `*` marks favorited projects. Each chip
shows `N.name age` — press the digit `1`-`9` to launch the matching
project immediately (claude in its directory). The chip row stays
pinned above the tree while you scroll, so the shortcuts never
disappear off the top.

A project icon is rendered per ecosystem (Go, Rust, Python, Node, TS,
Java, Ruby, C#, Shell, Docker) based on marker files (`go.mod`,
`Cargo.toml`, `pyproject.toml`, etc.) in the project directory.

### Tree

Group / project rows expand and collapse with `tab`. Worktrees show
the same ownership tags as `ws worktree list` (`main`, `mine`,
`shared with <machines>`, `legacy-wt`).

## Keys
Expand All @@ -47,6 +64,7 @@ Navigation:
- `h` / `←` — collapse one level. Smart: from a worktree row it
closes the parent project; from a project row under a group it
closes the group.
- `1`-`9` — launch the matching chip (claude in its directory)
- `q` — quit

Per-row actions:
Expand All @@ -62,6 +80,10 @@ Per-row actions:
- `d` — on a non-main worktree row, prompt for delete (with
registry release; releases this machine from
`[[branches]].machines`).
- `f` — on a project row, toggle favorite. Equivalent to
`ws favorite add` / `ws favorite rm` from the CLI. The new flag is
persisted to `workspace.toml` and synced across machines via the
reconciler.

Search:

Expand All @@ -74,8 +96,8 @@ Help:

## Worktree creation from the TUI

Press `w` on a project row → "Branch name" input → confirm. The TUI
runs the same path as `ws worktree add <project> <branch>`:
Press `w` on a project row → "Branch name" input → confirm. The
explorer runs the same path as `ws worktree add <project> <branch>`:

- Auto-detects an existing remote ref and checks it out.
- Auto-detects an existing local-only ref and attaches.
Expand All @@ -84,15 +106,15 @@ runs the same path as `ws worktree add <project> <branch>`:
without creating a duplicate.
- Otherwise creates a fresh branch from the project's default branch.

After the form closes, the agent invalidates its worktree cache and
re-renders so the new entry appears immediately.
After the form closes, the explorer invalidates its worktree cache
and re-renders so the new entry appears immediately.

## Project edit

Press `e` on a project row → group / category form. Edits update
`workspace.toml` directly (Phase 1 of the next reconciler tick
commits + pushes the change). Useful when reorganizing the layout
without leaving the launcher.
without leaving the explorer.

## Sessions

Expand All @@ -105,10 +127,10 @@ at the session's recorded `cwd`. The session cache is shared with

Three reasons it earns its keep:

- **One key per worktree.** Beats remembering aliases for branches
that come and go.
- **One key per pinned project.** Number hotkeys 1-9 beat
remembering aliases for branches that come and go.
- **Cross-workspace.** If you have several `ws daemon register`'d
directories, they all show up in one list.
- **Claude integration.** The launcher is the primary way to drop
- **Claude integration.** The explorer is the primary way to drop
into a Claude session that already has the right `cwd` and an
optional resume target.
Loading
Loading