on main help sign in
allow configuring shell (#157)
e8b4bb0Ed Zynda
README.md+22
@@ -96,6 +96,24 @@ You can configure OpenCode using environment variables:
96| `AZURE_OPENAI_ENDPOINT` | For Azure OpenAI models |
96| `AZURE_OPENAI_ENDPOINT` | For Azure OpenAI models |
97| `AZURE_OPENAI_API_KEY` | For Azure OpenAI models (optional when using Entra ID) |
97| `AZURE_OPENAI_API_KEY` | For Azure OpenAI models (optional when using Entra ID) |
98| `AZURE_OPENAI_API_VERSION` | For Azure OpenAI models |
98| `AZURE_OPENAI_API_VERSION` | For Azure OpenAI models |
99+| `SHELL` | Default shell to use (if not specified in config) |
100+
101+### Shell Configuration
102+
103+OpenCode allows you to configure the shell used by the bash tool. By default, it uses the shell specified in the `SHELL` environment variable, or falls back to `/bin/bash` if not set.
104+
105+You can override this in your configuration file:
106+
107+```json
108+{
109+ "shell": {
110+ "path": "/bin/zsh",
111+ "args": ["-l"]
112+ }
113+}
114+```
115+
116+This is useful if you want to use a different shell than your default system shell, or if you need to pass specific arguments to the shell.
99
117
100### Configuration File Structure
118### Configuration File Structure
101
119
@@ -136,6 +154,10 @@ You can configure OpenCode using environment variables:
136 "maxTokens": 80
154 "maxTokens": 80
137 }
155 }
138 },
156 },
157+ "shell": {
158+ "path": "/bin/bash",
159+ "args": ["-l"]
160+ },
139 "mcpServers": {
161 "mcpServers": {
140 "example": {
162 "example": {
141 "type": "stdio",
163 "type": "stdio",
internal/config/config.go+15
@@ -73,6 +73,12 @@ type TUIConfig struct {
73 Theme string `json:"theme,omitempty"`
73 Theme string `json:"theme,omitempty"`
74}
74}
75
75
76+// ShellConfig defines the configuration for the shell used by the bash tool.
77+type ShellConfig struct {
78+ Path string `json:"path,omitempty"`
79+ Args []string `json:"args,omitempty"`
80+}
81+
76// Config is the main configuration structure for the application.
82// Config is the main configuration structure for the application.
77type Config struct {
83type Config struct {
78 Data Data `json:"data"`
84 Data Data `json:"data"`
@@ -85,6 +91,7 @@ type Config struct {
85 DebugLSP bool `json:"debugLSP,omitempty"`
91 DebugLSP bool `json:"debugLSP,omitempty"`
86 ContextPaths []string `json:"contextPaths,omitempty"`
92 ContextPaths []string `json:"contextPaths,omitempty"`
87 TUI TUIConfig `json:"tui"`
93 TUI TUIConfig `json:"tui"`
94+ Shell ShellConfig `json:"shell,omitempty"`
88 AutoCompact bool `json:"autoCompact,omitempty"`
95 AutoCompact bool `json:"autoCompact,omitempty"`
89}
96}
90
97
@@ -217,6 +224,14 @@ func setDefaults(debug bool) {
217 viper.SetDefault("tui.theme", "opencode")
224 viper.SetDefault("tui.theme", "opencode")
218 viper.SetDefault("autoCompact", true)
225 viper.SetDefault("autoCompact", true)
219
226
227+ // Set default shell from environment or fallback to /bin/bash
228+ shellPath := os.Getenv("SHELL")
229+ if shellPath == "" {
230+ shellPath = "/bin/bash"
231+ }
232+ viper.SetDefault("shell.path", shellPath)
233+ viper.SetDefault("shell.args", []string{"-l"})
234+
220 if debug {
235 if debug {
221 viper.SetDefault("debug", true)
236 viper.SetDefault("debug", true)
222 viper.Set("log.level", "debug")
237 viper.Set("log.level", "debug")
internal/llm/tools/shell/shell.go+24−3
@@ -11,6 +11,8 @@ import (
11 "sync"
11 "sync"
12 "syscall"
12 "syscall"
13 "time"
13 "time"
14+
15+ "github.com/opencode-ai/opencode/internal/config"
14)
16)
15
17
16type PersistentShell struct {
18type PersistentShell struct {
@@ -57,12 +59,31 @@ func GetPersistentShell(workingDir string) *PersistentShell {
57}
59}
58
60
59func newPersistentShell(cwd string) *PersistentShell {
61func newPersistentShell(cwd string) *PersistentShell {
60− shellPath := os.Getenv("SHELL")
62+ // Get shell configuration from config
63+ cfg := config.Get()
64+
65+ // Default to environment variable if config is not set or nil
66+ var shellPath string
67+ var shellArgs []string
68+
69+ if cfg != nil {
70+ shellPath = cfg.Shell.Path
71+ shellArgs = cfg.Shell.Args
72+ }
73+
61 if shellPath == "" {
74 if shellPath == "" {
62− shellPath = "/bin/bash"
75+ shellPath = os.Getenv("SHELL")
76+ if shellPath == "" {
77+ shellPath = "/bin/bash"
78+ }
79+ }
80+
81+ // Default shell args
82+ if len(shellArgs) == 0 {
83+ shellArgs = []string{"-l"}
63 }
84 }
64
85
65− cmd := exec.Command(shellPath, "-l")
86+ cmd := exec.Command(shellPath, shellArgs...)
66 cmd.Dir = cwd
87 cmd.Dir = cwd
67
88
68 stdinPipe, err := cmd.StdinPipe()
89 stdinPipe, err := cmd.StdinPipe()