--- name: kugetsu description: Issue-driven session manager for opencode CLI. Manages base sessions and per-issue forked sessions with automatic indexing for headless orchestration. license: MIT compatibility: Requires opencode CLI, bash, python3, and filesystem access. metadata: author: shoko version: "2.2" --- # kugetsu - OpenCode Session Manager (Issue-Driven) Manages opencode sessions with a base session + forked session pattern optimized for headless orchestration. Each issue gets an isolated git worktree to prevent workspace conflicts. ## Installation ### For Human Users Run once on a new host: ```bash . skills/kugetsu/scripts/kugetsu-install.sh ``` ### For Agents (Self-Install) Copy the script to your PATH: ```bash cp skills/kugetsu/scripts/kugetsu ~/.local/bin/kugetsu chmod +x ~/.local/bin/kugetsu ``` ## Architecture ### Session Pattern - **Base Session**: Created once via TUI, used for forking dev agents - **PM Agent Session**: Created during init, persistent coordinator for task management - **Forked Sessions**: One per issue, branched from base via `opencode run --fork --session ` ### Git Worktree Isolation Each issue session gets its own git worktree to prevent conflicts: - Isolated working directory (no file collisions) - Isolated branch (no checkout conflicts) - Shared `.git` objects (efficient storage) ### Directory Structure ``` ~/.kugetsu/ ├── sessions/ │ ├── base.json # Base session metadata │ ├── pm-agent.json # PM agent session metadata │ └── github.com-shoko-kugetsu-14.json # Forked session per issue ├── worktrees/ │ ├── github.com-shoko-kugetsu-14/ # Isolated workdir for issue #14 │ └── github.com-shoko-kugetsu-15/ # Isolated workdir for issue #15 └── index.json # Maps session IDs and issue refs to session files ``` ### Index File ```json { "base": "ses_abc123", "pm_agent": "ses_pm_xyz789", "issues": { "github.com/shoko/kugetsu#14": "github.com-shoko-kugetsu-14.json" } } ``` ### Session File ```json { "type": "forked", "issue_ref": "github.com/shoko/kugetsu#14", "opencode_session_id": "ses_xyz789", "worktree_path": "/home/user/.kugetsu/worktrees/github.com-shoko-kugetsu-14", "created_at": "2026-03-29T18:16:10+02:00", "state": "idle" } ``` ## Issue Ref Format All issue references use the format: `instance/user/repo#identifier` Examples: - `github.com/shoko/kugetsu#14` (issue number) - `github.com/shoko/kugetsu#-discuss` (discussion, no issue number yet) - `gitlab.com/username/project#42` (issue number) ## Worktree Behavior ### On `kugetsu start` 1. Derives worktree path from issue ref: `~/.kugetsu/worktrees/{sanitized-ref}/` 2. If worktree exists: removes and recreates (guaranteed clean state) 3. If worktree doesn't exist: creates fresh 4. Clones repo, creates branch `fix/issue-{id}` 5. Runs opencode with `--workdir` pointing to worktree ### On `kugetsu destroy` 1. Removes worktree via `git worktree remove` 2. Deletes session file and index entry ### Repo Configuration If the repo URL cannot be derived from the issue ref, add to `~/.kugetsu/repos.json`: ```json { "github.com/shoko kugetsu#14": "https://custom.repo.url/owner/repo.git" } ``` ## Commands ### kugetsu init [--force] Initialize base + PM agent sessions via TUI: ```bash kugetsu init ``` - Requires a terminal (TTY) to spawn the opencode TUI - Creates base session and PM agent session - Stores both session IDs in `index.json` - Subsequent runs error unless `--force` is used ### kugetsu start `` `` [--debug] Start task for an issue by forking from base session: ```bash kugetsu start github.com/shoko/kugetsu#14 "fix authentication bug" kugetsu start github.com/shoko/kugetsu#-discuss "research auth options" ``` - Creates isolated git worktree for the issue - Forks new session from base - Requires PM agent to exist (created by init) - Uses `opencode run --fork --session "" --workdir ` ### kugetsu continue `` `` [--debug] Continue work on an existing issue session: ```bash kugetsu continue github.com/shoko/kugetsu#14 "add unit tests" ``` - Looks up session file from index - Uses `opencode run --continue --session "" --workdir ` ### kugetsu list List all tracked sessions: ```bash kugetsu list ``` Output: ``` ISSUE_REF TYPE SESSION_ID WORKTREE ──────────────────────────────────────────────────────────────────────────────────────────────────────── (base) base ses_abc123 N/A (pm-agent) pm_agent ses_pm_xyz789 N/A github.com/shoko/kugetsu#14 forked ses_xyz789 /home/user/.kugetsu/worktrees/github.com-shoko-kugetsu-14 ``` ### kugetsu prune [--force] Remove orphaned sessions and worktrees: ```bash kugetsu prune # Shows what would be deleted kugetsu prune --force # Deletes orphaned items ``` - Orphaned = session files or worktrees not in index - Always keeps `base.json` and `pm-agent.json` - Useful after opencode session cleanup ### kugetsu destroy `` [-y] Delete session and worktree for specific issue: ```bash kugetsu destroy github.com/shoko/kugetsu#14 # Prompts for confirmation kugetsu destroy github.com/shoko/kugetsu#14 -y # Skips confirmation ``` ### kugetsu destroy --pm-agent [-y] Delete PM agent session (requires explicit `--pm-agent`): ```bash kugetsu destroy --pm-agent -y ``` ### kugetsu destroy --base [-y] Delete base session (requires explicit `--base`): ```bash kugetsu destroy --base -y ``` **Note**: Destroying base also destroys PM agent since PM depends on base. ## Workflow Example ```bash # First-time setup (requires TTY) kugetsu init # Creates: base session + pm-agent session # Start work on issue kugetsu start github.com/shoko/kugetsu#14 "implement feature X" # Creates: worktree at ~/.kugetsu/worktrees/github.com-shoko-kugetsu-14/ # Continue later kugetsu continue github.com/shoko/kugetsu#14 "add tests" # Continue again kugetsu continue github.com/shoko/kugetsu#14 "fix failing test" # List all sessions kugetsu list # Clean up orphaned items kugetsu prune --force # Delete session and worktree when done kugetsu destroy github.com/shoko/kugetsu#14 ``` ## Headless Operation This design solves the headless CLI limitation discovered in Issue #14: 1. **Problem**: `opencode run --session ` doesn't work headlessly (SSE stream terminates) 2. **Solution**: Fork from existing base session, which works headlessly The pattern: - Base session created once via TUI (interactive) - PM agent session created during init (persistent coordinator) - All subsequent work uses `--fork --session ` or `--continue --session ` - Each session works in isolated git worktree ## Recovery If opencode sessions become out of sync: 1. `kugetsu list` shows tracked sessions 2. `kugetsu prune` removes orphaned files and worktrees 3. For full reset: `kugetsu destroy --base -y && kugetsu init` ## Remote Access via SSH (Optional) To access kugetsu from a remote machine, SSH setup is required. ### Automated Setup Run the SSH setup script inside your container: ```bash chmod +x skills/kugetsu/scripts/sshd-setup.sh bash skills/kugetsu/scripts/sshd-setup.sh ``` Omit `` to use default user `kugetsu`. ### What It Does - Checks systemd prerequisite - Creates non-root user - Configures SSH for key-only authentication - Enables passwordless sudo for the user - Starts sshd via systemd ### After Setup 1. Add your SSH public key to `~/.ssh/authorized_keys` on the container 2. Configure port forwarding on the host (see [docs/kugetsu-setup.md](../../docs/kugetsu-setup.md)) 3. Connect: `ssh -p 2222 @` ### Remote Usage Once connected via SSH, kugetsu works the same as local: ```bash kugetsu list kugetsu start github.com/shoko/kugetsu#14 "fix bug" kugetsu continue github.com/shoko/kugetsu#14 ``` ### Documentation See [docs/kugetsu-setup.md](../../docs/kugetsu-setup.md) for full remote access setup including host-side port forwarding and firewall configuration. ### Tailscale VPN (Alternative) If your host does not have a public IP or you need access across different networks, Tailscale provides a VPN solution. **Benefits:** - No public IP required - Each container gets its own unique Tailscale IP - Access from anywhere via Tailscale network - Normal internet access still works **Setup:** ```bash chmod +x skills/kugetsu/scripts/tailscale-setup.sh bash skills/kugetsu/scripts/tailscale-setup.sh ``` The script will: 1. Install Tailscale (supports Debian/Ubuntu, Fedora) 2. Start the tailscaled daemon 3. Prompt for AUTHKEY or browser-based login 4. Configure device name (defaults to current hostname) **After Setup:** - From any Tailscale device: `ssh @` - Works across different networks without port forwarding See [docs/kugetsu-setup.md](../../docs/kugetsu-setup.md) for full Tailscale setup documentation. ## Without kugetsu If kugetsu is not available, use opencode directly: ```bash # Create base session (requires TTY) opencode # Note the session ID from: opencode session list # Fork for issue opencode run --fork --session "task" # Continue opencode run --continue --session "continue" ``` Tradeoff: No issue mapping, no index, manual session tracking, no worktree isolation.