Skip to main content

fujimoto

pypi package release GitHub last commit GitHub downloads tests coverage GitHub stars

buymeacoffee

A terminal UI for managing Claude Code sessions across git worktrees and repositories. Spin up isolated worktree sessions or launch Claude directly in an existing repo — all from an interactive TUI with tmux-powered detachable sessions.

Why "Fujimoto"?

Fujimoto from Ponyo

Named after Fujimoto from Hayao Miyazaki's Ponyo — a former human turned fastidious caretaker of the sea. Fujimoto is obsessed with order and control, meticulously tending to the balance of his domain while managing his many daughters and their chaotic tendencies.

Like his namesake, this tool is a caretaker and orchestrator — keeping your worktrees organised, your sessions tracked, and your branches tidy. It manages the lifecycle from creation through to cleanup, fretting over unpushed commits and unmerged branches so you don't have to. And like Fujimoto learning to accept that Ponyo must live her own life, it knows when to let go — spinning off background Claude sessions to handle their own PRs and gracefully cleaning up when the work is done.

He carries himself with dignity, even in defeat. Your worktrees should too.

Prerequisites

  • Python 3.11+
  • git
  • tmux (the tool will offer to install it via brew on macOS, or print the install command for your distro on Linux)
  • uv package manager

Installation

Install the latest release from PyPI (recommended):

uv tool install fujimoto

Upgrade to the latest release:

uv tool upgrade fujimoto

Installing from source

To pick up unreleased changes, install directly from GitHub:

uv tool install git+https://github.com/jongracecox/fujimoto.git

Or install from a local clone:

uv tool install --force --reinstall /path/to/this/repo

Re-run with --force --reinstall after local code changes to pick up updates.

Configuration

All environment variables are optional:

export FUJIMOTO_WORKTREE_ROOT=~/git/worktrees/   # Where worktrees are created
export FUJIMOTO_GIT_ROOT=~/git/                  # Enables project switching
export FUJIMOTO_TERMINAL="alacritty --working-directory {dir}"  # Linux-only: terminal command
export FUJIMOTO_WINDOW_TITLE="{git_project} - {worktree_name}"   # Terminal window title template
export FUJIMOTO_META_KEY="C-a"                                   # In-session fujimoto chord (blank to disable)
export FUJIMOTO_TMUX_PREFIX="C-b"                                # tmux prefix key (default: C-b)
export FUJIMOTO_QUICK_TERMINAL_KEY="C-\`"                        # Global quick-terminal toggle key (blank to disable)

Note: As of this release, the defaults are swapped from earlier versions. The fujimoto chord is now Ctrl-A (was Ctrl-F) and the tmux prefix is now Ctrl-B (was Ctrl-A). To restore the previous layout:

export FUJIMOTO_META_KEY="C-f"
export FUJIMOTO_TMUX_PREFIX="C-a"

If FUJIMOTO_WORKTREE_ROOT is unset, worktrees are created inside the current project at <repo>/.fujimoto/worktrees/ (the .fujimoto/ directory is auto-gitignored). If FUJIMOTO_GIT_ROOT is unset, the project switcher is hidden. Add these to your shell profile (~/.zshrc, ~/.bashrc, etc.) to persist them.

Per-project setup (.fujimoto.yaml)

Worktrees start as clean checkouts, so untracked local files (e.g. .env) and per-worktree setup aren't carried over automatically. Drop an optional .fujimoto.yaml in your main clone to declare what fujimoto should do when it creates a worktree — and, optionally, every time you launch a session in one.

fujimoto reads the file from the main clone (not from the worktree), so it's typically a local, uncommitted file — add it to .git/info/exclude or .gitignore, since it often references local-only files like .env.

Scaffold a fully commented starter file with:

fujimoto --create-config      # writes .fujimoto.yaml to the main clone's root

All three sections are optional:

# Copy files from the main repo into the new worktree.
copy:
  - .env                       # string form -> copied once, at creation
  - path: config/secrets.json
    when: always               # re-copied on every launch (keeps it in sync)
  - "certs/*.pem"              # glob patterns are supported

# Link files instead of copying (hard link by default; falls back to a copy
# with a warning if the worktree is on a different filesystem).
link:
  - path: shared/model.bin
    type: symbolic             # hard (default) | symbolic

# What to do if an init command fails (without continue_on_error):
#   abort (default) returns to the menu; continue launches the session anyway.
on_error: abort

