Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Stable Tmux Socket Directory** - Moved tmux sockets from `/tmp/tmux-{uid}/` to `~/.claudio/sockets/` via `TMUX_TMPDIR` to prevent macOS periodic `/tmp` cleanup from killing active tmux servers. `ListClaudioSockets` checks both locations for backward compatibility.

### Changed
- **Ship Experimental Features** - Graduated intelligent naming, terminal support, inline multiplan, inline ultraplan, and grouped instance view from experimental to default. These features are now always enabled without configuration. Only subprocess mode remains experimental.
- **Extract `createTmuxSession()` Helper** - Extracted duplicated tmux session setup from `Start()` and `StartWithResume()` into a reusable `createTmuxSession()` method, eliminating ~40 lines of duplication.
- **Extract `buildInstanceCallbacks()` Helper** - Consolidated duplicated callback wiring between `newInstanceManager` and `newInstanceManagerWithBackend` into a shared method to prevent sync bugs when adding new callbacks.
- **Log tmux session option errors** - Replaced silent `_ =` error discards in `createTmuxSession` and recovery paths with Debug/Warn-level logging for better diagnostics.
Expand Down
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ Press `:` to enter command mode for advanced operations:
| `:a "task"` | Add a new instance |
| `:plan "objective"` | Start inline plan generation |
| `:ultraplan "objective"` | Start inline ultraplan workflow |
| `:multiplan "objective"` | Multi-pass planning (requires experimental flag) |
| `:multiplan "objective"` | Multi-pass planning |
| `:tripleshot "task"` | Start tripleshot execution (aliases: `:triple`, `:3shot`) |
| `:adversarial-retry` | Restart stuck adversarial role |
| `:group create [name]` | Create a new instance group |
Expand Down Expand Up @@ -302,11 +302,7 @@ adversarial:

# Experimental features
experimental:
intelligent_naming: false
triple_shot: false
inline_plan: false
inline_ultraplan: false
grouped_instance_view: false
subprocess_mode: false
```

### Environment Variables
Expand Down
22 changes: 3 additions & 19 deletions docs/guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,31 +361,15 @@ Enable experimental features (disabled by default).

```yaml
experimental:
# Use Claude (Anthropic API) to generate descriptive instance names
intelligent_naming: false

# Spawn 3 parallel attempts, judge selects best
triple_shot: false

# Enable :multiplan command in TUI
inline_plan: false

# Enable :ultraplan command in TUI
inline_ultraplan: false

# Visual group organization in sidebar
grouped_instance_view: false
# Use stream-json subprocess backend instead of tmux
subprocess_mode: false
```

**Feature Descriptions:**

| Feature | Description |
|---------|-------------|
| `intelligent_naming` | Claude (Anthropic API) generates short names for instances based on task and output |
| `triple_shot` | Three parallel attempts per task with judge selection |
| `inline_plan` | Enables `:multiplan` command (`:plan` always available) |
| `inline_ultraplan` | Enables `:ultraplan` command in standard TUI |
| `grouped_instance_view` | Organizes instances by group in sidebar |
| `subprocess_mode` | Uses the stream-json subprocess backend instead of the default tmux backend |

---

Expand Down
29 changes: 1 addition & 28 deletions docs/guide/inline-planning.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
# Inline Planning (Experimental)
# Inline Planning

Inline planning brings the power of Plan and UltraPlan workflows directly into the standard Claudio TUI. Instead of running a separate command, you can create plans, organize tasks into groups, and execute them all from within your normal session.

> **Note:** This feature is experimental. Enable it via the `experimental.inline_plan` and `experimental.inline_ultraplan` configuration options.

## Overview

```
Expand All @@ -19,30 +17,6 @@ Inline planning brings the power of Plan and UltraPlan workflows directly into t
└─────────────────────────────────────────────────────────────────────┘
```

## Enabling Inline Planning

Add these options to your config file (`~/.config/claudio/config.yaml`):

```yaml
experimental:
# Enable :plan command in TUI
inline_plan: true

# Enable :ultraplan command in TUI
inline_ultraplan: true

# Enable visual group organization in sidebar
grouped_instance_view: true
```

Or set via environment variables:

```bash
export CLAUDIO_EXPERIMENTAL_INLINE_PLAN=true
export CLAUDIO_EXPERIMENTAL_INLINE_ULTRAPLAN=true
export CLAUDIO_EXPERIMENTAL_GROUPED_INSTANCE_VIEW=true
```

## Quick Start

```bash
Expand Down Expand Up @@ -307,7 +281,6 @@ Plans use JSON format compatible with the `claudio plan` command:

### Groups not displaying

