projm
Project organizer and navigator for developers. Scans a directory, classifies projects by stack, groups related ones by name prefix, and lets you fuzzy-jump to any project and open it in your editor — all from the terminal.
Install
1. Quick Install Scripts (Recommended)
To install projm via pre-compiled binaries, you can run the interactive installation script.
For macOS and Linux (Shell):
|
For Windows (PowerShell):
irm https://github.com/ZAAFHachemrachid/projm/releases/latest/download/projm-installer.ps1 | iex
2. Pre-compiled Binaries & cargo-binstall
You can download the binaries directly from GitHub Releases.
Alternatively, install via cargo-binstall:
3. From Source
If you have the Rust toolchain installed, you can build and install projm directly from crates.io:
4. Homebrew (macOS/Linux)
5. Arch Linux (AUR)
[!NOTE] Available starting with the next release (v0.7.5+).
Setup
Add the shell functions to your zsh config:
This automatically installs completions, sets up zoxide, and adds two shell functions:
pg— fuzzy-jump to a project and open your editorpn— fuzzy-pick a project and run its dev command directly
[!TIP] Avoid Command Collisions: If
pgconflicts with another command on your system (e.g. PostgreSQL orpgcli), you can customize the generated shell function name using the--alias(or-a) flag:
Usage
# Scan a directory and move projects into ~/projects/<category>/
# Preview without moving anything
# Clone a repo straight into the right category folder under your base dir
# Clone a specific branch, rename it, and open it in your editor
# Fuzzy-pick a project, choose an editor, jump there
# Override the default base directory (~/projects)
# List detected editors on this machine
# Generate shell completions
# Install shell integration + zoxide + completions
# Run the current project's dev command directly
# Fuzzy-pick a project and run its dev command
# Run dev command for current directory
# Run dev command for a specific path
# Verify active development tools and environment health
# Git health sweep across all organized projects (branch, dirty, ahead/behind)
# Show only repos that are dirty or out of sync with upstream
# Machine-readable output for scripting
# Manage classification rules: list/add/remove/test/edit/export/import/pin/assign
Desktop App
Prefer a GUI? projm also ships as a cross-platform desktop app built with Tauri. It wraps the same organizing engine in a native window:
- Project browser — browse your organized base directory by category, with live git status.
- Organize / scan — point it at a folder and preview or apply the same classification the CLI performs.
- Blueprints — create and run project blueprints from the UI instead of the interactive terminal prompt.
- Rules editor — edit your
rules.tomlcustom classification rules with validation. - Environment check — the
projm checkdiagnostics, rendered as a live dashboard. - Built-in terminal — an embedded terminal so you can stay in one window.
Downloads
Grab the latest installer for your platform from GitHub Releases. CLI binaries and desktop bundles ship together in each v* release.
| Platform | Installer |
|---|---|
| macOS | .dmg (Apple Silicon + Intel) |
| Windows | .msi installer + NSIS setup .exe |
| Linux | .AppImage / .deb / .rpm |
[!NOTE] The desktop app auto-checks for updates on launch — the built-in updater ships with the next desktop release.
How it works
Project classification
Projects are classified by inspecting their contents:
| Marker | Category |
|---|---|
doc-lab.md present |
labs |
memory.x / openocd.cfg / embedded Cargo target |
embedded |
Monorepo markers (turbo.json, pnpm-workspace.yaml, lerna.json, nx.json, or "workspaces" in package.json) |
apps |
src-tauri/ or both Cargo.toml + package.json |
apps |
pubspec.yaml (Flutter/Dart) |
apps or ui |
build.gradle / build.gradle.kts (Kotlin/Android) |
apps |
*.xcodeproj / Package.swift (Swift/iOS) |
apps |
go.mod (Go) |
services or tools |
pom.xml / build.gradle (Java) |
services |
uv.lock / pyproject.toml + ML markers |
ml |
package.json — reads deps to detect frontend vs backend |
ui / services |
Cargo.toml only |
services or tools |
| Everything else | labs |
package.json projects are classified by reading actual dependencies — React/Vite/Svelte → ui, Hono/Express/Prisma → services, both → apps.
Adding support for new languages
Support for new language stacks is added directly in src/classify.rs. To add another stack:
- Identify the unique stack markers (e.g.
mix.exsfor Elixir,composer.jsonfor PHP). - Add classification check in the sequential
classify()flow. If the stack can map to multiple categories, define helper functions for extra validation (e.g.has_android_manifest()or checking for subdirectories likeandroid/andios/). - Verify with tests by adding unit test cases to
tests/classify_tests.rsmatching your stack.
Package manager detection
projm reads the lockfile present in the project root to identify the package manager — no guessing from package.json scripts:
| Lockfile | Package manager |
|---|---|
pnpm-lock.yaml |
pnpm |
bun.lockb / bun.lock |
bun |
yarn.lock |
yarn |
package-lock.json |
npm |
uv.lock |
uv (Python) |
Pipfile.lock |
pipenv |
poetry.lock |
poetry |
Cargo.lock |
cargo |
go.sum |
go modules |
pubspec.lock |
pub (Dart/Flutter) |
Gemfile.lock |
bundler (Ruby) |
composer.lock |
composer (PHP) |
Name-based grouping
Projects that share a prefix and a known suffix are grouped under a common folder:
~/projects/
└── apps/
└── drivetrack/ ← group folder
├── drivetrack/ ← standalone root (no suffix)
├── drivetrack-api/
├── drivetrack-web/
└── drivetrack-desk/
Recognised suffixes: api, web, mob, desk, mono, backend, frontend, server, client, cli, bot, admin, dashboard, landing, docs, and more.
Labs marker
Drop a doc-lab.md file in any project to force it into labs/ regardless of its stack:
pg — fuzzy project jump
pg calls projm g internally (or your custom alias if configured via projm init --alias <name>). All interactive UI writes to stderr, only the final shell command goes to stdout for eval. Uses z (zoxide) if available, falls back to cd.
apps drivetrack-api main ✓
apps drivetrack-web feat/auth *
ml trashnet main ✓
embedded rocket-telemetry-fw dev *
ui pioneers-website main ✓
projm clone
Clone a repository and drop it straight into the correct category folder — no more cloning into a random directory and organizing later.
projm clone first clones into a temporary staging directory inside your base directory (so the final move is a fast rename), then classifies the project with the same rules as organize and moves it into the right category folder under your base directory. It prints the destination path when done.
--name <name>— override the project name. By default the name is derived from the URL (trailing.git, query strings, and fragments are stripped, and the last path segment is used).--branch <branch>— passed through togit clone --branchto clone a specific branch.--open— after organizing, open the project in your editor. It detects installed editors, reuses the last editor you chose for that project (stored in~/.config/projm/prefs.json, falling back to the first installed editor), spawns it in the background, and remembers the choice.
Requires git on your $PATH. If a project with the target name already exists anywhere under your base directory, the clone is aborted so nothing is overwritten.
Editor detection
projm scans $PATH at runtime — only editors that are actually installed appear in the picker. The list of editors it knows about:
| Binary | Name |
|---|---|
nvim |
Neovim |
zed |
Zed |
zeditor |
Zed |
code |
VS Code |
kiro |
Kiro |
hx |
Helix |
idea |
IntelliJ |
cursor |
Cursor |
emacs |
Emacs |
vim |
Vim |
Selection behaviour:
- 0 found → error with install hint
- 1 found → opens directly, no picker shown
- 2+ found → interactive picker, last choice pre-selected
Last choice is remembered per-project in ~/.config/projm/prefs.json. Run projm editors to see what's detected on your machine.
Environment diagnostics
projm check scans your active $PATH and runs diagnostics to check the health and version of your compilers, runtimes, package managers, and development utilities:
- Rust:
cargo,rustc,rustup - Python:
python/python3,pip,uv,pipx - Node/JS:
node,npm,pnpm,yarn,bun,deno - Go:
go - Systems/VCS:
git,docker,docker-compose,curl,make
It performs smart cross-dependency validation (e.g. warning you if a package manager like npm is present but its runtime node is missing). Run projm check to see your environment status.
Directory structure
~/projects/
├── apps/ # Full-stack, Tauri, Flutter, Android, iOS, monorepos
├── services/ # Backend APIs — Rust, Hono, Go, Java, Express
├── ui/ # Frontend-only — React, Svelte, Vue
├── embedded/ # ESP32, LoRa, no_std Rust
├── ml/ # ML pipelines, notebooks
├── tools/ # CLI tools, scripts
└── labs/ # Experiments, anything with doc-lab.md
Roadmap
v0.2 — Auto-detect editors ✓ shipped
Editor detection, single-editor fast path, and per-project last-choice memory are all live. See Editor detection above.
v0.3 — Shell completions + zoxide setup ✓ shipped
Shell completions
Generated via Clap for zsh, bash, fish, and PowerShell:
Completions cover all subcommands and flags. projm init installs platform-specific completions automatically.
Auto-install & setup zoxide
When projm init runs, it checks zoxide and handles install automatically if missing:
[1/3] checking zoxide...
[2/3] writing completions...
[3/3] updating ~/.zshrc...
done. restart your shell or source ~/.zshrc
Package manager detection order (system-native preferred over cargo):
| OS | Tried in order |
|---|---|
| Arch Linux | pacman → yay → paru → cargo |
| Ubuntu/Debian | apt → cargo |
| macOS | brew → cargo |
| Windows | winget → choco → scoop → cargo |
| Fallback | cargo install zoxide |
On Linux/macOS, init updates ~/.zshrc with zsh integration and eval "$(zoxide init zsh)" (idempotent). On Windows, init updates ~/Documents/PowerShell/Microsoft.PowerShell_profile.ps1 with PowerShell integration and zoxide init powershell (idempotent).
v0.3.2 — Interactive Project Blueprints ✓ shipped
Save complex project creation commands with placeholders (e.g., cargo new {name}) and execute them interactively. After execution, projm prompts you to automatically run organize to move the new project into the correct category directory inside your Base Directory.
# Add a new blueprint interactively
# List all saved blueprints
# Run a blueprint to scaffold a new project
v0.4 — projm check (Environment Diagnostics) ✓ shipped
projm check (Environment Diagnostics)A diagnostic subcommand that scans the local machine's $PATH to identify and verify the health, location, and versions of active compilers, runtimes, package managers, and development utilities:
- Rust Toolchain:
cargo,rustc,rustup - Python Toolchain:
python/python3,pip,uv,pipx - Node/JS Toolchain:
node,npm,pnpm,yarn,bun,deno - Go Toolchain:
go - Systems & Utilities:
git,docker,docker-compose,curl,make
It performs smart cross-dependency validation (e.g. warning you if a package manager like npm is present but its runtime node is missing).
# Run environment diagnostics
v0.5 — Custom classification rules ✓ shipped
User-defined rules in ~/.config/projm/rules.toml, evaluated before built-in logic:
# Rules are evaluated top to bottom, first match wins
[[]]
= "pioneers-website" # exact name match
= "ui"
[[]]
= "rocket.toml" # file presence (replaces the doc-lab.md hard override)
= "services"
[[]]
= "adrar" # substring match
= "labs"
[[]]
= "fw" # override built-in suffix behaviour
= "embedded"
[[]]
= "burn" # Cargo.toml dep → Rust ML
= "ml"
[[]]
= "tensorflow" # package.json or requirements.txt dep
= "ml"
Evaluation order:
1. .projm.toml pin ← per-project marker inside the repo (highest priority)
2. rules.toml ← your custom rules
3. built-in logic ← everything else
Tip:
doc-lab.mdis just a built-in rule. You can replicate its behaviour for any marker viamarker = "doc-lab.md"with the highest position in your rules file.
Rules engine v2
Rules support much richer matching — all fields optional, AND-combined, first match wins:
[[]]
= "API microservices, except legacy ones"
= true # false keeps the rule but skips it
= 10 # lower runs first (optional)
= "*-api" # glob on the directory name
= "^svc-[0-9]+$" # or a regex
= "clients" # immediate parent directory name
= "**/experiments/**" # glob on the full path
= ["Dockerfile", "fly.toml"] # ALL must exist
= ["justfile", "Makefile"] # at least ONE must exist
= ["react", "vite"] # ALL deps must be present
= { = "react", = ">=18" } # semver check
= "rust" # detected stack (rust, js, tauri, go, …)
= [ { = "legacy" } ] # NOT — rule fails if any matches
= [ { = "*-api" }, { = "rocket.toml" } ] # OR groups
= "services"
Managing rules from the CLI
Per-project pin (.projm.toml)
Drop a .projm.toml in a project to pin its category — it wins over every rule
and travels with the repo. It shares the file with the [run] config:
= "ml" # pins classification
= "drivetrack" # optional: force a group folder
= false # optional: hide from listings
[]
= "cargo run" # existing run override still works
v0.6 — Universal language support ✓ shipped
Extend classification to cover every major stack:
| Marker | Language / Stack | Category |
|---|---|---|
pubspec.yaml + android/ or ios/ |
Flutter | apps |
pubspec.yaml only |
Dart package | ui |
build.gradle + AndroidManifest.xml |
Kotlin / Android | apps |
build.gradle without Android markers |
Spring Boot / JVM backend | services |
pom.xml |
Java / Maven | services |
*.xcodeproj / Package.swift |
Swift / iOS / macOS | apps |
go.mod |
Go service or CLI | services / tools |
Gemfile + config/routes.rb |
Ruby on Rails | services |
composer.json + artisan |
Laravel / PHP | services |
mix.exs |
Elixir / Phoenix | services |
*.csproj / *.sln |
C# / .NET | services / apps |
CMakeLists.txt + .ld / openocd |
C / C++ embedded | embedded |
CMakeLists.txt only |
C / C++ native app or lib | tools |
All new stacks respect the same grouping rules — myapp-android and myapp-ios will group under myapp/.
v0.7 — projm run + pn ✓ shipped
projm run + pnAuto-detect the project stack, predict the dev command, and run it directly — no need to leave the terminal.
Two entry points:
Instead of opening an editor (like pg), pn runs the project's dev command directly — streaming stdout/stderr to the terminal, with Ctrl+C support.
Dev command resolution:
| Detected Stack | Command |
|---|---|
| Rust (Cargo.toml) | cargo run |
| Bun | bun run dev |
| pnpm | pnpm dev |
| Yarn | yarn dev |
| npm | npm run dev |
| Tauri | <pkg-manager> tauri dev |
| Flutter | flutter run |
| Go | go run . |
| Python + uv.lock | uv run python main.py |
| Python (pip) | python main.py / python3 main.py |
| Ruby on Rails | bin/rails server |
| Elixir/Phoenix | mix run --no-halt |
| Kotlin/Java Gradle | ./gradlew run |
| Java Maven | mvn compile exec:java |
| Laravel/PHP | php artisan serve |
| C/C++ (CMake) | cmake --build build |
| C# / .NET | dotnet run |
Package.json scripts are read to find dev → start → fallback.
.projm.toml override:
Place a config file in the project root to override auto-detection:
[]
= "cargo run --features embedded" # full override
[]
= "cargo run"
= "cargo build --release"
= "cargo test"
[] # label monorepo packages
= "packages/api"
= "apps/web"
Monorepo support:
Detects Turborepo, pnpm workspaces, Nx, and Bun workspaces. Shows an interactive picker:
Select target (turbo):
> ▶ Run All
◻ apps/web
◻ apps/api
◻ packages/shared
◻ packages/ui
Auto-resolves workspace packages from pnpm-workspace.yaml, bun workspaces, or package.json workspaces. Individual packages can be labelled via .projm.toml.
Shell function:
Generated automatically by projm init alongside pg. No eval needed — pn spawns the dev command directly:
Summary
| Version | Feature | Status |
|---|---|---|
| v0.2 | Auto-detect installed editors + remember last choice | ✓ shipped |
| v0.3 | Shell completions (zsh/bash/fish/powershell) + auto-install zoxide | ✓ shipped |
| v0.3.2 | Interactive blueprints (projm blueprint) + auto-organization |
✓ shipped |
| v0.4 | projm check Environment diagnostics and doctor mode |
✓ shipped |
| v0.5 | rules.toml custom classification |
✓ shipped |
| v0.6 | Universal language support (Flutter, Kotlin, Go, Swift, Java, …) | ✓ shipped |
| v0.7 | projm run + pn — detect and launch the project's dev command |
✓ shipped |
License
MIT