# Run setup commands in the worktree after files are placed.
init:
  - uv sync                    # e.g. create the worktree's virtualenv
  - run: ./scripts/dev-setup.sh {{ worktree_dir }}
    when: always
    continue_on_error: true
    cwd: "{{ source_dir }}"    # optional; defaults to the worktree root

Notes:

  • when controls timing: once (default) runs only the first time the worktree is created; always runs on every connection — creating it, reconnecting to a running session, and relaunching/resuming an existing one.
  • Paths are relative to the repo root; the destination mirrors the same relative path inside the worktree.
  • init commands run (before the session is attached) via sh -x, so each command and its output is shown, stopping at the first failure unless continue_on_error: true. {{ source_dir }} and {{ worktree_dir }} expand to the main repo and worktree paths. On failure you're prompted to acknowledge the error before the screen is handed to the session.
  • fujimoto itself never creates a .venv — that's uv (or your tooling) running inside the worktree. Use an init: [uv sync] entry to set one up.

Window title template

When a Claude session is attached, fujimoto sets the terminal window title to 🧙🏽‍♂️ fujimoto - <rendered template>. The 🧙🏽‍♂️ fujimoto prefix is always present; FUJIMOTO_WINDOW_TITLE controls the suffix. Default: {git_project} - {worktree_name}. Set it to an empty string to suppress the suffix entirely.

Supported placeholders:

Placeholder Value
{git_project} Project (repo) name
{worktree_name} Worktree directory basename
{worktree_path} Absolute path to the working directory
{git_project_dir} Absolute path to the main project directory
{branch} Current git branch (empty outside a repo)
{session_type} worktree, direct, or adhoc
{tmux_name} tmux session name

Unknown placeholders render as empty strings.

While the session-manager screen itself is open (before you attach a session), the title uses the same format without the worktree portion: 🧙🏽‍♂️ fujimoto - <project>. It follows the current project as you switch projects. FUJIMOTO_WINDOW_TITLE does not affect this screen.

In-session shortcuts

When attached to a fujimoto-managed tmux session, press Ctrl-A (configurable via FUJIMOTO_META_KEY) to enter a one-shot "fujimoto mode", then:

Key Action
t Split a terminal pane below claude (30% height). Press again to toggle focus between claude and the terminal — only one extra pane at a time. Run exit in the pane to close it.
T Open a full-height side pane on the right. Same behavior as t: press again to toggle focus.
v Open VS Code at the session's working directory.
w Open a native terminal window at the session's working directory.
f Fork this session — detaches back to the fujimoto TUI and opens the Fork session flow for this worktree, so you get the usual name prompt, base-branch menu and conversation picker.
s Stop this session — closes claude but keeps the session in your list as 🟠, ready to resume. No prompt.
d Detach the tmux session (returns you to the fujimoto TUI).
x End this session. With a split open it kills just that pane (with confirmation), as before. With claude alone in the window it detaches to the fujimoto TUI and asks whether to terminate (default) or merely stop it.
[ Enter copy mode (scrollback / selection).
? Flash the binding cheatsheet in the status bar.

Set FUJIMOTO_META_KEY="" to disable the chord entirely, or to an alternative tmux key spec (e.g. M-f, C-Space) to remap. FUJIMOTO_META_KEY and FUJIMOTO_TMUX_PREFIX must differ — fujimoto will refuse to start a session otherwise.

Quick terminal shortcut (global)

Fujimoto can install a one-press global tmux binding that toggles a 30% bottom terminal pane: press Ctrl-` once to open the pane in the current working directory; press again to cycle focus between the panes. The first time you launch fujimoto you'll be asked whether to enable it — the choice is remembered in ~/.cache/fujimoto/settings.json and a toggle on the home screen lets you flip it later.

This is a tmux root-table binding (bind-key -n), which means it's server-global — installing it affects every tmux session on the machine, not just the ones fujimoto created. Re-applied on every fujimoto session create so it survives a tmux kill-server.

Override the key with FUJIMOTO_QUICK_TERMINAL_KEY (defaults to C-`). Set it to an empty string to disable the feature regardless of the saved preference; the home-screen toggle then shows disabled (env).

