Skip to main content

Per-project terminal profiles for iTerm2 (macOS) and Windows Terminal (Windows), safely via per-file JSON.

Project description

termprofiles

PyPI version

PyPI Python Platforms Terminal License

Per-project terminal profiles that feel native on macOS (iTerm2) and Windows (Windows Terminal), without hand-editing JSON.

Keywords: iTerm2 dynamic profiles, Windows Terminal fragments, per-project ZDOTDIR, developer automation CLI.

TermProfiles creates one JSON file per project so you can add or remove profiles safely. On macOS, each project gets its own ZDOTDIR (history + .zshrc), while Windows users receive tidy Windows Terminal fragments. Everything lives inside your home directory.

Contents

Overview

  • Per-project profiles: Generates one dynamic profile (macOS) or fragment (Windows) per directory.
  • Safe JSON handling: Files are written atomically with UTF-8 encoding to avoid corruption.
  • No tmux required: Launch directly into the project directory with your preferred shell.
  • Easy cleanup: termprofiles remove deletes the generated JSON (and optional macOS ZDOTDIR).
  • Discoverable: termprofiles list shows exactly what was created.

Supported Platforms & Requirements

macOS

  • macOS 11 or newer recommended.
  • iTerm2 with Dynamic Profiles enabled.
  • Shell: /bin/zsh is used, but you can customize via the generated .zshrc.

Windows

  • Windows 10 19041+ or Windows 11 with Windows Terminal 1.16 or newer.
  • PowerShell installed (default). Optional: Git Bash, Command Prompt, or WSL.

Installation

TermProfiles is published on PyPI; choose one of the installation methods below.

Using pipx (recommended)

pipx installs packages in isolated virtual environments and adds entry points to your shell.

# macOS (optional helper if Homebrew is available)
brew install pipx
pipx ensurepath
exec $SHELL

# macOS or Windows
pipx install termprofiles
# Upgrade later
pipx upgrade termprofiles

Verify the installation:

termprofiles --help

Using pip

If you prefer a virtual environment or user-site install:

python -m venv .venv  # optional virtual environment
source .venv/bin/activate  # Windows: .venv\Scripts\activate
python -m pip install --upgrade pip
python -m pip install termprofiles

From source

git clone https://github.com/yaioyaio/termprofiles.git
cd termprofiles
pipx install .  # or: python -m pip install .

Quick Start

macOS (iTerm2)

  1. Run termprofiles add /path/to/project.
  2. Reopen iTerm2 (or Profiles → Other Actions → Reload All Profiles).
  3. Launch the new profile named proj-<slug>.
  4. Enjoy an isolated .zshrc and history backed by ~/.zsh-profiles/<slug>/.

Example:

termprofiles add ~/dev/sample-app

Outputs something like Added: proj-sample-app and creates dp-sample-app.json in iTerm2's DynamicProfiles directory.

Windows (Windows Terminal)

  1. Run PowerShell as the user (no admin needed).
  2. Execute termprofiles add "C:\\src\\sample-app".
  3. Close and reopen Windows Terminal (or run wt.exe again).
  4. Select the new profile proj-sample-app from the dropdown.

By default the profile uses PowerShell and opens in your project directory.

Command Reference

termprofiles add <dir> [<dir> ...]

Create profiles for one or more project directories.

macOS options:

  • --parent-guid GUID — inherit UI from an existing iTerm2 profile.
  • --parent-name NAME — locate a profile by name (case-insensitive) and use its GUID.

Windows options:

  • --color-scheme NAME — apply an existing Windows Terminal color scheme.
  • --shell TYPEpowershell (default), cmd, git-bash, wsl, wsl:<alias>.
  • --wsl-distro NAME — WSL distribution to launch (default Ubuntu).
  • --wsl-zdotdir PATH — export ZDOTDIR before starting zsh in WSL.

termprofiles remove <target> [<target> ...]

Delete generated profiles. Each target can be the original directory or its slug.

  • macOS: add --keep-zdotdir to preserve ~/.zsh-profiles/<slug>.
  • Windows: only the fragment JSON is removed.

termprofiles list

Show profiles discovered via the generated JSON files. Helpful for auditing or scripting.

termprofiles doctor

Diagnose release prerequisites. The command checks that the current Git branch tracks an upstream, confirms whether the origin remote uses SSH, and verifies PyPI upload requirements such as twine, environment variables, .pypirc, and recent build artifacts.

termprofiles parents (macOS only)

Enumerate iTerm2 profiles detected in ~/Library/Preferences/com.googlecode.iterm2.plist with their GUIDs.

termprofiles setopt (macOS only)

Interactively toggle recommended setopt flags (e.g., NO_SHARE_HISTORY, SHARE_HISTORY, EXTENDED_HISTORY, INC_APPEND_HISTORY) for the current project's .zshrc, or run non-interactively via --enable SHARE_HISTORY --disable NO_SHARE_HISTORY. Changes are written atomically and active iTerm sessions using the same profile automatically source the updated file.

termprofiles prompt on|off|toggle (macOS only)