- Ensure `experimental.grouped_instance_view` is enabled
- Toggle with `:group show` command
- Check that instances have group assignments

Expand Down
17 changes: 1 addition & 16 deletions docs/guide/tui-navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ Press `:` to enter command mode for advanced operations. Type a command and pres
| `:D` | Remove selected instance (with confirmation) |
| `:plan "objective"` | Start inline plan generation |
| `:ultraplan "objective"` | Start inline UltraPlan workflow |
| `:multiplan "objective"` | Multi-pass planning (requires `experimental.inline_plan`) |
| `:multiplan "objective"` | Multi-pass planning |
| `:tripleshot "task"` | Start TripleShot execution (aliases: `:triple`, `:3shot`) |
| `:adversarial-retry` | Restart a stuck adversarial implementer or reviewer |
| `:group create [name]` | Create a new instance group |
Expand All @@ -188,21 +188,6 @@ This starts the inline planning workflow:
3. You review and edit tasks in the plan editor
4. Confirm to spawn instances organized by groups

### Enabling Experimental Commands

Some commands require experimental flags in your config:

```yaml
# ~/.config/claudio/config.yaml
experimental:
inline_plan: true # Enables :multiplan
inline_ultraplan: true # Enables :ultraplan
triple_shot: true # Enables :tripleshot
grouped_instance_view: true # Enables :group commands
```

---

## Adding Instances

Press `a` to add a new instance:
Expand Down
28 changes: 5 additions & 23 deletions docs/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,29 +509,17 @@ Controls experimental features that may change or be removed. These features are

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `experimental.intelligent_naming` | bool | `false` | Use Claude (Anthropic API) to generate short, descriptive instance names |
| `experimental.triple_shot` | bool | `false` | Spawn three parallel instances and select the best solution |
| `experimental.inline_plan` | bool | `false` | Enable `:multiplan` command in the TUI (`:plan` is always available) |
| `experimental.inline_ultraplan` | bool | `false` | Enable `:ultraplan` command in the TUI |
| `experimental.grouped_instance_view` | bool | `false` | Enable visual group organization in the sidebar |
| `experimental.subprocess_mode` | bool | `false` | Use stream-json subprocess backend instead of tmux |

**Feature descriptions:**

| Feature | Description |
|---------|-------------|
| `intelligent_naming` | Uses Claude (Anthropic API) to generate short, descriptive instance names for the sidebar based on the task and Claude's initial output. Requires `ANTHROPIC_API_KEY`. |
| `triple_shot` | Spawns three parallel instances working on the same problem, then uses a judge instance to evaluate and select the best solution. |
| `inline_plan` | Enables the `:multiplan` command in the standard TUI for multi-pass planning with 3 planners + assessor. The `:plan` command is always available without this setting. |
| `inline_ultraplan` | Enables the `:ultraplan` command in the standard TUI, allowing you to start an UltraPlan workflow with parallel task execution. |
| `grouped_instance_view` | Organizes instances visually by execution group in the TUI sidebar. Related tasks are grouped together, with sub-groups for dependency chains. |
| `subprocess_mode` | Uses the stream-json subprocess backend instead of the default tmux backend for instance execution. |

```yaml
experimental:
intelligent_naming: false
triple_shot: false
inline_plan: false # enables :multiplan; :plan is always available
inline_ultraplan: false
grouped_instance_view: false
subprocess_mode: false
```

See the [Inline Planning Guide](../guide/inline-planning.md) for detailed usage of inline planning features.
Expand All @@ -556,9 +544,7 @@ Replace dots with underscores and use uppercase:
| `resources.cost_limit` | `CLAUDIO_RESOURCES_COST_LIMIT` |
| `ultraplan.max_parallel` | `CLAUDIO_ULTRAPLAN_MAX_PARALLEL` |
| `paths.worktree_dir` | `CLAUDIO_PATHS_WORKTREE_DIR` |
| `experimental.inline_plan` | `CLAUDIO_EXPERIMENTAL_INLINE_PLAN` |
| `experimental.inline_ultraplan` | `CLAUDIO_EXPERIMENTAL_INLINE_ULTRAPLAN` |
| `experimental.grouped_instance_view` | `CLAUDIO_EXPERIMENTAL_GROUPED_INSTANCE_VIEW` |
| `experimental.subprocess_mode` | `CLAUDIO_EXPERIMENTAL_SUBPROCESS_MODE` |

**Priority:** Environment variables override config file values.

Expand Down Expand Up @@ -681,11 +667,7 @@ ultraplan:

