npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, πŸ‘‹, I’m Ryan HefnerΒ  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you πŸ™

Β© 2026 – Pkg Stats / Ryan Hefner

@joaodotwork/plantas-cli

v2.12.0

Published

🌱 Plantas - Session management for parallel development with git worktrees and AI assistants

Readme

🌱 Plantas CLI

npm version license node

Session management for parallel development with git worktrees

Plantas is a powerful CLI tool that enables parallel development workflows using git worktrees. It helps developers manage multiple concurrent work sessions without the overhead of branch switching or stashing.

Features

  • 🌿 Parallel Sessions - Work on multiple features simultaneously using git worktrees
  • 🌳 Session Tracking - Keep track of active and closed sessions with metadata
  • πŸ™ GitHub Integration - Associate sessions with GitHub issues for better traceability
  • πŸ”— Automated Symlinking - Automatically share persistent config files (like .env, .gemini) across sessions
  • 🌱 Zero Conflicts - Each session has its own directory and branch; config files use union merge
  • πŸƒ Easy Cleanup - Automatic worktree management and cleanup
  • πŸ”’ Safety Features - Confirmation prompts and --force flag to prevent accidents
  • πŸ”„ Auto Recovery - Rebuild sessions.json from git history if corrupted
  • πŸ“… ISO 8601 Timestamps - Git-native timestamp format with timezone support
  • 🌊 Seiva Compatible - Optional integration with Seiva context management for AI coordination
  • πŸ” Cross-Session Awareness - Optional realtime channel so parallel Claude Code sessions see each other's activity (--cross-session)

What's New in v2.12.0

