projm 0.3.2

Project organizer and fuzzy navigator for developers — classify, group, and jump to projects from the terminal
Documentation

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.

version

Install

cargo install projm

Setup

Add the shell function to your zsh config:

projm init >> ~/.config/zsh/.zshrc
source ~/.config/zsh/.zshrc

This adds pg — a shell function that jumps you into a project and opens your editor.

Usage

# Scan a directory and move projects into ~/projects/<category>/
projm organize ~/Downloads/dump

# Preview without moving anything
projm organize ~/Downloads/dump --dry-run

# Fuzzy-pick a project, choose an editor, jump there
pg

# Override the default base directory (~/projects)
projm set-base ~/code

# List detected editors on this machine
projm editors

# Generate shell completions
projm completions zsh
projm completions powershell

# Install shell integration + zoxide + completions
projm init

# Verify active development tools and environment health
projm check

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
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.

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:

touch my-experiment/doc-lab.md
projm organize ~/projects

pg — fuzzy project jump

pg calls projm g internally. 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  ✓

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
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:

projm completions zsh >> ~/.config/zsh/completions/_projm
projm completions powershell > ~/.config/powershell/completions/projm.ps1

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 pacmanyayparucargo
Ubuntu/Debian aptcargo
macOS brewcargo
Windows wingetchocoscoopcargo
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.4 — projm new + package manager detection

Scaffold a new project directly into the right place:

projm new drivetrack-mobile
# detects prefix "drivetrack" already in apps/drivetrack/
# → creates ~/projects/apps/drivetrack/drivetrack-mobile/
# → asks: stack? (rust / hono / react / tauri / flutter / uv)
# → runs the right init command with the right package manager
# → touches doc-lab.md if you pass --lab

Stack → init command mapping:

Stack Command
Rust cargo init
Hono/TS pnpm create hono (or detected pm)
React pnpm create vite
Tauri pnpm create tauri-app
Flutter flutter create
Python/uv uv init
Go go mod init

Package manager detection

The right install command is determined from the lockfile in the project root — 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)
poetry.lock poetry
Pipfile.lock pipenv
requirements.txt pip
Cargo.lock cargo
go.sum go modules
pubspec.lock pub (Dart/Flutter)
build.gradle / build.gradle.kts gradle
pom.xml maven
Gemfile.lock bundler (Ruby)
composer.lock composer (PHP)

Also shown in projm g as project metadata.


v0.5 — Custom classification rules

User-defined rules in ~/.config/projm/rules.toml, evaluated before built-in logic:

# Rules are evaluated top to bottom, first match wins

[[rule]]
name     = "pioneers-website"  # exact name match
category = "ui"

[[rule]]
marker   = "rocket.toml"       # file presence (replaces the doc-lab.md hard override)
category = "services"

[[rule]]
name_contains = "adrar"        # substring match
category      = "labs"

[[rule]]
suffix   = "fw"                # override built-in suffix behaviour
category = "embedded"

[[rule]]
has_dep  = "burn"              # Cargo.toml dep → Rust ML
category = "ml"

[[rule]]
has_dep  = "tensorflow"        # package.json or requirements.txt dep
category = "ml"

Evaluation order:

1. rules.toml       ← your custom rules (highest priority)
2. built-in logic   ← everything else

Tip: doc-lab.md is just a built-in rule. You can replicate its behaviour for any marker via marker = "doc-lab.md" with the highest position in your rules file.


v0.6 — Universal language support

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

Detect and execute the project's dev command without leaving projm:

projm run
# reads lockfile → infers package manager
# reads package.json scripts / Cargo.toml / pyproject.toml
# → picks the right dev command and runs it

Dev command resolution per stack:

Stack Command
Rust binary cargo run
Hono/TS bun dev / pnpm dev
React/Vite bun dev / pnpm dev
Tauri pnpm tauri dev
Flutter flutter run
Python/uv uv run / python main.py
Go go run .

Pairs naturally with pg — jump to a project and optionally start it in one step:

pg --run

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.4 projm new scaffold + package manager detection from lockfile planned
v0.5 rules.toml custom classification planned
v0.6 Universal language support (Flutter, Kotlin, Go, Swift, Java, …) planned
v0.7 projm run — detect and launch the project's dev command planned

License

MIT