Removing the binding. Because it lives on the tmux server, deleting ~/.cache/fujimoto/settings.json does not clear an already-installed binding. To remove it:

  • Toggle it off from the fujimoto home screen (preferred — runs tmux unbind-key -n for you), or
  • Run tmux unbind-key -n 'C-'` (substitute your configured key) for a one-off removal that survives until the next fujimoto session create, or
  • Run tmux kill-server to wipe all tmux state including this binding.

Note: when the saved preference is on, fujimoto re-applies the binding on every session create (so it survives a tmux kill-server). Toggle it off first if you want the removal to stick across launches.

Terminal caveat: many terminals swallow or remap Ctrl-` (iTerm2, Ghostty, Alacritty and others use it for a "quake-mode" toggle, and most terminals don't send a distinguishable code for Ctrl plus a non-letter key by default). If the binding doesn't fire, either remap your terminal to forward Ctrl-` to tmux, or pick a different key via the env var.

Platform support

Fujimoto runs on macOS and Linux.

  • macOS: "Open terminal → New window" uses iTerm2 if installed, otherwise Terminal.app. tmux is auto-installable via brew.
  • Linux: "Open terminal → New window" uses FUJIMOTO_TERMINAL if set, otherwise auto-detects a common terminal emulator (gnome-terminal, konsole, kitty, alacritty, wezterm, foot, xfce4-terminal, tilix, terminator, xterm). FUJIMOTO_TERMINAL accepts a {dir} placeholder for the working directory; if absent, the directory is appended as the final argument. tmux must be installed manually — fujimoto will print the right command for your distro (apt-get / dnf / pacman / zypper / apk).

"Open terminal → This window" instead pauses the TUI and launches your $SHELL as a child process with the working directory set to the session path. Running exit returns you to fujimoto, on the same session's action menu.

Usage

Run from inside any git repository:

fujimoto

Home Screen

🟠 Restore 2 stopped sessions
+ New worktree session
+ New session in <project>
+ Ad hoc session
───── sessions ─────
🟢 20260309-cleanup-ui          (worktree)
🟢 direct-1                     (direct @ main)
🟠 20260307-parser-rewrite      (worktree)
🟠 direct-2                     (direct @ main)
───── inactive worktrees ─────
⚫ 20260308-old-experiment      (worktree)
⚫ 20260309-cleanup-ui-alt 🍴   (worktree)
─────
  Switch project

Worktrees created with Fork session are marked with 🍴.

Sessions are remembered across a restart

A force restart kills every tmux session, and without help every piece of work in flight comes back looking like an abandoned worktree. Fujimoto remembers what you had open instead:

Meaning
🟢 Running right now.
🟠 Stopped — not running, but you never told fujimoto you were done with it. Resume it and carry on.
An inactive worktree: terminated through fujimoto, or never launched from it.

The rule is simply that fujimoto is the only thing that changes a session's status. Terminating one through fujimoto marks it done; anything else — a host restart, tmux kill-session from another terminal, closing the window, exit in the pane — leaves it stopped and resumable. There is no guessing about why a session went away.

Restore appears at the top of the home screen whenever something is stopped. It relaunches every stopped session in the project at once, each resuming its most recent conversation, and attaches to none of them — pick the one you want to sit in from the list.

Stop ends the claude process but keeps the session history: the transcript is untouched and the conversation resumes where it left off. Any task claude was part-way through is interrupted, so stop at a natural break.

Searching sessions

Press / on the home screen to open a search box, then type to filter. Matching is live and case-insensitive, against session names and branch names, and covers the sessions (running and stopped), inactive worktrees and previous claude sessions lists at once. While a filter is active the action rows (+ New …, settings, switch project) are hidden so only matches remain.

Key While searching
Enter Apply the filter and move to the filtered list
/ Move the highlight without leaving the search box
Escape Clear the filter and return to the full list

Three Session Types

Worktree sessions create an isolated git worktree with its own branch. Useful for standalone tasks that become PRs, or investigations where you want to fork off and explore.

Direct sessions launch Claude in an existing repo directory on its current branch. Quick and lightweight — no worktree overhead.

Ad hoc sessions launch Claude in a temporary directory outside any git project. For quick questions, investigations, and one-off tasks that don't need a repository.

Session Actions

Select any session to see contextual options:

Session State Options
Active worktree Connect, Fork session, Resume previous session, Stop, Terminate, Finish
Stopped worktree Resume previous session, Fork session, Launch, Terminate, Finish
Inactive worktree Resume previous session, Fork session, Launch, Finish
Active direct Connect, Fork session, Resume previous session, Stop, Terminate

Stop keeps the session in your list as 🟠; Terminate marks it done and drops it to ⚫. Both close claude — the difference is only whether fujimoto offers it back to you.

All session types also offer Open terminal, Open in VS Code and Rename.

Fork Session

Fork session branches a conversation and the filesystem in one step: it creates a new worktree and starts Claude there with the parent session's full history (claude --resume <id> --fork-session). Use it to try a second approach without losing the context you have built up, or without disturbing the work already in the original worktree.

It asks for a name, then a base branch — defaulting to the parent's branch, so the fork starts from the parent's commits. Choosing the parent's own base branch instead gives you a sibling: same conversation, none of the parent's code changes. If the directory has more than one previous Claude session, you also pick which conversation to fork.

The fork appears in the session list as a normal worktree session marked with 🍴, and the forked Claude session is told it has moved: it knows the original worktree's location, and that it was branched from the parent's committed tip — so any uncommitted changes in the original worktree are not present.

Fork is offered for worktree and direct sessions that have at least one previous Claude session. Requires Claude Code 2.1.223 or newer, which is the first version that can resume a session id from a different directory.

Finish Flow

When you're done with a worktree, the Finish flow checks the branch state and offers:

  • Push & Create PR — pushes the branch and spins up a background Claude session to create the PR
  • Cherry-pick to base — applies your commits back to the original branch, then cleans up
  • Discard & Delete — throws away the work (with confirmation if there are unpushed commits)

For already-merged branches: Delete or Delete + remove remote branch.

Naming Conventions

Thing Pattern Example
Worktree directory {YYYYMMDD}-{slug} 20260309-fix-unit-tests
Git branch worktree/{dir-name} worktree/20260309-fix-unit-tests
tmux session (worktree) {project}/{dir-name} qsic-data/20260309-fix-unit-tests
tmux session (direct) {project}/direct-{N} qsic-data/direct-1

tmux Session Controls

The tmux prefix defaults to Ctrl-B (tmux's standard default) and is configurable via FUJIMOTO_TMUX_PREFIX:

Shortcut Action
Ctrl-B D Detach (leave running)
Ctrl-B [ Scroll/copy mode
Ctrl-B X Kill pane

The same actions are also reachable from the fujimoto chord — e.g. Ctrl-A d, Ctrl-A [, Ctrl-A x — so swapping the prefix off Ctrl-A doesn't cost you these bindings.

These options are set per-session and don't affect your global tmux config.

Keyboard Shortcuts

Key Action
Enter Select
/ Search sessions (home screen)
Escape Back (or quit from home; clears an active search first)
q Quit
Arrow keys Navigate

Development

uv sync
uv run fujimoto        # Run locally
uv run pytest          # Run tests with coverage

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fujimoto-0.8.0.tar.gz (155.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fujimoto-0.8.0-py3-none-any.whl (57.5 kB view details)

Uploaded Python 3

File details

Details for the file fujimoto-0.8.0.tar.gz.

File metadata

  • Download URL: fujimoto-0.8.0.tar.gz
  • Upload date:
  • Size: 155.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for fujimoto-0.8.0.tar.gz
Algorithm Hash digest
SHA256 aa03f3b80d988d56f30a0f4739ed0a00a9d2b6023e03cfa9846fd99066c45464
MD5 0049593d368534ca78e8b1f76626ad2e
BLAKE2b-256 757a7ead3c254bae6eecafcbccd78e130c2c7d6d4ae1791436cbf1b493c0fd03

See more details on using hashes here.

Provenance

The following attestation bundles were made for fujimoto-0.8.0.tar.gz:

Publisher: release.yml on jongracecox/fujimoto

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fujimoto-0.8.0-py3-none-any.whl.

File metadata

  • Download URL: fujimoto-0.8.0-py3-none-any.whl
  • Upload date:
  • Size: 57.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for fujimoto-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8cbaa223e6452edc7e089957387ba9b2495feed60628be9f1d09a73c5ada43f3
MD5 83e7af193fcdaacdc501227959928b68
BLAKE2b-256 8b76cc489106a50a1c8306495851ec8245d8554556ab48c25682fe246080dc30

See more details on using hashes here.

Provenance

The following attestation bundles were made for fujimoto-0.8.0-py3-none-any.whl:

Publisher: release.yml on jongracecox/fujimoto

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.9.0

2 files

This release

0.8.0 This release

2 files

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page