Skip to content

Conversation

@renekris
Copy link
Owner

@renekris renekris commented Jan 4, 2026

Summary

Implements issue #19: Add --ci flag for non-interactive shuvcode execution with automatic permission handling.

Features Added

  1. Prompt Passing System

    • PromptPreset enum: RALPH_LOOP, STANDARD_OOTL, MINIMAL
    • PROMPT_PRESETS dict with detailed instructions for each preset
    • Priority order: CLI flag > env var > WT-TASK.md > None
  2. CLI Flags

    • --agent-prompt: Custom prompt override
    • --agent-preset ralph-loop|standard-ootl|minimal: Preset selection
    • --no-prompt: Disable prompt passing (old behavior)
    • --ci: Non-interactive mode with auto-permissions
  3. Configuration

    • Added prompt settings to WorktreeSettings
    • Model validator for mutually exclusive prompt flags
    • CLI-level validation: --ci and --no-prompt cannot be used together
  4. Core Logic

    • _resolve_shuvcode_prompt(): Implements priority order
    • _open_shuvcode(): Supports 3 modes:
      • CI mode: shuvcode run "<prompt>" + OPENCODE_PERMISSION='{"*":"allow"}'
      • Normal mode: shuvcode <path> --prompt "<prompt>"
      • No prompt: shuvcode <path> (old behavior)
  5. Testing

    • 9 tests covering all prompt resolution scenarios
    • Tests verify command generation and environment variable setting
    • New test validates CI mode env var
  6. Documentation

    • Updated README with usage examples
    • CI/CD integration examples (GitHub Actions, GitLab CI)
    • Note about automatic OPENCODE_PERMISSION setting

CI Mode Behavior

When --ci flag is used:

# Uses non-interactive execution with auto-permissions
ghwt 42 --issue --ci
# → shuvcode run "WT-TASK.md" + OPENCODE_PERMISSION='{"*":"allow"}'

Key benefits:

  • No TUI interface (uses shuvcode run)
  • Auto-approves all operations via OPENCODE_PERMISSION environment variable
  • Perfect for CI/CD pipelines and automated workflows

Usage Examples

# CI mode - fully non-interactive
ghwt 42 --issue --ci

# CI mode with custom prompt
ghwt 42 --issue --ci --agent-prompt "Execute specific task"

# CI mode with preset
ghwt 42 --issue --ci --agent-preset ralph-loop

# Normal interactive mode with prompt
ghwt 42 --issue --agent-prompt "Custom instructions"

# No prompt (old behavior)
ghwt 42 --issue --no-prompt

Test Results

tests/unit/test_prompt_passing.py: 9/9 passed ✅
tests/unit/test_config.py: 11/11 passed ✅
Full test suite: 87/89 passed (2 pre-existing failures) ✅
Code quality: ruff checks pass ✅

Files Modified

  • config.py: Added enums, presets, validators
  • main.py: Added CLI flags and validation
  • worktree_creator.py: Added prompt resolution and CI mode
  • tests/unit/test_prompt_passing.py: 9 new tests
  • tests/unit/test_config.py: 11 validation tests
  • README.md: Documentation and examples

Issue #20 Closure

Issue #20 (YOLO flag) has been closed as redundant. The --ci flag implemented in this PR provides the requested autonomous execution functionality:

  • --ci uses non-interactive shuvcode run command
  • OPENCODE_PERMISSION='{"*":"allow"}' auto-approves all operations
  • Users wanting custom autonomous behavior can use --ci --agent-prompt

Separate --yolo flag would duplicate functionality without adding value.

Acceptance Criteria

  • ✅ WT-TASK.md content is automatically passed to shuvcode
  • --agent-prompt flag overrides WT-TASK.md content
  • --no-prompt flag disables prompt passing (current behavior)
  • GHWT_AGENT_INIT_PROMPT environment variable is respected
  • GHWT_AGENT_INIT_PRESET environment variable selects predefined preset
  • ✅ Shuvcode opens with prompt pre-loaded using --prompt flag
  • ✅ Tests verify prompt passing to shuvcode subprocess
  • ✅ Documentation includes all usage patterns and CI/CD examples
  • ✅ CI mode sets OPENCODE_PERMISSION environment variable for non-interactive execution

Closes #19
Related: Closed #20

Implements issue #19: Add --ci flag for non-interactive
shuvcode execution with automatic permission approval.

