dw

command module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 20, 2026 License: MIT Imports: 11 Imported by: 0

README

dw — discussion workspace picker

release license

Spin up a dated workspace for every topic you explore with Claude — then fuzzy-jump back to any of them.

dw gives each topic its own <category>/<YYYY-MM-DD>-<topic>/ folder with a frontmatter README. No naming ceremony: type a topic, pick a category, and start working. Later, fuzzy-find it and cd straight in.

$ dw
> k8s pod                                         research/2026-06-14-k8s-pod-oom
  db outage                                       incident/2026-06-01-db-outage
  + create: 2026-06-17-k8s-pod                    (pick a category)
    status: active  tags: [gpu, linux]  created: 2026-06-14

Features

  • Dated auto-layout — workspaces live at <root>/<category>/<YYYY-MM-DD>-<topic-slug>/, created for you.
  • Create on demand, no create command — type a topic; if nothing matches, pick a category and dw makes it. Categories are created on the fly too.
  • Category chosen after the topic — write what you're thinking about first, file it second.
  • Fuzzy jump — fuzzy-match across category/name and titles, newest first, fzf-style.
  • Resume instantly — your last workspace is pinned to the top; dw - jumps to it with no UI.
  • Frontmatter-aware — shows status / tags / created from each README under the selection.
  • Scriptable primitives — the TUI is sugar over plain commands: dw new creates, dw list (--json) streams, so you can compose your own flow (dw list --json | fzf) instead of the picker.
  • Unicode-safe slugs — Japanese and other scripts survive slugification (機械学習 調査機械学習-調査).
  • Zero-config — defaults to ~/dw; one env var to relocate.

Install

go install github.com/edge2992/dw@latest

Don't use Go? Grab a prebuilt binary for your OS/arch from the Releases page (linux / macOS / windows × amd64 / arm64, with checksums.txt). Check the installed version with dw version.

Shell integration

dw is a child process, so it cannot change your shell's working directory itself. Instead it prints the chosen path to stdout, and a thin wrapper function does the cd. The path-producing subcommands (the picker, dw -, dw new) are captured and cd'd into; the others (list, root, …) pass straight through so their output shows up as usual.

Let dw generate the wrapper for you — add this to your ~/.zshrc (or ~/.bashrc):

eval "$(dw init zsh)"   # use `dw init bash` for bash

dw init prints the function below; eval'ing it keeps the integration in sync with the binary, so there's nothing to hand-copy:

dw() {
  case "${1:-}" in
    ''|-|new)
      local dir
      dir="$(command dw "$@")" && [ -n "$dir" ] && cd "$dir" ;;
    *)
      command dw "$@" ;;
  esac
}

Want to land in the workspace and launch Claude in one go? Add a second wrapper:

function dwc() {
  case "${1:-}" in
    ''|-|new)
      local dir
      dir="$(command dw "$@")" && [ -n "$dir" ] && cd "$dir" && claude ;;
    *)
      command dw "$@" ;;
  esac
}

Quickstart

dw                              # open the picker: fuzzy-find, or type a new topic to create one
dw -                           # jump straight back to your last workspace
dw new "my topic" -c research  # create a workspace non-interactively and cd in
dw list                        # print every workspace as category/name
dw root                        # print the workspace root

Prefer to compose your own picker? The interactive TUI is just sugar over the primitives — wire dw list to your favourite fuzzy finder instead:

cd "$(dw list --json | jq -r '.[].path' | fzf)"

In the picker:

  • Type to filter, enter to cd into the highlighted workspace.
  • No match? A + create: <date>-<slug> row appears → enterpick a category → it's created and you cd in.
  • At the category step, type an unknown name to spin up a new category; esc goes back to browse so you can retype the topic.
  • ↑/↓ (or ctrl+p / ctrl+n) to move; esc / ctrl+c to abort.

Commands

Command Description
dw Open the interactive picker (fuzzy list + create-on-demand).
dw - Jump to the last workspace; prints its path.
dw new <topic> -c <cat> Create a workspace non-interactively; prints its path.
dw list List workspaces as category/name, one per line.
dw list --json List workspaces as a JSON array (includes absolute path).
dw root Print the resolved workspace root.
dw init <zsh|bash> Print the shell wrapper to eval (see Shell integration).
dw version Print the version.
dw help / -h Show usage.