Enable, disable, or toggle the built-in prompt ([%F{cyan}<slug>%f] user@host path %#). When enabled, it overrides whatever prompt your inherited parent profile provides. The command rewrites the project .zshrc and reloads the profile in running tabs.

termprofiles new (macOS only)

Open a new iTerm window (or add --tab to open a tab) that uses the current project's profile, useful after tweaking settings.

How Profiles Are Structured

  • Slug generation: The directory name is lowercased, spaces become -, and non-alphanumeric characters are stripped (e.g., /Users/Alex/My Appmy-app).
  • File naming:
    • macOS: ~/Library/Application Support/iTerm2/DynamicProfiles/dp-<slug>.json
    • Windows: %LOCALAPPDATA%\Microsoft\Windows Terminal\Fragments\TermProfiles\proj-<slug>.json
  • Idempotent: If a JSON file already exists, the command prints Skip (exists) and leaves your configuration untouched.

macOS Details

  • Each project gets ~/.zsh-profiles/<slug>/ containing .zshrc and .zsh_history.
  • A slug maps 1:1 to a session scope: ZDOTDIR=~/.zsh-profiles/<slug> is forced so every terminal using the same slug shares history and config, while other slugs stay fully isolated.
  • .zshrc sources ~/.zshrc.common if present, so you can share aliases across projects.
  • History is unlimited up to 50k entries (HISTSIZE + SAVEHIST). By default setopt NO_SHARE_HISTORY keeps per-window commands from syncing in real time, preventing cross-project bleed. If you prefer live history sync, edit the generated .zshrc and switch to setopt SHARE_HISTORY.
  • Launch command: /usr/bin/env ZDOTDIR="<project_zdotdir>" /bin/zsh -l.
  • --isolate-cli codex,my-cli drops wrappers in ~/.zsh-profiles/<slug>/bin/ so those CLIs run with project-scoped HOME/XDG directories.
  • If you set a parent profile, the generated dynamic profile inherits colors, fonts, and other UI settings from it.
  • Use termprofiles setopt (or termprofiles setopt --enable SHARE_HISTORY --disable NO_SHARE_HISTORY) to switch between history behaviors and toggle helpers like HIST_IGNORE_SPACE; results propagate to every open tab instantly.
  • termprofiles prompt on|off|toggle flips the prebuilt prompt snippet on demand; enabling it gives each profile a cyan [<slug>] prefix, while disabling it defers to the parent profile's prompt.

codex session sharing

  • Running termprofiles add <dir> --isolate-cli codex creates wrappers so that every terminal on the same slug uses ~/.zsh-profiles/<slug>/cli-homes/codex for Codex CLI data.
  • Codex writes history when the process exits (or an explicit save happens), so simultaneous Codex sessions do not see each other's commands instantly. Exit one instance or trigger codex history to refresh the shared file.
  • Updating Codex simply replaces the binary on PATH; because the wrapper calls the real executable (shutil.which("codex")), all profiles pick up the new version automatically. Re-run termprofiles add <dir> --isolate-cli codex only if the executable lives at a new path.

Windows Details

  • Fragment JSON conforms to the Windows Terminal fragment spec and is auto-discovered on launch.
  • --shell wsl runs wsl.exe -d <distro>; combine with --wsl-zdotdir to export ZDOTDIR and spawn zsh via bash -lc.
  • --shell git-bash points to the default Git for Windows install path ("C:\\Program Files\\Git\\bin\\bash.exe" -li). Adjust manually if you installed Git elsewhere.
  • startingDirectory is set to the project path; Windows Terminal respects it for local shells and translates for WSL.

Configuration & Environment Variables

Every CLI flag has an environment variable equivalent (useful for shell rc files or CI scripts):

Purpose Flag Environment Variable Default
iTerm2 parent GUID --parent-guid TP_PARENT_GUID None
iTerm2 parent name --parent-name TP_PARENT_NAME None
Windows color scheme --color-scheme TP_COLOR_SCHEME None
Windows shell --shell TP_SHELL powershell
WSL distro --wsl-distro TP_WSL_DISTRO Ubuntu
WSL ZDOTDIR export --wsl-zdotdir TP_WSL_ZDOTDIR None
CLI session isolation --isolate-cli TP_ISOLATE_CLI None

Command-line arguments take precedence over environment variables. Set them in your shell profile to create customized defaults; always pick names that exist in your setup:

# macOS example — choose from `termprofiles parents`
export TP_PARENT_NAME="DEFAULT"
# Windows example — choose from Windows Terminal `schemes`
export TP_COLOR_SCHEME="One Half Dark"
  • Discover parent profile names on macOS with termprofiles parents; it prints the names and GUIDs detected in iTerm2's preferences.
  • On Windows, open Windows Terminal settings (wt settings) or inspect settings.json to view the schemes array and copy the color scheme name you want to export via TP_COLOR_SCHEME.

Example Workflows

  • Automate profile creation: find ~/Code -maxdepth 1 -type d -not -path '*/.*' -print0 | xargs -0 termprofiles add.
  • Shared look & feel: on macOS set TP_PARENT_NAME to your favorite theme; on Windows set TP_COLOR_SCHEME to keep colors consistent.
  • Isolate CLI state: termprofiles add ~/dev/sample-app --isolate-cli codex keeps Codex CLI data under ~/.zsh-profiles/sample-app/cli-homes/codex instead of the global ~/.codex.
  • Verify Codex sharing: termprofiles add . --isolate-cli codex → open two iTerm2 windows using the same proj-<slug> profile → run a Codex command in one → confirm it appears via codex history --latest in the other after the first session exits or saves.
  • Tune zsh quickly: termprofiles setopt to toggle history options, then termprofiles prompt on (or off) to adjust the shared prompt; the tool re-sources every open session automatically.
  • Spin up new shells: termprofiles new --tab opens another tab with the same profile right away, ideal after changing configuration.
  • WSL development: termprofiles add "/mnt/c/dev/app" --shell wsl --wsl-distro Ubuntu-22.04 --wsl-zdotdir "/home/user/.config/zsh/app" launches straight into WSL zsh with project-specific config.
  • Clean removal: termprofiles remove ~/dev/sample-app --keep-zdotdir keeps historical context while removing the dynamic profile.

Troubleshooting & FAQ

  • git push fails with “no upstream branch”. Run git push --set-upstream origin <branch> once (for example git push --set-upstream origin develop) so Git knows which remote branch to track.
  • Git keeps asking for credentials. Switch the remote to SSH (git remote set-url origin git@github.com:yaioyaio/termprofiles.git) after registering your SSH key with GitHub, or store a Personal Access Token using git config --global credential.helper.
  • PyPI upload rejects credentials. Ensure a valid token is available via ~/.pypirc or environment variables (TWINE_USERNAME=__token__, TWINE_PASSWORD=pypi-...) before running python -m twine upload dist/*.
  • Build succeeds but shows license warnings. Update project.license in pyproject.toml to an SPDX string (for example "MIT") to silence the new setuptools deprecation warning.
  • Want an automated check? Run termprofiles doctor to validate Git/PyPI prerequisites in one command.
  • Profiles are missing. Restart iTerm2/Windows Terminal so it reloads dynamic profiles/fragments.
  • iTerm2 cannot read the JSON. Ensure Dynamic Profiles are enabled (Preferences → Profiles → Other Actions → Import JSON Profiles).
  • Windows Terminal ignores the profile. Confirm fragments are enabled (Settings → Open JSON file should list TermProfiles). Check %LOCALAPPDATA%\Microsoft\Windows Terminal\Fragments\TermProfiles for the created JSON.
  • Parent profile not found (macOS). Use termprofiles parents to list available names and GUIDs. Remember that matching is case-insensitive and trims whitespace.
  • Custom shells. For Windows Git Bash installs in a different location, copy the generated fragment, edit commandline, or pass a custom path by editing the JSON after creation.
  • Unrecognized directory. termprofiles add skips paths that are not directories and prints Skip (not a dir).

Uninstalling

  • Remove generated JSON: run termprofiles remove <targets> (and optionally delete ~/.zsh-profiles/<slug>).
  • Delete the package:
    • pipx: pipx uninstall termprofiles
    • pip/virtualenv: python -m pip uninstall termprofiles
  • Clean up leftover directories if desired: rm -rf ~/Library/Application Support/iTerm2/DynamicProfiles/dp-*.json (macOS) or delete the fragments folder on Windows.

Contributing

  • Issues and pull requests welcome at GitHub.
  • Local setup:
    git clone https://github.com/yaioyaio/termprofiles.git
    cd termprofiles
    python -m venv .venv
    source .venv/bin/activate
    python -m pip install --upgrade pip
    python -m pip install -e .
    termprofiles --help
    
  • Run formatting and packaging checks as needed (python -m build).
  • Follow conventional Python best practices and keep documentation updated.

License

MIT © yaioyaio

Project details


Download files

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

Source Distribution

termprofiles-0.1.3.tar.gz (25.4 kB view details)

Uploaded Source

Built Distribution

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

termprofiles-0.1.3-py3-none-any.whl (20.3 kB view details)

Uploaded Python 3

File details

Details for the file termprofiles-0.1.3.tar.gz.

File metadata

  • Download URL: termprofiles-0.1.3.tar.gz
  • Upload date:
  • Size: 25.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for termprofiles-0.1.3.tar.gz
Algorithm Hash digest
SHA256 46d156428eb70d1ef8f7c1107867142a870b7be33e0ec35b910d10cca9ca72a2
MD5 e1af4c0cf20c1c3f62ecd916edad3224
BLAKE2b-256 f78e02febbd42fefb21b71d67585f9b21cb72ca73437aef2e4ffadddd990dd6a

See more details on using hashes here.

File details

Details for the file termprofiles-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: termprofiles-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 20.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for termprofiles-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 127656fd9126b73c8f898746744bb223f30173d3e4a9fd6c7016f18ca7706aa9
MD5 1059058af845fc114a22807919cc8cfd
BLAKE2b-256 c41c990098012c61503d6fb6a7018b6aff656de25086301ba58734d9fd96bb15

See more details on using hashes here.

Supported by

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