Changes:
- Add PromptPreset enum and PROMPT_PRESETS dict (RALPH_LOOP, STANDARD_OOTL, MINIMAL)
- Add prompt settings to WorktreeSettings (agent_prompt, agent_prompt_preset, no_prompt, ci_mode)
- Add CLI flags: --agent-prompt, --agent-preset, --no-prompt, --ci
- Implement _resolve_shuvcode_prompt() with priority order (CLI > env var > WT-TASK.md)
- Modify _open_shuvcode() to support CI mode with OPENCODE_PERMISSION env var
- Add comprehensive tests: 9 prompt passing tests, 11 validation tests
- Update README with usage examples and CI/CD integration

CI Mode Behavior:
- Uses "shuvcode run" command instead of interactive TUI
- Sets OPENCODE_PERMISSION='{"*":"allow"}' to auto-approve all operations
- Perfect for CI/CD pipelines and automated workflows

Testing:
- 9/9 prompt passing tests pass
- 11/11 validation tests pass
- 87/89 total tests pass (2 pre-existing failures unrelated to changes)

Closes #19
Related: Closed #20 (yolo flag - functionality covered by --ci)
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 7 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="README.md">

<violation number="1" location="README.md:163">
P2: Documentation inaccuracy: `--no-prompt` is listed as priority item 5, but it&#39;s actually a bypass flag that disables prompt passing entirely, not a fallback. According to the code, item 5 should be &quot;None (no prompt passed)&quot; when no source is configured. Consider: `5. None (if no prompt source is configured)`

Then add a separate note: &quot;Use `--no-prompt` to explicitly disable prompt passing.&quot;</violation>
</file>

<file name="config.py">

<violation number="1" location="config.py:154">
P2: Error message is misleading when only 2 of 3 mutually exclusive flags are used. The message implies all three are provided together, but the validation triggers for any 2+ flags. Consider a clearer message like &quot;Only one of --agent-prompt, --agent-preset, or --no-prompt can be specified&quot;.</violation>
</file>

<file name="worktree_creator.py">

<violation number="1" location="worktree_creator.py:548">
P3: Dead code: The `no_prompt` check here will never be True because `_resolve_shuvcode_prompt` is only called when `no_prompt` is False (checked in `_open_shuvcode` before calling). This block should be removed.</violation>

<violation number="2" location="worktree_creator.py:588">
P1: CI mode doesn&#39;t pass `worktree_path` to shuvcode. Unlike other modes that pass the path as an argument, CI mode runs `shuvcode run &lt;prompt&gt;` without any directory context. Consider passing the worktree path or setting `cwd=worktree_path` in the subprocess call.</violation>

<violation number="3" location="worktree_creator.py:600">
P2: Logging the full command may expose large or sensitive prompt content. In CI mode, `cmd` includes the entire prompt which could be the full WT-TASK.md content. Consider logging only the command structure or truncating the prompt.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

2. `GHWT_AGENT_INIT_PROMPT` environment variable
3. `--agent-preset` CLI flag or `GHWT_AGENT_INIT_PRESET` environment variable
4. WT-TASK.md file content (default)
5. No prompt (`--no-prompt` flag)
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Documentation inaccuracy: --no-prompt is listed as priority item 5, but it's actually a bypass flag that disables prompt passing entirely, not a fallback. According to the code, item 5 should be "None (no prompt passed)" when no source is configured. Consider: 5. None (if no prompt source is configured)

Then add a separate note: "Use --no-prompt to explicitly disable prompt passing."

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At README.md, line 163:

<comment>Documentation inaccuracy: `--no-prompt` is listed as priority item 5, but it&#39;s actually a bypass flag that disables prompt passing entirely, not a fallback. According to the code, item 5 should be &quot;None (no prompt passed)&quot; when no source is configured. Consider: `5. None (if no prompt source is configured)`

Then add a separate note: &quot;Use `--no-prompt` to explicitly disable prompt passing.&quot;</comment>

<file context>
@@ -97,6 +97,71 @@ export WORKTREE_ROOT=/path/to/worktrees
+2. `GHWT_AGENT_INIT_PROMPT` environment variable
+3. `--agent-preset` CLI flag or `GHWT_AGENT_INIT_PRESET` environment variable
+4. WT-TASK.md file content (default)
+5. No prompt (`--no-prompt` flag)
+
 ### Output
</file context>
Suggested change
5. No prompt (`--no-prompt` flag)
5. None (no prompt if nothing configured)
**Note:** Use `--no-prompt` to explicitly disable prompt passing entirely.
Fix with Cubic

