- Scala 91.5%
- Shell 7.8%
- CSS 0.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| .claude/skills/build-iw-cli-skills | ||
| .git-hooks | ||
| .github | ||
| .iw | ||
| commands | ||
| core | ||
| dashboard | ||
| docs | ||
| project-management | ||
| research | ||
| schemas | ||
| scripts | ||
| test | ||
| .gitignore | ||
| .mill-version | ||
| .scalafix.conf | ||
| .scalafmt.conf | ||
| build.mill | ||
| CLAUDE.md | ||
| CONTRIBUTING.md | ||
| iw | ||
| iw-bootstrap | ||
| iw-run | ||
| llms.txt | ||
| mill | ||
| README.md | ||
| RELEASE.md | ||
| VERSION | ||
iw-cli
Project-local CLI tool for managing git worktrees and integrating with issue trackers.
Overview
iw is a project-local tool (similar to mill) that:
- Manages git worktrees as sibling directories for isolated development
- Integrates with issue trackers (Linear, YouTrack, GitHub, GitLab)
- Provides tmux session management per worktree
- Supports project-specific extensibility via scala-cli scripts
Installation
Quick Start
Download and run the bootstrap script in your project root:
curl -L https://code.iterative.works/iterative-works/iw-cli/releases/download/vlatest/iw-bootstrap -o iw
chmod +x iw
./iw init
The bootstrap script will:
- Read the version from
.iw/config.conf(defaults to "latest") - Download the specified version to
~/.local/share/iw/versions/<version>/ - Pre-compile dependencies for offline use
- Execute the requested command
Version Pinning
Pin a specific version in your project's .iw/config.conf:
version = "0.1.0"
Or use the latest release:
version = "latest"
If not specified, defaults to "latest".
Requirements
- scala-cli: Install from scala-cli.virtuslab.org
- git: For worktree management
- tmux (optional): For session management
- curl: For downloading releases
Dashboard contributor requirements
Additional prerequisites for working on the dashboard module:
- Node 20+ with
corepack enable(drives Yarn 4 via thepackageManagerfield inpackage.json) - Yarn 4 — installed automatically by Corepack; no separate install needed
- Mill 1.1.5 — the committed
./millwrapper downloads it on first use WEBAWESOME_NPM_TOKEN— set in env before runningyarn install; needed to fetch licensed UI components
Commands
| Command | Description |
|---|---|
iw init |
Interactive setup, creates .iw/config.conf |
iw doctor |
Validate environment (tokens, tmux, etc.) |
iw start [--prompt <text>] (<issue-id> | --effort <slug>) |
Create sibling worktree + tmux session |
iw open [--prompt <text>] [issue-id|effort-slug] |
Open tmux session (defaults to current branch) |
iw rm <issue-id|effort-slug> |
Kill session, remove worktree, delete branch |
iw issue [issue-id] |
Fetch issue details from configured tracker |
iw projects [--json] |
List all registered projects |
iw worktrees [--all] [--json] |
List worktrees for current project |
iw status [issue-id|effort-slug] [--json] |
Show detailed worktree status |
iw review-state |
Manage review-state.json files (validate, write, update) |
iw ./test [unit|compile|e2e] |
Run tests (project-specific command) |
Agent integration
The --prompt flag on start and open enables agent-driven development. When provided, iw launches a Claude Code session in the tmux pane with the given prompt and exits immediately (detached mode).
# Start work on an issue with an agent
iw start 203 --prompt "Analyze this issue and create analysis.md"
# Send new instructions to an existing session
iw open 203 --prompt "Continue with implementation phase 2"
The projects, worktrees, and status commands support --json for machine-readable output, enabling agents to discover and monitor worktrees programmatically.
# List all projects
iw projects --json
# List worktrees for current project
iw worktrees --json
# Get detailed status for a worktree
iw status IW-203 --json
For detailed documentation on review-state commands, see docs/commands/review-state.md.
Effort worktrees
A worktree is keyed either on a tracker issue or on an effort — a human-named
branch with no tracker issue, hosting several slices that ship as one PR. The
effort must already be framed (project-management/efforts/<slug>/ present) before
the worktree is created:
iw start --effort mail-capture
This creates branch mail-capture and worktree <project>-mail-capture. iw open,
iw rm and iw status accept the slug wherever they accept an issue ID.
See docs/effort-worktrees.md for the slug rules, the on-disk layout, and what the dashboard shows for an effort worktree.
Plugins
AI-specific workflow commands (e.g. implement, batch-implement, transcript-analyze) are not part of iw-cli core. They are distributed as plugin commands — the reference distribution is kanon, which packages Claude Code integrations as hooks and commands.
Plugins are discovered automatically under $XDG_DATA_HOME/iw/plugins/ (defaults to ~/.local/share/iw/plugins/) or via the IW_PLUGIN_DIRS environment variable. A plugin's commands are invoked with the <plugin>/<command> syntax:
iw kanon/batch-implement IW-123
iw kanon/implement IW-123 --phase 2
Plugins may also contribute hooks that extend the behavior of core commands (e.g. kanon's claude-session.hook-start.scala adds an agent session launch to iw start).
A hook may declare the version it was written against with a // REQUIRES: iw-cli >= X.Y.Z header. Hooks the installed version cannot satisfy are skipped with a warning naming the hook and both versions, and the command runs without them — a hook decorates a command rather than being the thing you asked to run, so one stale plugin hook never blocks it. Commands carrying the same header are stricter: an unsatisfied requirement stops the run.
Session hooks receive a SessionContext carrying key (the identity the worktree is addressed under) and kind (Issue or Effort). Read kind before interpreting key: only an issue key resolves against the tracker — an effort worktree's key is its slug. See docs/effort-worktrees.md.
Setting IW_PLUGINS_DISABLED=1 suppresses discovery from every source, so the run only sees the commands and hooks shipped with the installation and the project. Use it to reproduce iw-cli behavior without installed plugins.
GitHub Integration
Repository Auto-Detection
When using iw init --tracker=github, the repository is automatically detected from your git remote URL:
# Automatically detects "iterative-works/iw-cli" from remote URL
iw init --tracker=github
Supported URL formats:
- HTTPS:
https://github.com/owner/repo.git - HTTPS without .git:
https://github.com/owner/repo - HTTPS with username:
https://username@github.com/owner/repo.git - HTTPS with trailing slash:
https://github.com/owner/repo/ - SSH:
git@github.com:owner/repo.git - SSH without .git:
git@github.com:owner/repo
Multiple remotes:
When your repository has multiple remotes (e.g., origin and upstream), the origin remote is always used for auto-detection.
Manual input:
If auto-detection fails (non-GitHub remote or no remote configured), you'll be prompted to enter the repository manually in owner/repo format.
Authentication
GitHub integration uses the gh CLI for authentication:
# Authenticate once
gh auth login
# Then use iw normally
iw init --tracker=github
iw issue
No API tokens needed - iw uses your existing gh authentication.
GitLab Integration
Repository Auto-Detection
When using iw init --tracker=gitlab, the repository is automatically detected from your git remote URL:
# Automatically detects "owner/project" from remote URL
iw init --tracker=gitlab --team-prefix=PROJ
Supported URL formats:
- HTTPS:
https://gitlab.com/owner/project.git - HTTPS without .git:
https://gitlab.com/owner/project - HTTPS with trailing slash:
https://gitlab.com/owner/project/ - SSH:
git@gitlab.com:owner/project.git - SSH without .git:
git@gitlab.com:owner/project - Self-hosted:
https://gitlab.company.com/owner/project.git - Nested groups:
https://gitlab.com/company/team/project.git
Multiple remotes:
When your repository has multiple remotes (e.g., origin and upstream), the origin remote is always used for auto-detection.
Manual input:
If auto-detection fails (non-GitLab remote or no remote configured), you'll be prompted to enter the repository manually in owner/project or group/subgroup/project format.
Authentication
GitLab integration uses the glab CLI for authentication:
# Install glab CLI (macOS)
brew install glab
# Install glab CLI (Linux/Windows)
# See https://gitlab.com/gitlab-org/cli#installation
# Authenticate once
glab auth login
# Then use iw normally
iw init --tracker=gitlab --team-prefix=PROJ
iw issue
No API tokens needed - iw uses your existing glab authentication.
Self-Hosted GitLab
For self-hosted GitLab instances, specify the base URL during initialization:
iw init --tracker=gitlab --team-prefix=PROJ --base-url=https://gitlab.company.com
Or add it manually to .iw/config.conf:
tracker {
type = gitlab
repository = "team/project"
teamPrefix = "PROJ"
baseUrl = "https://gitlab.company.com" # Optional, defaults to gitlab.com
}
Nested Groups
GitLab supports nested group structures like company/team/project. These are fully supported:
# Auto-detection works with nested groups
git remote add origin https://gitlab.com/company/team/project.git
iw init --tracker=gitlab --team-prefix=PROJ
Configuration:
tracker {
type = gitlab
repository = "company/team/project"
teamPrefix = "PROJ"
}
Worktree Layout
Worktrees are created as sibling directories:
~/projects/
├── myproject/ # main worktree (master/main)
├── myproject-IW-123/ # worktree for issue IW-123
├── myproject-IW-456/ # worktree for issue IW-456
Development
Setup
Clone the repository and use the local iw script directly:
git clone https://code.iterative.works/iterative-works/iw-cli.git
cd iw-cli
./iw --list
The local iw script runs commands from commands/ without downloading anything - ideal for development.
Testing in Other Projects
To test your local iw-cli changes in other projects, set IW_HOME:
# In any project using iw-bootstrap
IW_HOME=/path/to/iw-cli ./iw --list
# Or export for the session
export IW_HOME=/path/to/iw-cli
./iw start ISSUE-123
This bypasses version download and uses your local iw-run directly.
Testing
The project has three types of tests:
Unit Tests (Scala/munit)
Run Scala unit tests with:
./iw ./test unit
Or directly with scala-cli:
scala-cli test core/
E2E Tests (BATS)
End-to-end tests verify the CLI behavior. By default, tests that would create real Linear issues are skipped.
Run E2E tests (without live API calls):
./iw ./test e2e
Or directly with BATS:
bats test/
Live API Tests
Some E2E tests can create real Linear issues for comprehensive testing. These are disabled by default to prevent issue accumulation.
To enable live API tests:
ENABLE_LIVE_API_TESTS=1 ./iw ./test e2e
Requirements:
LINEAR_API_TOKENenvironment variable must be setENABLE_LIVE_API_TESTS=1must be explicitly set
Warning: Live API tests will create real issues in Linear with [TEST] prefix. These should be cleaned up periodically.
Run All Tests
./iw ./test
Or manually:
scala-cli test core/ && bats test/
Project Structure
iw-cli/
├── iw # Development launcher (runs locally)
├── iw-bootstrap # Distribution bootstrap (downloads releases)
├── iw-run # Distribution launcher (in release tarball)
├── VERSION # Current version
├── commands/ # Shared command implementations (*.scala)
├── core/ # Shared library code
│ ├── project.scala # Build configuration (deps, Scala version)
│ └── test/ # Unit tests
├── test/ # E2E tests (*.bats)
├── scripts/ # Build/release scripts
├── .iw/
│ ├── config.conf # Project config (tracker, etc.)
│ └── commands/ # Project-specific commands (test.scala)
└── RELEASE.md # Release process documentation
Creating a Release
See RELEASE.md for the full release process. Quick version:
scripts/package-release.sh 0.1.0
# Creates release/iw-cli-0.1.0.tar.gz
License
MIT