--- 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 ``` ## Configuration User overrides can be set in `~/.kugetsu/config`. This file is sourced on each kugetsu command call, so changes take effect immediately without re-initialization. A default config file is created during `kugetsu init` with commented examples: ```bash # User configuration overrides # Values set here take precedence over defaults # Changes take effect immediately (no re-init needed) # Max concurrent dev agents (default: 3) # MAX_CONCURRENT_AGENTS=5 ``` ### Available Config Options | Variable | Default | Description | |----------|---------|-------------| | `MAX_CONCURRENT_AGENTS` | 3 | Maximum number of concurrent dev agents | | `KUGETSU_TEMP_DIR` | `~/.local/share/opencode/tool-output` | Temp directory for subagent tool output (useful in headless environments where /tmp is restricted) | | `KUGETSU_VERBOSITY` | `default` | PM agent verbosity level: `verbose`, `default`, or `quiet` | ### Environment Variables for Agents Agents receive environment variables through env files, not command-line injection. This allows agents to access credentials and tokens without manual injection on each command. **Files created during `kugetsu init`:** - `~/.kugetsu/env/default.env` - Variables for all agents - `~/.kugetsu/env/pm-agent.env` - Variables for PM agent (overrides default) **Commands:** ```bash kugetsu env list # List all env files kugetsu env show [agent] # Show env file contents (values masked) kugetsu env set [agent] # Set a variable kugetsu env get [agent] # Get a variable value kugetsu env rm [agent] # Remove a variable ``` **Example - Setting GITEA_TOKEN:** ```bash # Set token for PM agent kugetsu env set GITEA_TOKEN ghp_xxx pm-agent # Verify (token masked in output) kugetsu env show pm-agent # Agent now has GITEA_TOKEN when delegated to ``` **Sensitive values are automatically masked** in logs and display: - GITEA_TOKEN, GITHUB_TOKEN, GITLAB_TOKEN - API_KEY, PASSWORD, TOKEN, SECRET **Usage in delegation:** ```bash # PM agent will have GITEA_TOKEN from pm-agent.env kugetsu delegate "post comment on #69" ``` ## 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. ### kugetsu delegate `` Send a message to the PM agent for task coordination (fire-and-forget): ```bash kugetsu delegate "work on issue #14" kugetsu delegate "review PR #92" ``` - Non-blocking: returns immediately, runs in background - PM agent processes the message asynchronously - Uses `KUGETSU_VERBOSITY` env var to control PM agent output verbosity - Log output stored in `~/.kugetsu/logs/delegate-.log` ### kugetsu logs [n] Show recent delegation logs: ```bash kugetsu logs # Show last 10 logs kugetsu logs 20 # Show last 20 logs ``` - Logs are stored in `~/.kugetsu/logs/` - Automatically deletes logs older than 7 days ### kugetsu status Check if kugetsu is properly initialized: ```bash kugetsu status ``` Output: - `kugetsu_not_initialized` - No index file - `base_session_missing` - Base session not found - `pm_agent_missing` - PM agent not found - `ok` - Everything is initialized ### kugetsu doctor [--fix] Diagnose and fix kugetsu issues: ```bash kugetsu doctor # Show diagnostic info kugetsu doctor --fix # Attempt automatic repairs ``` - Checks index file existence - Validates base and PM agent sessions - With `--fix`: recreates PM agent if missing - With `--fix-permissions`: fixes session permissions in opencode database ### kugetsu notify [list|clear] Show or clear notifications from PM agent: ```bash kugetsu notify list # Show unread notifications (default) kugetsu notify clear # Mark all as read ``` - PM agent writes task completion notifications to `~/.kugetsu/notifications.json` - Shows timestamp, type, message, and issue ref for each notification ### kugetsu server Manage git server configurations: ```bash kugetsu server list # List all configured servers kugetsu server add github https://github.com # Add a server kugetsu server remove gitlab # Remove a server kugetsu server default github # Set default server kugetsu server get github # Get server URL ``` ### kugetsu queue Manage task queue for autonomous PM operation: ```bash kugetsu queue list # Show queued tasks kugetsu queue enqueue "task" # Add task to queue kugetsu queue dequeue # Remove next task from queue kugetsu queue clear # Clear all queued tasks ``` - Queue stored in `~/.kugetsu/queue.json` ## 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.