active_flags = [f for f in prompt_flags if f]
if len(active_flags) > 1:
raise ValueError(
"Cannot use --agent-prompt, --agent-preset, and --no-prompt together"
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Error message is misleading when only 2 of 3 mutually exclusive flags are used. The message implies all three are provided together, but the validation triggers for any 2+ flags. Consider a clearer message like "Only one of --agent-prompt, --agent-preset, or --no-prompt can be specified".

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At config.py, line 154:

<comment>Error message is misleading when only 2 of 3 mutually exclusive flags are used. The message implies all three are provided together, but the validation triggers for any 2+ flags. Consider a clearer message like &quot;Only one of --agent-prompt, --agent-preset, or --no-prompt can be specified&quot;.</comment>

<file context>
@@ -56,10 +111,50 @@ class WorktreeSettings(BaseSettings):
+        active_flags = [f for f in prompt_flags if f]
+        if len(active_flags) &gt; 1:
+            raise ValueError(
+                &quot;Cannot use --agent-prompt, --agent-preset, and --no-prompt together&quot;
+            )
+        if self.ci_mode and self.no_prompt:
</file context>
Suggested change
"Cannot use --agent-prompt, --agent-preset, and --no-prompt together"
"Only one of --agent-prompt, --agent-preset, or --no-prompt can be specified"
Fix with Cubic

cmd = ["shuvcode", str(worktree_path), "--prompt", prompt]
env = None # Use parent process environment

self.logger.debug("Executing shuvcode command", command=" ".join(cmd))
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Logging the full command may expose large or sensitive prompt content. In CI mode, cmd includes the entire prompt which could be the full WT-TASK.md content. Consider logging only the command structure or truncating the prompt.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At worktree_creator.py, line 600:

<comment>Logging the full command may expose large or sensitive prompt content. In CI mode, `cmd` includes the entire prompt which could be the full WT-TASK.md content. Consider logging only the command structure or truncating the prompt.</comment>

<file context>
@@ -477,13 +569,44 @@ def _open_shuvcode(self, worktree_path: Path) -&gt; None:
+                cmd = [&quot;shuvcode&quot;, str(worktree_path), &quot;--prompt&quot;, prompt]
+                env = None  # Use parent process environment
+
+        self.logger.debug(&quot;Executing shuvcode command&quot;, command=&quot; &quot;.join(cmd))
 
-        with contextlib.suppress(subprocess.CalledProcessError, FileNotFoundError, subprocess.TimeoutExpired):
</file context>
Suggested change
self.logger.debug("Executing shuvcode command", command=" ".join(cmd))
self.logger.debug(
"Executing shuvcode command",
command=cmd[0],
subcommand=cmd[1] if len(cmd) > 1 else None,
prompt_length=len(cmd[2]) if len(cmd) > 2 and cmd[1] == "run" else None,
)
Fix with Cubic

self.logger.info(
"Opening shuvcode in CI mode", prompt_length=len(prompt)
)
cmd = ["shuvcode", "run", prompt]
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: CI mode doesn't pass worktree_path to shuvcode. Unlike other modes that pass the path as an argument, CI mode runs shuvcode run <prompt> without any directory context. Consider passing the worktree path or setting cwd=worktree_path in the subprocess call.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At worktree_creator.py, line 588:

<comment>CI mode doesn&#39;t pass `worktree_path` to shuvcode. Unlike other modes that pass the path as an argument, CI mode runs `shuvcode run &lt;prompt&gt;` without any directory context. Consider passing the worktree path or setting `cwd=worktree_path` in the subprocess call.</comment>

<file context>
@@ -477,13 +569,44 @@ def _open_shuvcode(self, worktree_path: Path) -&gt; None:
+                self.logger.info(
+                    &quot;Opening shuvcode in CI mode&quot;, prompt_length=len(prompt)
+                )
+                cmd = [&quot;shuvcode&quot;, &quot;run&quot;, prompt]
+                # Set OPENCODE_PERMISSION to auto-allow all operations in CI
+                env = os.environ.copy()
</file context>
Fix with Cubic

return content

# Priority 4: No prompt (--no-prompt or file missing)
if self.settings.no_prompt:
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Dead code: The no_prompt check here will never be True because _resolve_shuvcode_prompt is only called when no_prompt is False (checked in _open_shuvcode before calling). This block should be removed.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At worktree_creator.py, line 548:

<comment>Dead code: The `no_prompt` check here will never be True because `_resolve_shuvcode_prompt` is only called when `no_prompt` is False (checked in `_open_shuvcode` before calling). This block should be removed.</comment>

<file context>
@@ -458,13 +496,67 @@ def _write_task_file(
+            return content
+
+        # Priority 4: No prompt (--no-prompt or file missing)
+        if self.settings.no_prompt:
+            self.logger.debug(&quot;No prompt (no-prompt flag set)&quot;)
+
</file context>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Add --ci or --non-interactive-env option for opencode/shuvcode direct prompt [Feature] Add --yolo flag for autonomous agent execution

2 participants