@joaodotwork/plantas-cli
v2.12.0
Published
π± Plantas - Session management for parallel development with git worktrees and AI assistants
Maintainers
Readme
π± Plantas CLI
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 -Afailure 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 -Astaged 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 norskip-worktree/assume-unchangedapply to tracked paths β so 2.11.0 could only add apre-commitguard, whichgit commit --no-verifybypasses. - 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.jsonis 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-verifyin 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 mergestill performs the swap for them via the recorded intent (#63), and thepre-commitguard stays installed as their protection.plantas doctorreports the guard as informational rather than a warning, since new worktrees do not need 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
Fixed
plantas statusandplantas rebuildread the sessions registry from the main checkout, not the current directory β they resolved it againstprocess.cwd(), which only worked in a worktree because the config dir happened to be symlinked.plantas syncno longer tries to stashcontext.md: it is gitignored (#60), so it can never be the dirty tracked file that blocks a pull.sessions.jsonis.
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 intoCLAUDE.mdjust to reach them.plantas startnow symlinks the worktree's store to the main checkout's, soMEMORY.mdand every memory file are shared.plantas endremoves 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 enddeletes 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 withfeat/*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-branchopts 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 mergeresolves its target (#62):integrationBranchfrom config, elseorigin/HEAD, elsemain/master. So a repo wheremainis production anddevis integration gets the right answer. - Deletion uses
git branch -D, gated by an explicitmerge-base --is-ancestorcheck. This is deliberate:git branch -dmeasures 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 intodev. The ancestry check is the real gate and is stricter than-d's.
- Merged-ness is measured against the integration branch, resolved the same way
- 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-cliManual installation
git clone https://github.com/joaodotwork/plantas-cli
cd plantas-cli
npm install
npm linkQuick Start
- Initialize Plantas in your project:
cd your-project
plantas init- 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)
- Navigate to the session:
cd ../your-project-session-A/
# Open your editor and start working- List active sessions:
plantas list- End the session when done:
plantas end AThis 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:
- Installation β’ Commands β’ Configuration
- Use Cases β’ Seiva Integration β’ Cross-Session Awareness
- Troubleshooting
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-sessionis fully opt-in and additive β it only installs hooks/commands under.claude/. Re-running with--forceis safe and idempotent (it merges intosettings.local.jsonwithout 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 onbranch- 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 (--baseis an accepted alias)--no-commit- Don't auto-commit thesessions.jsonregistration
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-effortgit fetchof just that branch, so you don't silently branch from a stale local copy. Passrefs/heads/<name>to force the local branch, or setPLANTAS_NO_FETCH=1to skip the fetch. - Always printed:
startreports 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
baseRefon the session insessions.jsonand shown byplantas list.plantas mergeuses it as a fallback merge target. - An existing branch can't be re-cut β
--fromis 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:
.claudeThe 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 thesessions.jsonclose
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 worktreeSafety Features:
- β οΈ Prompts before deleting worktree
- β οΈ Warns if uncommitted changes exist
- β οΈ Shows what will be deleted
- β
Use
--forceto 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 JSONplantas status
Show current Plantas status and configuration.
Example:
plantas statusplantas 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 --fixIt 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 mainWhy 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-featureMerge 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:
- the explicit
branchargument; - the current branch's configured upstream (
@{upstream}), if it has one; integrationBranchfrom.plantas.config.jsonβ defaults to the repository's default branch, so single-branch repos keep working with zero configuration;- the ref the worktree was created from (
baseRefinsessions.json, recorded byplantas 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 tooWhat 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-onlyWhat 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 pathPLANTAS_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 hotfixCode Review While Building
Review PRs without disrupting your current work:
plantas start review "Review PR #42" pr-42-review
# Review, test, comment
plantas end reviewResume 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 offThis 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 oneSeiva 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.mdis 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 --seivaThis:
- Uses
.claude/directory for compatibility - Generates initial
context.mdfrom project analysis - Installs post-commit hook for automatic regeneration
- Creates
AI_GUIDE.mdfor 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 worktreesEach 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-awareplantas-sessionsmerge 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-sessionThis installs (all under .claude/):
- Two hooks β
UserPromptSubmitappends each prompt to a sharedcross-session.logand injects a digest of the other sessions' last-hour activity into the prompt context;Stoprecords 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_DIRanchoring 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 doctorUpgrading
npm install -g @joaodotwork/plantas-cli@latest
cd your-project
plantas init --seiva --forceSee 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 branchA 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 fallbackWorktree 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 sessionContributing
Contributions welcome! See the main repository for guidelines.
License
MIT License - see LICENSE file for details.
Links
Etymology
Plantas (Spanish/Portuguese) means:
- π± Plants - organisms that grow from roots
- π Plans - organized schemes or methods
- π£ Soles (of feet) - foundation for navigation
All three meanings apply to parallel session management!
Made with π± by joaodotwork
