Fixes#142 - process_queue silently skips all queue items because
issue_ref and message Python extraction commands were missing a closing
parenthesis. The error was silently swallowed by 2>/dev/null causing
both variables to be empty, so every queue item was skipped.
Implements #137 - Agent timeout handling.
Changes:
- Add TASK_TIMEOUT_HOURS config (default: 1 hour)
- Update queue item to track opencode_session_id and pid
- Add check_task_timeouts() function that:
- Checks notified tasks against timeout threshold
- Kills process if exceeded
- Marks session as 'timeout' state
- Integrate timeout check into queue daemon loop
Timeout behavior:
- Task is marked 'notified' when PM receives it
- If not completed within TASK_TIMEOUT_HOURS, task is killed
- Queue item marked 'error', session marked 'timeout'
- Extract hostname from pr_url instead of hardcoding domains
- Look up server base URL from GIT_SERVERS config
- Append /api/v1 to derive API URL (configurable per server)
- Works with any server configured in GIT_SERVERS
- Rename update-pr to set-pr for clarity (it's setting the PR URL, not updating PR)
- Add optional pr-url argument to kugetsu start command
Usage: kugetsu start <issue-ref> <message> [pr-url]
- If pr-url is provided at start, it's stored directly in session file
- Add WORKTREE_CHECK_PR_STATUS config (default: true)
- Add pr_url and branch_name fields to session files
- Add check_pr_status() to query PR status via API (Gitea/GitHub)
- Add update_session_pr_url() to update PR URL in session
- Add kugetsu update-pr command to set PR URL
- Modify cmd_destroy to check PR status before destroying worktree
Closes#135
- Parse issue refs from message (gitserver.com/owner/repo/issues/123 or owner/repo#123)
- Find existing worktrees/sessions by issue number
- Ask user to confirm which worktree to use, or delegate anyway
- Inject missing info context to PM agent
- Inject selected worktree context to PM agent
Fixes#128
The --dir flag only sets directory for the subprocess, not the session's
stored directory in opencode's SQLite DB. This was already fixed for
cmd_start in v0.1.10, but cmd_continue still had the bug.
Fixes#127
1. Init: cd to ~/.kugetsu-worktrees before creating base session
This keeps all worktrees inside a predictable directory structure
and avoids external_directory permission issues
2. Init: Clear old logs but keep repos.json, config, and env files
3. Fork context: Add kugetsu_get_fork_context() that provides:
- Important working rules (stop on error, don't pivot)
- Repository configuration from repos.json
- Environment file location info
4. Fork message: Prepend context to user message when forking session
Previously destroy only removed local session files but didn't delete
the sessions from opencode's database. This caused init to reuse the
same session with old context.
Now destroy calls 'opencode session delete <id>' to properly remove
the session from opencode.
Warn users if running kugetsu init from a directory with files or
git repository. This prevents project context from contaminating the
base session, which causes forked sessions to have unwanted context.
opencode session list doesn't show sessions in ~/.kugetsu-worktrees/ directories.
This caused detection to fail even though sessions were being created.
Now we query the database directly for sessions matching the worktree path.
Also fixed database path in fix_session_permissions (was ~/.opencode/, should be ~/.local/share/opencode/).
Previously we only fixed base session permissions before forking.
But permissions are NOT inherited from parent to child.
Now we update the newly created session's permissions immediately
after detection, ensuring the forked session can access external
directories like ~/.kugetsu/worktrees/.
- Call fix_session_permissions in cmd_start before forking to ensure
base session has correct permissions for external_directory access
- Add debug logging to show forked session's directory and permissions
after creation to help diagnose permission inheritance issues
1. Move session detection BEFORE checking if fork process is still running.
Previous code broke out of loop if forked process exited, skipping detection.
2. Add database query debugging when detection fails to help diagnose
why opencode session list might miss newly created sessions.
- Capture fork output to log file for debugging
- Track fork PID to detect if process exits early
- Retry session detection up to 10 seconds instead of 1 second
- Show fork log output when session creation fails
- Improve error message to indicate timeout
Issue #105: opencode run --fork/--continue --dir <path> fails to create sessions
Root cause: The --dir flag breaks session creation in opencode. Sessions
fail to be created when --dir is used with --fork or --continue.
Solution: Instead of using --dir flag, create worktrees inside the parent
session's directory and use 'cd $worktree_path && opencode run ...' to
change directory before running opencode.
Key changes:
- Worktrees now created at $PWD/.kugetsu-worktrees/{issue-ref}/ instead
of $WORKTREES_DIR/{issue-ref}/
- .kugetsu-worktrees is a hidden directory (git ignored by default)
- cmd_start and cmd_continue now use 'cd && opencode run' instead of
'opencode run --dir'
This approach works because:
1. Worktree is inside parent's directory tree (permission granted)
2. cd properly changes working directory before opencode runs
3. Session gets created with correct directory set
4. No .gitignore entry needed (. prefix makes it hidden from git)
- Test E7: verify fix_session_permissions function exists
- Test E8: verify cmd_doctor --fix-permissions flag is recognized
- Test E9: verify permission JSON is valid JSON
- Test E10: verify SQL UPDATE syntax works correctly
These tests verify the fix without requiring actual opencode installation.
- Add test E7: verify fix_session_permissions function exists
- Add test E8: verify cmd_doctor --fix-permissions flag is recognized
- Add fix_session_permissions call to cmd_init to set permissions
when initializing new sessions
Add --fix-permissions flag to cmd_doctor:
kugetsu doctor --fix-permissions
The fix_session_permissions() function:
- Updates base session and PM agent session permissions in SQLite
- Sets external_directory pattern to '*' with action 'allow'
- This fixes the issue where PM agent cannot access external directories
This addresses issue #36 where PM agent external_directory permission fails.
Fixes#36
Export KUGETSU_TEMP_DIR in cmd_delegate so subagents can use it
instead of /tmp which may be blocked by opencode.
Default: ~/.local/share/opencode/tool-output
This allows agents to write temp files in an allowed directory
instead of /tmp which is blocked in headless mode.
Fixes#73
Add tests for env pass-through feature:
- Test env command exists and lists files
- Test env set creates env file
- Test env show masks sensitive values (GITEA_TOKEN)
- Test set -a exports variables to child processes
- Test pm-agent.env takes precedence over default.env
- Test cmd_init creates env template files
These tests ensure the env pass-through mechanism works correctly
and that variables are properly exported to subagents.
The issue: variables sourced in cmd_delegate were not being passed
to child processes (subagents) because 'source' doesn't automatically
export variables to child processes.
Fix:
1. Use 'set -a' before sourcing to auto-export all variables
2. Use 'set +a' after sourcing to disable auto-export
3. Updated template comments to recommend 'export' prefix
Also added unit test to verify env pass-through works.
Verified with tests that child processes now see the exported variables.
Add section on Environment Variables for Agents:
- Explain env files (default.env, pm-agent.env)
- Document kugetsu env commands (list, show, set, get, rm)
- Show example usage for GITEA_TOKEN
- Note sensitive value masking
- Explain delegation usage
This ensures agents know to use kugetsu env instead of manually
injecting variables on each command.
Update cmd_init to create:
- ~/.kugetsu/env/ directory
- ~/.kugetsu/env/default.env (template)
- ~/.kugetsu/env/pm-agent.env (template)
Users can then edit these files to add their tokens/secrets.
Add environment variable management for delegating to agents.
Features:
- Add ENV_DIR constant (\~/.kugetsu/env)
- Add mask_sensitive_vars() to hide sensitive values in logs
- Add load_agent_env() to load agent-specific env files
- Add cmd_env command for managing env files:
- list: List all env files
- show [agent]: Show env file contents (masked)
- set <key> <value> [agent]: Set key=value
- get <key> [agent]: Get value for key
- rm <key> [agent]: Remove key
- Update cmd_delegate to load pm-agent.env or default.env before running
Example usage:
kugetsu env set GITEA_TOKEN xxx pm-agent
kugetsu delegate "post comment on #69"
Fixes#76
- Remove hardcoded git.fbrns.co server (users should add their own)
- Add comment about how to add servers
- Support --force flag in cmd_init to regenerate config file
This addresses han's review feedback:
1. Removed git.fbrns.co from default config
2. Config file can now be regenerated with --force flag
3. We continue using the existing config file (not separate file)
Document findings from database investigation:
- Session table schema with all fields explained
- Session ID format and generation (unique, no duplicates)
- Parent-child relationships for forked sessions
- Session detection logic used by kugetsu
- Permission structure and common issues
- SQL queries for debugging session problems
- Known issues and solutions (from #81, #36)
This document helps future debugging of session-related issues
without having to investigate opencode internals directly.
Replace string-based session comparison with array-based approach:
- Store before_sessions in an array instead of pipe-delimited string
- This is more robust against word-splitting issues in bash
- Skip base_session_id and pm_agent_session_id explicitly
- Compare each after-session against the before array
This approach is more reliable when multiple agents fork concurrently
because it properly compares each session ID individually rather than
relying on regex matching in a string.
Fixes#81
When cmd_start forks a new session, the session detection logic now
excludes both base_session_id AND pm_agent_session_id to prevent
forked sessions from being misidentified as the pm-agent session.
This addresses issue #81 where forked sessions were showing the same
session ID as the pm-agent.
Add 'kugetsu server' command for managing git server configurations:
- kugetsu server list List all configured git servers
- kugetsu server add <name> <url> Add a new git server
- kugetsu server remove <name> Remove a git server
- kugetsu server default [<name>] Get or set default server
- kugetsu server get [<name>] Get URL for a server
Update get_repo_url() to use GIT_SERVERS config:
- First checks repos.json for direct mapping
- Then checks GIT_SERVERS for matching hostname
- Falls back to DEFAULT_GIT_SERVER
- Falls back to github.com as last resort
Update cmd_init to create config with default git servers:
- github.com -> https://github.com
- git.fbrns.co -> https://git.fbrns.coFixes#78
Set GIT_EDITOR and EDITOR to 'cat' in kugetsu init to prevent
vim from opening during git operations in headless mode.
This fixes issues where git rebase --continue would hang waiting
for vim TTY input in opencode sessions.
Fixes#70
- Source ~/.kugetsu/config on each command call
- Allows user to override defaults (e.g., MAX_CONCURRENT_AGENTS)
- Changes take effect immediately, no re-init needed
Fixes#67
The session-counting approach (PR #65) now properly handles agent
concurrency limits. Remove the broken slot-based mechanism:
- Remove acquire_agent_slot() and release_agent_slot() functions
- Remove AGENT_COUNT_FILE and AGENT_LOCK_FILE variables
- Remove unused run_with_limit() function
- Remove release-slot.sh script
- Update cmd_delegate to use fire-and-forget without slot management
Both cmd_start and cmd_delegate now use count_active_dev_sessions()
for concurrency checking.
Replaced broken slot-based mechanism with session-counting:
- Added count_active_dev_sessions() function that counts actual
session files in ~/.kugetsu/sessions/, excluding base.json and pm-agent.json
- Modified cmd_start() to check session count before creating new session:
- If count >= MAX_CONCURRENT_AGENTS, reject with error
- Otherwise allow new session creation
- Removed wait since --fork returns immediately
- cmd_continue() no longer counts toward limit (existing sessions
can always continue via --continue)
This properly enforces MAX_CONCURRENT_AGENTS while preserving --fork
functionality. The slot mechanism didn't work because opencode run
--fork returns immediately after forking, not after child completes.
- Fixed cmd_start() and cmd_continue() to wait for forked child
- Capture child PID with $! and wait before release_agent_slot
- This ensures slot is only released after child process completes
Issue #57: worktree creation was creating bare repos instead of
proper worktrees, breaking parallel agent workflow.
The --bare flag created repos with no working directory, making them
useless for development. Changed to regular clone.
PR #54 fixed opencode arg order in cmd_delegate and cmd_start,
but kugetsu init function still had message AFTER flags.
Fixed in:
- kugetsu_init function: message before --fork --session
- Similar patterns in session creation code
Closes related to #53
Replace hardcoded git.fbrns.co/shoko/kugetsu with dynamic
<domain>/<user>/<repo> format pulled from git remote and config.
Makes PM skill usable with github.com, gitlab.com, or any git server.
- PM can ONLY write to ~/.kugetsu/queue.json and ~/.kugetsu/logs/* (was entire ~/.kugetsu/)
- Update delegation format to git.fbrns.co/shoko/kugetsu#<issue>
- PM must not write new kugetsu scripts - delegate via issue/PR workflow
- Update examples and violation cases to reflect stricter boundaries
Issue #52: PM violated NEVER write code constraint by writing directly to
repo files (SKILL.md) instead of delegating to a dev agent.
Added explicit Write Permissions section defining:
- PM can ONLY write to ~/.kugetsu/
- PM can NEVER write to repositories/*, skills/*, or any dir outside ~/.kugetsu/
- If asked to write outside ~/.kugetsu/, must delegate via kugetsu start
opencode CLI requires: opencode run "message" --session sid --workdir /path
But kugetsu was placing message AFTER flags, causing all commands to fail.
Fixed in:
- cmd_delegate: nohup sh -c with message first
- cmd_start: --fork --session with message first
- fork_session_for_issue: --continue --session with message first
Closes#53
2026-03-31 21:29:37 +00:00
9 changed files with 2288 additions and 417 deletions
This document contains findings about how OpenCode manages sessions, based on direct database investigation. Use this when debugging session-related issues in kugetsu.
## Database Location
```bash
opencode db path
# Returns: ~/.local/share/opencode/opencode.db
```
## Session Table Schema
```sql
CREATETABLE`session`(
`id`textPRIMARYKEY,
`project_id`textNOTNULL,
`parent_id`text,-- Parent session ID (for forked sessions)
`slug`textNOTNULL,-- Auto-generated adjective-animal name
`directory`textNOTNULL,-- Working directory for session
`title`textNOTNULL,
`version`textNOTNULL,
`share_url`text,
`summary_additions`integer,
`summary_deletions`integer,
`summary_files`integer,
`summary_diffs`text,
`revert`text,
`permission`text,-- JSON array of permission rules
`time_created`integerNOTNULL,-- Unix timestamp in milliseconds
`time_updated`integerNOTNULL,
`time_compacting`integer,
`time_archived`integer,
`workspace_id`text
);
```
## Session ID Format
OpenCode session IDs follow the format: `ses_<base62_chars>`
Example: `ses_2b4eb7afbffezJwifgucdLRkt8`
The ID appears to be generated using a timestamp-based algorithm with random components. Analysis of 118+ sessions shows:
- **No duplicate IDs** - Each session gets a unique ID even with concurrent forks
- **No sequential patterns** - IDs are not sequential even for sessions created milliseconds apart
- **Contains timestamp** - The first numeric portion appears to encode creation time
## Querying Sessions
### List all sessions
```bash
opencode session list
```
### Query database directly (requires sqlite3 or python)
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) |
| `QUEUE_DAEMON_INTERVAL_MINUTES` | 5 | How often daemon polls queue (in minutes) |
| `QUEUE_DAEMON_BATCH_SIZE` | 2 | How many tasks daemon picks per poll |
| `QUEUE_CLEANUP_AGE_DAYS` | 7 | Auto-cleanup completed/error items older than N days |
### 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 <key> <value> [agent]# Set a variable
kugetsu env get <key> [agent]# Get a variable value
kugetsu env rm <key> [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
@@ -50,6 +114,10 @@ Each issue session gets its own git worktree to prevent conflicts:
├── worktrees/
│ ├── github.com-shoko-kugetsu-14/ # Isolated workdir for issue #14
│ └── github.com-shoko-kugetsu-15/ # Isolated workdir for issue #15
├── queue/
│ ├── items/ # Queue item JSON files
│ ├── daemon.pid # Daemon process ID
│ └── daemon.log # Daemon log output
└── index.json # Maps session IDs and issue refs to session files
```
@@ -195,23 +263,152 @@ kugetsu destroy --base -y
**Note**: Destroying base also destroys PM agent since PM depends on base.
### kugetsu delegate `<message>`
Send a message to the PM agent for task coordination via queue:
@@ -2,14 +2,53 @@ You are a PM (Project Manager) for software development.
Your role is COORDINATOR. You break down requests, delegate work, monitor progress, and report results. You NEVER write code. Not even small fixes. Not even one-liners. Not even documentation. If asked to write code: delegate it using `kugetsu start`.
## Write Permissions: Strict Boundary
PM has EXPLICIT write boundaries. You can ONLY write to two specific locations.
### PM can ONLY write to:
-`~/.kugetsu/queue.json` - Queue state
-`~/.kugetsu/logs/*` - Your logs
### PM can NEVER write to (read-only):
-`~/.kugetsu/` - Everything else in this directory is read-only
-`repositories/*` - All repository code
-`skills/*` - All skill files, including PM skill files
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.