# Experimental features (disabled by default)
experimental:
intelligent_naming: false
triple_shot: false
inline_plan: false
inline_ultraplan: false
grouped_instance_view: false
subprocess_mode: false
```

---
Expand Down
2 changes: 0 additions & 2 deletions docs/reference/keyboard-shortcuts.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ These shortcuts use a vim-style `g` prefix. Press `g` first, then the action key
| `gr` | Retry failed tasks in current group |
| `gf` | Force-start next group (ignore dependencies) |

> **Note:** Group commands require `experimental.grouped_instance_view: true` in your config.

## Views

| Key | Action |
Expand Down
38 changes: 6 additions & 32 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,28 +370,10 @@ func (s *SparseCheckoutConfig) GetSparseDirectories() []string {

// ExperimentalConfig controls experimental features that may change or be removed
type ExperimentalConfig struct {
// IntelligentNaming uses Claude to generate short, descriptive instance names
// for the sidebar based on the task and Claude's initial output.
// Requires ANTHROPIC_API_KEY to be set. (default: false)
IntelligentNaming bool `mapstructure:"intelligent_naming"`

// TerminalSupport enables the embedded terminal pane feature.
// When enabled, :term, :t, and :termdir commands become available
// to interact with a terminal inside Claudio. (default: false)
TerminalSupport bool `mapstructure:"terminal_support"`

// InlinePlan enables the :plan command in the standard TUI, allowing users to
// start a Plan workflow directly from the main interface. (default: false)
InlinePlan bool `mapstructure:"inline_plan"`

// InlineUltraPlan enables the :ultraplan command in the standard TUI, allowing
// users to start an UltraPlan workflow directly from the main interface. (default: false)
InlineUltraPlan bool `mapstructure:"inline_ultraplan"`

// GroupedInstanceView enables visual grouping of instances by execution group
// in the TUI sidebar. Related tasks are organized together, with sub-groups
// for dependency chains. (default: false)
GroupedInstanceView bool `mapstructure:"grouped_instance_view"`
// SubprocessMode uses direct subprocess execution (claude --print --output-format stream-json)
// instead of tmux sessions for pipeline instances. This replaces screen scraping with typed
// NDJSON event parsing for more reliable completion detection. (default: false)
SubprocessMode bool `mapstructure:"subprocess_mode"`
}

// ResolveWorktreeDir returns the resolved worktree directory path.
Expand Down Expand Up @@ -535,11 +517,7 @@ func Default() *Config {
},
},
Experimental: ExperimentalConfig{
IntelligentNaming: false, // Disabled by default until stable
TerminalSupport: false, // Disabled by default until stable
InlinePlan: false, // Controls :multiplan only; :plan is always available
InlineUltraPlan: false, // Disabled by default until stable
GroupedInstanceView: false, // Disabled by default until stable
SubprocessMode: false, // Disabled by default until stable
},
}
}
Expand Down Expand Up @@ -667,11 +645,7 @@ func SetDefaults() {
viper.SetDefault("paths.sparse_checkout.cone_mode", defaults.Paths.SparseCheckout.ConeMode)

// Experimental defaults
viper.SetDefault("experimental.intelligent_naming", defaults.Experimental.IntelligentNaming)
viper.SetDefault("experimental.terminal_support", defaults.Experimental.TerminalSupport)
viper.SetDefault("experimental.inline_plan", defaults.Experimental.InlinePlan)
viper.SetDefault("experimental.inline_ultraplan", defaults.Experimental.InlineUltraPlan)
viper.SetDefault("experimental.grouped_instance_view", defaults.Experimental.GroupedInstanceView)
viper.SetDefault("experimental.subprocess_mode", defaults.Experimental.SubprocessMode)
}

// Load reads the configuration from viper into a Config struct and validates it
Expand Down
14 changes: 2 additions & 12 deletions internal/orchestrator/orchestrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -1532,19 +1532,9 @@ func (o *Orchestrator) initBudgetManager() {
}

// initNamer initializes the intelligent naming service.
// This is optional - requires both:
// 1. experimental.intelligent_naming config set to true
// 2. ANTHROPIC_API_KEY environment variable set
// If disabled or API key not set, instances use their original task as the display name.
// This is optional - requires ANTHROPIC_API_KEY environment variable set.
// If API key not set, instances use their original task as the display name.
func (o *Orchestrator) initNamer() {
// Check if intelligent naming is enabled in config
if o.config == nil || !o.config.Experimental.IntelligentNaming {
if o.logger != nil {
o.logger.Debug("intelligent naming disabled via config")
}
return
}

client, err := namer.NewAnthropicClient()
if err != nil {
// API key not set or other issue - namer won't be available
Expand Down
6 changes: 3 additions & 3 deletions internal/orchestrator/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ type Session struct {
Instances []*Instance `json:"instances"`

// Groups holds optional visual groupings of instances for the TUI.
// When GroupedInstanceView is enabled, instances are organized into groups
// rather than displayed as a flat list. Groups can have sub-groups for
// representing nested dependencies (e.g., in Plan/UltraPlan workflows).
// Instances are organized into groups rather than displayed as a flat list.
// Groups can have sub-groups for representing nested dependencies
// (e.g., in Plan/UltraPlan workflows).
// IMPORTANT: Always use thread-safe accessor methods (GetGroups, AddGroup, etc.)
// instead of direct access to avoid race conditions with TUI rendering.
Groups []*InstanceGroup `json:"groups,omitempty"`
Expand Down
6 changes: 3 additions & 3 deletions internal/orchestrator/session/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ type SessionData struct {
Instances []*InstanceData `json:"instances"`

// Groups holds optional visual groupings of instances for the TUI.
// When GroupedInstanceView is enabled, instances are organized into groups
// rather than displayed as a flat list. Groups can have sub-groups for
// representing nested dependencies (e.g., in Plan/UltraPlan workflows).
// Instances are organized into groups rather than displayed as a flat list.
// Groups can have sub-groups for representing nested dependencies
// (e.g., in Plan/UltraPlan workflows).
Groups []*InstanceGroup `json:"groups,omitempty"`

// UltraPlan holds the ultra-plan session state (nil for regular sessions)
Expand Down
31 changes: 0 additions & 31 deletions internal/tui/command/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"github.com/Iron-Ham/claudio/internal/orchestrator/workflows/tripleshot"
"github.com/Iron-Ham/claudio/internal/tui/msg"
tea "github.com/charmbracelet/bubbletea"
"github.com/spf13/viper"
)

// Dependencies defines the interface for dependencies that the CommandHandler needs.
Expand Down Expand Up @@ -777,25 +776,11 @@ func cmdFilter(_ Dependencies) Result {
return Result{FilterMode: &filterMode}
}

// terminalDisabledError is the error message when terminal support is disabled.
const terminalDisabledError = "Terminal support is disabled. Enable it in :config under Experimental"

// isTerminalEnabled checks if the experimental terminal support feature is enabled.
func isTerminalEnabled() bool {
return viper.GetBool("experimental.terminal_support")
}

func cmdTerminal(_ Dependencies) Result {
if !isTerminalEnabled() {
return Result{ErrorMessage: terminalDisabledError}
}
return Result{ToggleTerminal: true}
}

func cmdTerminalFocus(deps Dependencies) Result {
if !isTerminalEnabled() {
return Result{ErrorMessage: terminalDisabledError}
}
if deps.IsTerminalVisible() {
return Result{
EnterTerminalMode: true,
Expand All @@ -806,17 +791,11 @@ func cmdTerminalFocus(deps Dependencies) Result {
}

func cmdTerminalDirWorktree(_ Dependencies) Result {
if !isTerminalEnabled() {
return Result{ErrorMessage: terminalDisabledError}
}
mode := 1 // TerminalDirWorktree
return Result{TerminalDirMode: &mode}
}

func cmdTerminalDirProject(_ Dependencies) Result {
if !isTerminalEnabled() {
return Result{ErrorMessage: terminalDisabledError}
}
mode := 0 // TerminalDirProject (the directory where Claudio was started)
return Result{TerminalDirMode: &mode}
}
Expand Down Expand Up @@ -1099,11 +1078,6 @@ func cmdPlan(deps Dependencies) Result {
}

func cmdMultiPlan(deps Dependencies) Result {
// Check if inline plan is enabled in config (multiplan remains experimental)
if !viper.GetBool("experimental.inline_plan") {
return Result{ErrorMessage: "MultiPlan mode is disabled. Enable it in :config under Experimental"}
}

// Don't allow starting multiplan mode if already in ultraplan mode
if deps.IsUltraPlanMode() {
return Result{ErrorMessage: "Cannot start multiplan mode while in ultraplan mode"}
Expand All @@ -1126,11 +1100,6 @@ func cmdMultiPlan(deps Dependencies) Result {
// - :ultraplan --multi-pass [obj] - Use multi-pass planning
// - :ultraplan --plan <file> - Load existing plan file
func cmdUltraPlan(deps Dependencies, args string) Result {
// Check if inline ultraplan is enabled in config
if !viper.GetBool("experimental.inline_ultraplan") {
return Result{ErrorMessage: "UltraPlan mode is disabled. Enable it in :config under Experimental"}
}

// Don't allow starting another ultraplan if already in ultraplan mode
if deps.IsUltraPlanMode() {
return Result{ErrorMessage: "Already in ultraplan mode"}
Expand Down
Loading
Loading