Changed

  • Session worktrees no longer symlink the config directory (#59) β€” the change that removes the destructive-git add -A failure class instead of guarding it.
    • Until 2.11.x the whole config dir was symlinked into each worktree. Where that directory is tracked, git saw a symlink standing where a tracked directory belongs, so git add -A staged both halves of the illusion: the symlink as a new blob and a deletion of every tracked file beneath it (sessions.json, the cross-session hooks, the /plantas:* commands). No git mechanism prevents that β€” neither exclude rules nor skip-worktree/assume-unchanged apply to tracked paths β€” so 2.11.0 could only add a pre-commit guard, which git commit --no-verify bypasses.
    • The config dir is now left exactly as git checked it out, and only gitignored files are linked (context.md, settings.local.json, cross-session.log). A symlink at an ignored path is invisible to git, so there is nothing to stage and nothing to guard. The link step refuses to link any path git does not ignore β€” the invariant is enforced, not assumed.
    • sessions.json is deliberately not linked. It is tracked, so linking it would recreate the same bug for one file. plantas resolves the main checkout's copy by absolute path instead. The session scripts are resolved from the main checkout too β€” they are gitignored, so a worktree never had its own copy.
    • git add -A && git commit --no-verify in a worktree is now safe, which the guard could never make it.
    • Worktrees created by ≀2.11.x are unaffected and keep working: they still carry the directory symlink, plantas merge still performs the swap for them via the recorded intent (#63), and the pre-commit guard stays installed as their protection. plantas doctor reports the guard as informational rather than a warning, since new worktrees do not need it.

Fixed

  • plantas status and plantas rebuild read the sessions registry from the main checkout, not the current directory β€” they resolved it against process.cwd(), which only worked in a worktree because the config dir happened to be symlinked.
  • plantas sync no longer tries to stash context.md: it is gitignored (#60), so it can never be the dirty tracked file that blocks a pull. sessions.json is.

Added

  • Claude Code's persistent memory is shared across worktrees (#48): memories live at ~/.claude/projects/<key>/memory, where <key> is the project's absolute path with / replaced by -. Every worktree has a different path, so every session got its own empty store β€” a memory written in one session was invisible to every other worktree and to the main checkout, and cross-worktree conventions had to be duplicated into CLAUDE.md just to reach them. plantas start now symlinks the worktree's store to the main checkout's, so MEMORY.md and every memory file are shared. plantas end removes the link, which lives outside the worktree and would otherwise dangle. Opt out with "sessions": { "shareMemory": false }.
    • An existing real memory directory at the worktree's key is never replaced β€” it is reported and left alone. Memories are not recoverable, so this path only ever creates or replaces a symlink.
  • plantas end deletes the session branch when it is fully merged (#42): closing a session removed the worktree but left the branch, so a weekly batch of parallel sessions silted the parent repo up with feat/* branches already on the integration branch. The branch is now deleted once it is proven merged, and kept otherwise β€” unmerged work is never destroyed by a cleanup path. --keep-branch opts out entirely. A branch checked out in another worktree is left alone and reported.
    • Merged-ness is measured against the integration branch, resolved the same way plantas merge resolves its target (#62): integrationBranch from config, else origin/HEAD, else main/master. So a repo where main is production and dev is integration gets the right answer.
    • Deletion uses git branch -D, gated by an explicit merge-base --is-ancestor check. This is deliberate: git branch -d measures merged-ness against HEAD, not against the branch actually being integrated into, so in a dev-integration repo it refuses to delete branches that are fully merged into dev. The ancestry check is the real gate and is stricter than -d's.
  • v2.11.1 β€” 2026-08-24
  • v2.11.0 β€” 2026-08-24
  • v2.10.1 β€” 2026-07-06
  • v2.10.0 β€” 2026-06-30
  • v2.9.0 β€” 2026-06-30
  • v2.8.1 β€” 2026-06-13

Full history in CHANGELOG.md.

Installation

Via npm (recommended)

npm install -g @joaodotwork/plantas-cli

Manual installation

git clone https://github.com/joaodotwork/plantas-cli
cd plantas-cli
npm install
npm link

Quick Start

  1. Initialize Plantas in your project:
cd your-project
plantas init
  1. Start your first session:
plantas start A "Admin UI improvements" feat/admin "components/Admin*"

This creates:

  • A new git worktree at ../your-project-session-A/
  • A session entry in .plantas/sessions.json
  • A new branch feat/admin (or checks out existing)
  1. Navigate to the session:
cd ../your-project-session-A/
# Open your editor and start working
  1. List active sessions:
plantas list
  1. End the session when done:
plantas end A

This automatically removes the worktree and archives the session.

Documentation

πŸ“š Complete Guides:

  • CHANGELOG.md - Version history and release notes
  • MIGRATION.md - Upgrade guide and troubleshooting
  • ARCHITECTURE.md - Complete system architecture and design
  • Seiva - Context management system for AI coordination (optional integration)

Quick Links:

Commands

plantas init

Initialize Plantas in the current git repository.

Options:

  • --seiva - Use .claude/ directory and install Seiva context management
  • --cross-session - Install Claude Code hooks + slash commands for realtime cross-session awareness (requires --seiva)
  • --force - Overwrite existing configuration

Example:

plantas init
plantas init --seiva                  # Install with Seiva context integration
plantas init --seiva --cross-session  # ...plus realtime cross-session awareness

--cross-session is fully opt-in and additive β€” it only installs hooks/commands under .claude/. Re-running with --force is safe and idempotent (it merges into settings.local.json without duplicating entries). See Cross-Session Awareness below.

plantas start <id> <focus> [branch] [areas] [--issue <number>] [--from <ref>]

Start a new parallel session with automatic worktree creation.

Arguments:

  • id - Short identifier (e.g., A, B, feature-name)
  • focus - Description of what you're working on
  • branch - Git branch name (optional, defaults to current)
  • areas - Comma-separated file patterns (optional)

Options:

  • -i, --issue <number> - Associate with GitHub issue number
  • --from <ref> - Branch point for a new branch (--base is an accepted alias)
  • --no-commit - Don't auto-commit the sessions.json registration

Auto-commit: start commits the new sessions.json entry in the main repo as a single-file commit (it never sweeps in your other staged work). This keeps the tracked copy from drifting behind the live, shared, symlinked file. Pass --no-commit to skip.

Examples:

# Basic usage - creates new branch or uses current
plantas start A "Bug fixes"

# Associate with GitHub issue
plantas start auth "Implement user authentication" --issue 123

# Attach to existing branch (automatically detected)
plantas start B "Continue feature work" feat/existing-feature

# Create new branch if it doesn't exist
plantas start C "New feature" feat/new-feature

# Branch from an integration branch instead of whatever HEAD happens to be
plantas start menu-print "Print-ready PDFs" feat/menu-print --issue 121 --from dev

# With file areas
plantas start D "API refactor" feat/api "src/api/*,tests/api/*"

Note: Plantas automatically detects whether the branch exists:

  • βœ… If branch exists: checks it out in the worktree
  • βœ… If branch doesn't exist: creates it for you

Choosing the branch point (--from)

Without --from, a new branch is cut from whatever HEAD the main checkout happens to be on β€” fine while main is the only long-lived branch, wrong the moment a repo grows an integration branch (dev, staging, …). --from makes the branch point an explicit input instead of ambient state:

plantas start api "New endpoint" feat/api --from dev          # β†’ origin/dev if it exists
plantas start api "New endpoint" feat/api --from refs/heads/dev  # force the local branch
plantas start api "New endpoint" feat/api --from v2.3.0       # a tag, or a SHA
  • Remote-first: a bare name resolves to <remote>/<name> when that remote-tracking ref exists (dev β†’ origin/dev), after a best-effort git fetch of just that branch, so you don't silently branch from a stale local copy. Pass refs/heads/<name> to force the local branch, or set PLANTAS_NO_FETCH=1 to skip the fetch.
  • Always printed: start reports the branch point whether or not you passed the flag (βœ“ Branched from: origin/dev (6ad9948 …)), so a wrong base is visible at the moment it's made rather than at merge time.
  • Recorded: the resolved ref is stored as baseRef on the session in sessions.json and shown by plantas list. plantas merge uses it as a fallback merge target.
  • An existing branch can't be re-cut β€” --from is then recorded as the session's base ref and a warning explains it wasn't applied.

The config-dir commit guard

plantas start symlinks the config dir (.claude/.plantas) into the worktree so every session shares one sessions.json. In a repo where that directory is tracked, git sees the symlink standing where a tracked directory should be, and a plain git add -A stages both halves: the symlink as a new file and a deletion of every real file under it β€” sessions.json, the cross-session hooks, the /plantas:* commands.

No git-side mechanism prevents that staging (.git/info/exclude doesn't apply to tracked paths, and update-index --skip-worktree is overridden by add -A and breaks git merge in the worktree), so start installs a pre-commit guard in the repo's shared hooks directory. It unstages those paths, says so, and lets the rest of the commit through:

πŸ›‘οΈ  plantas: unstaged the symlinked config dir β€” it cannot be committed from a worktree:
     .claude

The hook is shared by every worktree, so one plantas start installs it retroactively for sessions that already exist. plantas doctor reports whether it's in place. A pre-existing non-plantas pre-commit hook is never overwritten β€” start warns and leaves it alone.

plantas end <id>

End a session and cleanup its worktree.

Options:

  • -f, --force - Skip confirmation prompts
  • -k, --kill-orphans - Stop processes still running inside the worktree (dev servers) instead of only reporting them
  • --purge - Also delete leftovers the sweep cannot prove disposable (listed first)
  • --no-commit - Don't auto-commit the sessions.json close

Auto-commit: like start, end commits the sessions.json change (the session moving to closed) in the main repo as a single-file commit, so the tracked copy stays in sync. Pass --no-commit to skip.

Examples:

plantas end A                        # Prompts for confirmation
plantas end A --force                # Skips confirmation (for scripts)
plantas end A --force --kill-orphans # Also stops dev servers rooted in the worktree

Safety Features:

  • ⚠️ Prompts before deleting worktree
  • ⚠️ Warns if uncommitted changes exist
  • ⚠️ Shows what will be deleted
  • βœ… Use --force to skip prompts for automation

Live processes: before anything is removed, end looks for processes whose working directory is inside the worktree (via lsof) and prints their PIDs, command lines and listening ports. Left alone they become orphans: still bound to :4321, serving a checkout that no longer exists, and still writing into the deleted path. end never kills them without consent β€” pass --kill-orphans (or answer the prompt) to stop them first.

Leftover sweep: git worktree remove will not delete a directory it cannot empty, so it can leave an empty-directory husk that looks exactly like a live worktree. end verifies the path is really gone and, if not, sweeps only what it can prove is disposable:

| Removed | Preserved and reported | |---|---| | empty directories (rmdir) | untracked files that aren't build output | | git-ignored paths under a build/cache directory (node_modules, .netlify, .vite, dist, …) | modified tracked files | | tracked files byte-identical to the session branch (verified by hash) | ignored-but-precious files (.env, logs, notes) | | symlinks β€” the link only, never its target | anything at all when git's ignore data is unavailable | | the dangling .git worktree pointer | |

Anything preserved is printed with its path, and the session still closes cleanly β€” a leftover is a warning, not a failure. Use --purge to delete the reported leftovers too.

plantas list

List all active and recently closed sessions.

Alias: plantas ls

Options:

  • -a, --active - Show only active sessions
  • -c, --closed - Show only closed sessions
  • --all - Show both active and closed sessions (default)
  • -r, --recent <n> - Show active + last N closed sessions
  • -t, --table - Compact table output (one line per session)
  • --json - Machine-readable JSON output

Examples:

plantas list
plantas list --active
plantas list --recent 5
plantas list --table      # compact table view
plantas list --json       # parseable JSON

plantas status

Show current Plantas status and configuration.

Example:

plantas status

plantas doctor

Check installation, dependencies, and config-dir integrity.

Options:

  • --fix - Repair what can be repaired β€” currently, a session worktree whose config dir should be a symlink but is a real directory (the flattened directory is moved into the worktree's git dir rather than deleted)

Example:

plantas doctor
plantas doctor --fix

It inspects the current worktree plus every registered active session worktree. A run that emitted warnings says so in the summary instead of claiming all checks passed.

plantas sync

Pull latest changes into the main worktree, auto-stashing coordination files that would otherwise block the pull.

Options:

  • -r, --remote <remote> - Remote name (default: origin)
  • -b, --branch <branch> - Branch to pull (default: current branch)
  • -f, --force - Run even from a worktree

Example:

# After merging a session PR on GitHub, pull into main cleanly:
plantas sync

# Pull from a specific remote/branch:
plantas sync --remote upstream --branch main

Why this exists: After merging a session PR, coordination files (.claude/sessions.json) often have uncommitted local changes from hooks. git pull aborts before the union merge strategy kicks in. plantas sync stashes those files first, pulls with --no-rebase, then pops the stash.

plantas merge [branch]

Merge a branch into the current worktree, handling symlinked config directories that cause git merge to fail.

Arguments:

  • branch - Branch to merge. Omitted, it is resolved (never guessed) β€” see below.

Examples:

# In a session worktree, merge your integration branch:
plantas merge

# Merge a specific branch:
plantas merge origin/dev
plantas merge feat/other-feature

Merge target resolution. Merging the wrong branch is a valid git operation, so a wrong default cannot fail loudly. With no argument, plantas merge resolves the target in this order and refuses rather than guessing:

  1. the explicit branch argument;
  2. the current branch's configured upstream (@{upstream}), if it has one;
  3. integrationBranch from .plantas.config.json β€” defaults to the repository's default branch, so single-branch repos keep working with zero configuration;
  4. the ref the worktree was created from (baseRef in sessions.json, recorded by plantas start).

If none resolve, it errors and names every candidate it tried instead of falling back to a hard-coded ref. The chosen ref and where it came from are always printed:

🎯 Merge target: origin/dev (integrationBranch (plantas config))

In a repo where main is production and dev is the integration branch, set it once:

{ "integrationBranch": "origin/dev" }

Why this exists: Session worktrees have a symlinked .claude/ (or .plantas/) directory. git merge fails because git can't stash paths beyond a symlink. plantas merge temporarily removes the symlink, restores real tracked files, runs the merge, then re-creates the symlink.

Interruption safety. The window in which the symlink is removed is wrapped in try/finally plus SIGINT/SIGTERM/SIGHUP handlers, and the intended state is recorded in the worktree's git dir before the symlink goes away. A Ctrl-C mid-merge restores the symlink on the way out; a hard kill leaves a record that plantas merge and plantas doctor --fix use to repair it.

plantas context

Generate .claude/context.md from project state. Derives tech stack, key files, work streams, and recent activity automatically.

Options:

  • --human - Output human-readable markdown (default: compressed AI format)
  • --refresh - Also regenerate context in all active worktrees
  • --quiet - Suppress output (for hooks)

Examples:

plantas context              # Compressed AI format
plantas context --human      # Human-readable markdown
plantas context --refresh    # Update all worktrees too

What it derives:

| Data | Source | |------|--------| | Tech stack | package.json, requirements.txt, go.mod, Cargo.toml, Gemfile | | Key files | Files modified 2+ times in recent commits | | Work streams | Conventional commit messages (feat/fix/refactor/docs) | | Active patterns | File change patterns (tests, CI/CD, migrations, API) | | Sessions | .claude/sessions.json | | Recent activity | Last 5 commits |

plantas rebuild

Rebuild sessions.json from git worktrees and branch history. Useful for recovery from file corruption or migration scenarios.

Options:

  • --dry-run - Show what would be rebuilt without writing
  • --force - Overwrite existing sessions.json with active sessions
  • --active-only - Only rebuild active sessions from worktrees

Examples:

# Basic rebuild - scans worktrees and branches
plantas rebuild

# Preview what would be rebuilt
plantas rebuild --dry-run

# Force overwrite existing file
plantas rebuild --force

# Only active sessions (faster)
plantas rebuild --active-only

What Gets Reconstructed:

  • βœ… Session IDs from worktree paths
  • βœ… Branch names
  • βœ… Worktree paths (for active sessions)
  • βœ… Creation timestamps from git branch metadata
  • βœ… Focus descriptions from commit messages
  • ℹ️ Areas default to "general"

Use Cases:

  • πŸ”§ Recover from corrupted sessions.json
  • πŸ”§ Accidentally deleted sessions.json
  • πŸ”§ Migrate from manual git worktree workflow
  • πŸ”§ Verify sessions.json integrity
  • πŸ”§ Onboard existing project to Plantas

Configuration

Plantas can be configured via .plantas.config.json:

{
  "configDir": ".claude",
  "sessionsFile": ".claude/sessions.json",
  "worktreePrefix": "session-",
  "timestampFormat": "HH:mm",
  "defaultAreas": "general",
  "sessions": {
    "autoSymlink": [".env", ".gemini", ".gemini-clipboard"]
  },
  "hooks": {
    "onStart": null,
    "onEnd": null
  }
}

Configuration Options

| Field | Description | Default | |-------|-------------|---------| | configDir | Directory for Plantas/Seiva files | .plantas | | sessionsFile | Path to the sessions registry | configDir/sessions.json | | integrationBranch | Branch work accumulates on; used by plantas merge with no argument | null β†’ the repo's default branch | | worktreePrefix | Prefix for worktree directories | session- | | sessions.autoSymlink | Files to automatically symlink into worktrees | [] | | sessions.shareMemory | Share Claude Code's persistent memory (~/.claude/projects/<key>/memory) between the main checkout and every session worktree | true | | hooks.onStart | Shell command to run after starting a session | null | | hooks.onEnd | Shell command to run after ending a session | null |

Keep this file committed

.plantas.config.json is what records which directory this repo uses β€” .claude/ for plantas init --seiva, .plantas/ otherwise. Every config-dir-aware command reads it.

If it is missing or malformed, plantas no longer falls silently back to the built-in default (which would point a --seiva repo at a .plantas/ that does not exist). Instead it detects the config dir from whichever candidate directory contains sessions.json, and says so:

⚠️  No .plantas.config.json found, but .claude/sessions.json exists β€” using .claude/.
     Run "plantas init" to write the config file so this is not guessed.

Detection is keyed on the session registry rather than on the directory merely existing, so a repo that has a .claude/ for Claude Code and has never run plantas keeps resolving to the default. If both candidates hold a registry, plantas reports the ambiguity and uses the default rather than guessing.

sessionsFile always follows configDir unless you set it explicitly.

Environment Variables

You can also override configuration via environment variables:

  • PLANTAS_CONFIG_DIR - Config directory (default: .plantas)
  • PLANTAS_SESSIONS_FILE - Sessions file path
  • PLANTAS_WORKTREE_PREFIX - Worktree directory prefix

Hooks

Plantas supports custom hooks for automation:

onEnd Hook

Runs automatically after ending a session. Perfect for syncing your main branch after merging PRs:

{
  "hooks": {
    "onEnd": "git checkout main && git pull && echo 'βœ… Main branch synced'"
  }
}

Common use cases:

  • Sync main after PR merge: "git checkout main && git pull"
  • Clean up feature branches: "git checkout main && git pull && git branch -d $BRANCH"
  • Run cleanup scripts: "./scripts/cleanup.sh"

Example workflow:

# Work on feature
plantas start A "Add login" feat/login

# Make changes, commit, push, merge PR on GitHub

# End session - hook automatically syncs main
plantas end A
# β†’ Removes worktree
# β†’ Switches to main
# β†’ Pulls latest changes
# β†’ βœ… Your local main is now up-to-date!

Use Cases

Parallel Feature Development

Work on multiple features simultaneously without branch switching:

# Start feature A
plantas start checkout "Checkout flow" feat/checkout "components/Checkout*"

# Start feature B (in a new terminal)
plantas start admin "Admin dashboard" feat/admin "components/Admin*"

Both sessions run in parallel with isolated worktrees.

Hotfix During Feature Work

Need to fix a critical bug while working on a large feature?

# Already working on feature
plantas start hotfix "Fix payment bug" hotfix/payment "src/api/payment.ts"

# Fix the bug, commit, merge
# Then end the session
plantas end hotfix

Code Review While Building

Review PRs without disrupting your current work:

plantas start review "Review PR #42" pr-42-review
# Review, test, comment
plantas end review

Resume Work on Existing Branches

Attach sessions to branches that already exist (no need to recreate them):

# List your branches
git branch
# feat/authentication
# feat/checkout
# main

# Attach session to existing branch
plantas start auth "Continue auth work" feat/authentication

# The branch already has commits - no problem!
# Plantas creates a worktree and you continue where you left off

This is perfect for:

  • Returning to paused work
  • Collaborating on shared branches
  • Working on long-running features across multiple sessions

Experimentation

Try different approaches in parallel:

plantas start modal "Modal UI approach" experiment/modal
plantas start inline "Inline editing approach" experiment/inline

# Compare both, keep the best one

Seiva Integration (Optional)

Plantas can optionally integrate with Seiva - a context management system that helps AI assistants understand your project state.

When used with Seiva:

  • Auto-generated context via plantas context β€” derives everything from repo state
  • Token-efficient β€” compressed format uses ~500 tokens vs ~2k for markdown
  • Zero merge conflicts β€” context.md is gitignored, generated locally per worktree
  • Post-commit hook β€” context regenerates automatically after each commit
  • Multi-ecosystem β€” analyzes Node.js, Python, Go, Rust, and Ruby projects

To install with Seiva:

plantas init --seiva

This:

  • Uses .claude/ directory for compatibility
  • Generates initial context.md from project analysis
  • Installs post-commit hook for automatic regeneration
  • Creates AI_GUIDE.md for multi-agent workflows

How Context Generation Works (v2.6.0+)

Context is fully derived β€” no manual maintenance:

# Auto-runs after every commit via post-commit hook
# Or run manually:
plantas context              # compressed AI format
plantas context --human      # human-readable markdown
plantas context --refresh    # update all active worktrees

Each worktree generates its own context.md independently. The repo is the source of truth; context.md is just a cache for AI consumption.

What's committed:

  • βœ… sessions.json - Session tracking (JSON-aware plantas-sessions merge driver)
  • βœ… AI_GUIDE.md - Workflow documentation for AI agents
  • βœ… .plantas.config.json - Team configuration
  • ❌ context.md - Auto-generated, gitignored
  • ❌ settings.local.json - Local Claude Code permissions
  • ❌ *.sh - Generated scripts

Without Seiva, Plantas works standalone β€” you get session management and worktrees, but no automatic AI context sharing.

Cross-Session Awareness (Optional)

Seiva's committed sessions.json is the git-layer coordination channel β€” it surfaces work across commits, branches, and days. (context.md is gitignored: it is regenerated locally per worktree, so it informs your agent rather than travelling through git.) --cross-session adds a complementary conversation-layer channel: a realtime view of what every parallel Claude Code session is currently prompting and touching, surfaced to the others within the hour.

plantas init --seiva --cross-session

This installs (all under .claude/):

  • Two hooks β€” UserPromptSubmit appends each prompt to a shared cross-session.log and injects a digest of the other sessions' last-hour activity into the prompt context; Stop records which files the turn touched.
  • Three slash commands that read across the whole worktree fleet:
    • /plantas:tail [N] β€” last N cross-session log entries (default 20)
    • /plantas:status [recent_N] β€” plantas sessions mapped to their Claude session IDs
    • /plantas:search <term> β€” grep transcripts across all worktrees + plantas-tracked closed sessions
  • CROSS_SESSION.md β€” a design doc covering the log format, components, and the $CLAUDE_PROJECT_DIR anchoring rationale.

Hook commands are anchored via $CLAUDE_PROJECT_DIR (not relative paths), so they survive any cd inside a turn. The wiring in settings.local.json is merged additively β€” existing permissions and hooks are preserved β€” and re-running with --force is idempotent.

Requires --seiva (Claude Code reads hooks and slash commands from .claude/). Passing --cross-session alone prints a warning and skips the install. The whole feature rides on plantas start symlinking .claude/ across worktrees, so every session writes to one shared log at <repo>/.claude/cross-session.log (gitignored).

| Layer | Mechanism | Surfaced when | |---|---|---| | git-layer (Seiva) | sessions.json committed under a JSON-aware merge driver | Across commits, branches, days | | conversation-layer (--cross-session) | cross-session.log JSONL + prompt-context injection | Within the hour, between live sessions |

Requirements

  • Git (required)
  • Node.js 14+ (required)
  • jq or python3 (for JSON processing)
  • Bash (for shell scripts)

Check your installation:

plantas doctor

Upgrading

npm install -g @joaodotwork/plantas-cli@latest
cd your-project
plantas init --seiva --force

See MIGRATION.md for detailed upgrade instructions from v1.x.

How It Works

Plantas uses git worktrees to create isolated working directories:

your-project/                    (main repo)
β”œβ”€β”€ .plantas/
β”‚   β”œβ”€β”€ sessions.json            (session registry)
β”‚   β”œβ”€β”€ start-session.sh
β”‚   β”œβ”€β”€ end-session.sh
β”‚   └── list-sessions.sh
└── src/

../your-project-session-A/       (worktree for session A)
β”œβ”€β”€ .plantas -> ../your-project/.plantas/  (symlink)
└── src/

../your-project-session-B/       (worktree for session B)
β”œβ”€β”€ .plantas -> ../your-project/.plantas/  (symlink)
└── src/

Benefits:

  • βœ… No branch switching overhead
  • βœ… Run multiple dev servers simultaneously
  • βœ… Isolated dependencies (node_modules, venv)
  • βœ… Clean separation of concerns
  • βœ… Easy cleanup

Troubleshooting

"Your local changes would be overwritten by merge" on pull

This happens when coordination files (.claude/sessions.json) have uncommitted changes from hooks. Use plantas sync instead of git pull:

plantas sync

"is beyond a symbolic link" on merge in worktree

This happens because session worktrees have a symlinked .claude/ directory and git can't stash paths beyond symlinks. Use plantas merge instead of git merge:

plantas merge              # merges your resolved integration branch
plantas merge feat/branch  # merge any branch

A session worktree's .claude/ is a real directory instead of a symlink

The worktree has silently stopped sharing coordination state with the main checkout (usually an interrupted merge). Don't fix it by hand:

plantas doctor        # reports every degraded session worktree
plantas doctor --fix  # restores the symlink, keeping a backup of what it replaced

"Not a git repository" error

Make sure you're in a git repository:

git init

"Neither jq nor python3 found"

Install jq (recommended):

# macOS
brew install jq

# Ubuntu/Debian
sudo apt-get install jq

# Or use python3 as fallback

Worktree already exists

If a worktree path already exists:

# Remove it manually
rm -rf ../your-project-session-A/

# Or use git worktree
git worktree remove ../your-project-session-A/

Uncommitted changes warning

Before ending a session, commit or stash your changes:

cd ../your-project-session-A/
git add .
git commit -m "Save work"
# Then end the session

Contributing

Contributions welcome! See the main repository for guidelines.

License

MIT License - see LICENSE file for details.

Links

Etymology

Plantas (Spanish/Portuguese) means:

  1. 🌱 Plants - organisms that grow from roots
  2. πŸ“‹ Plans - organized schemes or methods
  3. πŸ‘£ Soles (of feet) - foundation for navigation

All three meanings apply to parallel session management!


Made with 🌱 by joaodotwork