feat(kugetsu): implement issue-driven session management
- Add kugetsu init to create base session via TUI - Add kugetsu start/continue for issue-based task handling - Add kugetsu list/prune/destroy for session lifecycle - Implement directory files + index.json storage pattern - Use issue ref format: instance/user/repo#number - Fork from base session enables headless operation Solves: opencode headless CLI limitation discovered in issue #14
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
---
|
||||
name: kugetsu
|
||||
description: Session manager for opencode CLI. Use when managing long-running opencode sessions, resuming interrupted work, or tracking session state across disconnects. Features state tracking (used/idle/left), auto-fill last message on resume, and safe locking via confirmation prompts.
|
||||
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, and filesystem access for session state.
|
||||
compatibility: Requires opencode CLI, bash, python3, and filesystem access.
|
||||
metadata:
|
||||
author: shoko
|
||||
version: "1.1"
|
||||
version: "2.0"
|
||||
---
|
||||
|
||||
# kugetsu - OpenCode Session Manager
|
||||
# kugetsu - OpenCode Session Manager (Issue-Driven)
|
||||
|
||||
Manages opencode CLI sessions with state tracking and safe resume.
|
||||
Manages opencode sessions with a base session + forked session pattern optimized for headless orchestration.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -27,122 +27,184 @@ cp skills/kugetsu/scripts/kugetsu ~/.local/bin/kugetsu
|
||||
chmod +x ~/.local/bin/kugetsu
|
||||
```
|
||||
|
||||
Or source directly when needed:
|
||||
```bash
|
||||
. skills/kugetsu/scripts/kugetsu
|
||||
## Architecture
|
||||
|
||||
### Session Pattern
|
||||
- **Base Session**: Created once via TUI, used for forking
|
||||
- **Forked Sessions**: One per issue, branched from base via `opencode run --fork --session <base>`
|
||||
|
||||
### Directory Structure
|
||||
```
|
||||
~/.kugetsu/
|
||||
├── sessions/
|
||||
│ ├── base.json # Base session metadata
|
||||
│ └── github.com-shoko-kugetsu-14.json # Forked session per issue
|
||||
└── index.json # Maps issue refs to session files
|
||||
```
|
||||
|
||||
## Session State
|
||||
### Index File
|
||||
```json
|
||||
{
|
||||
"base": "ses_abc123",
|
||||
"issues": {
|
||||
"github.com/shoko/kugetsu#14": "github.com-shoko-kugetsu-14.json"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| State | Meaning | Resumable? |
|
||||
|-------|---------|------------|
|
||||
| `used` | Session is active (process running) | Yes (with confirmation) |
|
||||
| `idle` | Session ended gracefully | No |
|
||||
| `left` | Session interrupted/crashed | Yes |
|
||||
| `invalid` | Session data missing/corrupt | No |
|
||||
### Session File
|
||||
```json
|
||||
{
|
||||
"type": "base|forked",
|
||||
"issue_ref": "github.com/shoko/kugetsu#14",
|
||||
"opencode_session_id": "ses_xyz789",
|
||||
"created_at": "2026-03-29T18:16:10+02:00",
|
||||
"state": "idle"
|
||||
}
|
||||
```
|
||||
|
||||
## Session Directory
|
||||
## Issue Ref Format
|
||||
|
||||
Sessions are stored in `~/.kugetsu/sessions/<session_id>/`:
|
||||
- `state` - current state (used/idle/left/invalid)
|
||||
- `message` - last user message (for auto-fill)
|
||||
- `pid` - active process PID (when used)
|
||||
All issue references use the format: `instance/user/repo#number`
|
||||
|
||||
Examples:
|
||||
- `github.com/shoko/kugetsu#14`
|
||||
- `gitlab.com/username/project#42`
|
||||
- `codeberg.org/user/repo#100`
|
||||
|
||||
## Commands
|
||||
|
||||
### kugetsu start `<session_id>` `<message>`
|
||||
Start a new session:
|
||||
### kugetsu init [--force]
|
||||
|
||||
Initialize base session via TUI:
|
||||
```bash
|
||||
kugetsu start mytask "fix bug #1"
|
||||
kugetsu init
|
||||
```
|
||||
- Creates session directory
|
||||
- Sets state to `used`
|
||||
- Stores PID and message
|
||||
- Runs: `opencode run --session <session_id> <message>`
|
||||
|
||||
### kugetsu list [--all]
|
||||
List sessions:
|
||||
- Requires a terminal (TTY) to spawn the opencode TUI
|
||||
- Creates base session once; subsequent runs error unless `--force` is used
|
||||
- Stores base session ID in `index.json`
|
||||
|
||||
### kugetsu start `<issue-ref>` `<message>` [--debug]
|
||||
|
||||
Start task for an issue by forking from base session:
|
||||
```bash
|
||||
kugetsu list # Shows only `left` (resumable)
|
||||
kugetsu list --all # Shows all states
|
||||
kugetsu start github.com/shoko/kugetsu#14 "fix authentication bug"
|
||||
```
|
||||
|
||||
### kugetsu resume `<session_id>` [message]
|
||||
Resume an interrupted session:
|
||||
- Forks new session from base
|
||||
- Stores mapping in `index.json`
|
||||
- Uses `opencode run --fork --session <base-session-id> "<message>"`
|
||||
|
||||
### kugetsu continue `<issue-ref>` `<message>` [--debug]
|
||||
|
||||
Continue work on an existing issue session:
|
||||
```bash
|
||||
kugetsu resume mytask # Auto-fills last message
|
||||
kugetsu resume mytask "continue" # Uses provided message
|
||||
kugetsu continue github.com/shoko/kugetsu#14 "add unit tests"
|
||||
```
|
||||
- If state is `used`: prompts for confirmation (someone else might be using)
|
||||
- If state is `idle`: errors (not resumable)
|
||||
- If state is `left`: proceeds with message
|
||||
|
||||
### kugetsu stop `<session_id>`
|
||||
Stop a session gracefully:
|
||||
- Looks up session file from index
|
||||
- Uses `opencode run --continue --session <opencode-session-id> "<message>"`
|
||||
|
||||
### kugetsu list
|
||||
|
||||
List all tracked sessions:
|
||||
```bash
|
||||
kugetsu stop mytask
|
||||
kugetsu list
|
||||
```
|
||||
- Sends SIGTERM to process
|
||||
- Sets state to `idle`
|
||||
|
||||
### kugetsu destroy `<session_id>` [-y]
|
||||
Delete a session:
|
||||
Output:
|
||||
```
|
||||
ISSUE_REF TYPE SESSION_ID CREATED
|
||||
──────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
(base) base ses_abc123 N/A
|
||||
github.com/shoko/kugetsu#14 forked ses_xyz789 2026-03-29T18:16:10+02:00
|
||||
```
|
||||
|
||||
### kugetsu prune [--force]
|
||||
|
||||
Remove orphaned sessions (files not in index):
|
||||
```bash
|
||||
kugetsu destroy mytask # Prompts for confirmation (default: N)
|
||||
kugetsu destroy mytask -y # Skips confirmation
|
||||
kugetsu prune # Shows what would be deleted
|
||||
kugetsu prune --force # Deletes orphaned sessions
|
||||
```
|
||||
- Errors if session is `used` (use `stop` first)
|
||||
- Errors if session not found
|
||||
|
||||
### kugetsu destroy --all [-y]
|
||||
Delete all sessions:
|
||||
- Orphaned = session files in `sessions/` but not in `index.json`
|
||||
- Always keeps `base.json`
|
||||
- Useful after opencode session cleanup
|
||||
|
||||
### kugetsu destroy `<issue-ref>` [-y]
|
||||
|
||||
Delete session for specific issue:
|
||||
```bash
|
||||
kugetsu destroy --all # Prompts for confirmation (default: N)
|
||||
kugetsu destroy --all -y # Skips confirmation
|
||||
```
|
||||
- Useful for fresh start
|
||||
|
||||
### kugetsu help
|
||||
Show usage help.
|
||||
|
||||
## State Transitions
|
||||
|
||||
```
|
||||
start ──────────────► used ──────► idle (stop/SIGTERM)
|
||||
│
|
||||
└──────► left (kill/SIGINT/crash)
|
||||
│
|
||||
▼
|
||||
destroy (delete)
|
||||
kugetsu destroy github.com/shoko/kugetsu#14 # Prompts for confirmation
|
||||
kugetsu destroy github.com/shoko/kugetsu#14 -y # Skips confirmation
|
||||
```
|
||||
|
||||
## Example Workflow
|
||||
### kugetsu destroy --base [-y]
|
||||
|
||||
Delete base session (requires explicit `--base`):
|
||||
```bash
|
||||
kugetsu destroy --base -y
|
||||
```
|
||||
|
||||
## Workflow Example
|
||||
|
||||
```bash
|
||||
# Start a long-running task
|
||||
kugetsu start issue42 "implement feature X"
|
||||
# First-time setup (requires TTY)
|
||||
kugetsu init
|
||||
|
||||
# ... time passes, connection drops ...
|
||||
# Start work on issue
|
||||
kugetsu start github.com/shoko/kugetsu#14 "implement feature X"
|
||||
|
||||
# Check what sessions are resumable
|
||||
# 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
|
||||
|
||||
# Resume with auto-filled message
|
||||
kugetsu resume issue42
|
||||
# Clean up orphaned sessions
|
||||
kugetsu prune --force
|
||||
|
||||
# Later, when done
|
||||
kugetsu stop issue42
|
||||
|
||||
# When you want a fresh start
|
||||
kugetsu destroy --all
|
||||
# Delete session 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 <new>` 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)
|
||||
- All subsequent work uses `--fork --session <base>` or `--continue --session <forked>`
|
||||
|
||||
## Recovery
|
||||
|
||||
If opencode sessions become out of sync:
|
||||
|
||||
1. `kugetsu list` shows tracked sessions
|
||||
2. `kugetsu prune` removes orphaned files
|
||||
3. For full reset: `kugetsu destroy --base -y && kugetsu init`
|
||||
|
||||
## Without kugetsu
|
||||
|
||||
If kugetsu is not installed, use opencode directly:
|
||||
If kugetsu is not available, use opencode directly:
|
||||
```bash
|
||||
opencode run --session mytask "task description"
|
||||
opencode run --continue --session mytask "continue"
|
||||
opencode session list
|
||||
# Create base session (requires TTY)
|
||||
opencode
|
||||
# Note the session ID from: opencode session list
|
||||
|
||||
# Fork for issue
|
||||
opencode run --fork --session <base-session-id> "task"
|
||||
|
||||
# Continue
|
||||
opencode run --continue --session <forked-session-id> "continue"
|
||||
```
|
||||
Tradeoff: No state tracking, no auto-fill, no filtered list, no confirmation prompts.
|
||||
|
||||
Tradeoff: No issue mapping, no index, manual session tracking.
|
||||
Reference in New Issue
Block a user