Every path-producing command writes to stdout; diagnostics go to stderr. That's what makes the dw() wrapper and pipelines like dw list | fzf work.

Layout

$DW_ROOT/<category>/<YYYY-MM-DD>-<topic-slug>/
  README.md   # frontmatter-indexed entry point

$DW_ROOT defaults to ~/dw. Categories are arbitrary folders; the defaults offered when empty are research, incident, discussion, scratch.

Configuration

  • DW_ROOT — workspace root. Defaults to ~/dw.

  • Templates — picked per category, first match wins:

    1. ~/.config/discussion/templates/<category>.md — per-category
    2. ~/.config/discussion/templates/default.md — shared default
    3. ~/.config/discussion/template.md — legacy single template (back-compat)
    4. built-in default (works with nothing configured)

    All substitute {{title}}, {{category}}, {{date}}. Drop a ~/.config/discussion/templates/research.md to give just the research category its own scaffold.

  • Last-workspace cache — recorded under os.UserCacheDir() (~/Library/Caches/dw/last on macOS, ~/.cache/dw/last on Linux). Drives both the top-of-list pin and dw -.

Migration

Breaking change. The default root moved from ~/Discussion to ~/dw, and the environment variable was renamed DISCUSSION_ROOTDW_ROOT. The old variable is no longer read.

If you have an existing ~/Discussion tree, either point dw at it or move it:

export DW_ROOT=~/Discussion   # keep your data where it is
# — or —
mv ~/Discussion ~/dw          # adopt the new default

Architecture

  • internal/workspace — scanning / slugification / creation / templates / last-path persistence (pure logic, tested).
  • internal/tui — the single bubbletea fuzzy list (jump + create + category select + pin).
  • main.go — subcommand dispatch (run()); wires dw -, new, list, root, init, version, help, and the picker. dw new and the picker share the same workspace.Create core.

Development

make fmt    # gofumpt + goimports (golangci-lint fmt)
make lint   # golangci-lint run
make test   # go test -race ./...
make        # all of the above
  • Lint/Format: golangci-lint v2 (config .golangci.yml, standard set + misspell/revive; formatters gofumpt/goimports).
  • Hooks: pre-commit framework (.pre-commit-config.yaml). A global pre-commit hook delegates here after gitleaks, so pre-commit install is not required. Setup: uv tool install pre-commit, brew install golangci-lint.
  • CI: GitHub Actions (.github/workflows/ci.yml) runs build / test -race / golangci-lint.

Release

Versioning is automated. Release Please parses Conventional Commits to decide the next version: every push to main updates a release PR (with CHANGELOG), and merging it creates the semver tag and GitHub Release. GoReleaser then attaches prebuilt binaries for each OS/arch (.github/workflows/release.yml). feat bumps the minor, fix the patch.

License

MIT © edge2992

Documentation

Overview

Command dw is an interactive picker for Claude discussion/research workspaces.

It scans $DW_ROOT (default ~/dw) for projects laid out as <category>/<YYYY-MM-DD>-<topic>/, shows a fuzzy list, and prints the selected or newly-created project path to stdout. A thin shell wrapper cd's into it.

Subcommands: `dw -` jumps to the last workspace, `dw new` creates one non-interactively, `dw list` lists workspaces, `dw root` prints the root, `dw init` prints the shell wrapper, `dw version` prints the version, and `dw help` shows usage.

Directories

Path Synopsis
internal
tui
Package tui implements the interactive dw picker: one fuzzy list that both jumps to an existing project and creates a new one when nothing matches.
Package tui implements the interactive dw picker: one fuzzy list that both jumps to an existing project and creates a new one when nothing matches.
workspace
Package workspace handles discovery and creation of discussion projects laid out as <root>/<category>/<YYYY-MM-DD>-<topic-slug>/.
Package workspace handles discovery and creation of discussion projects laid out as <root>/<category>/<YYYY-MM-DD>-<topic-slug>/.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL