@@ -113,6 +113,7 @@ type commandRunner interface {
113113 SetStderr (io.Writer )
114114 SetDir (string )
115115 SetEnv (env map [string ]string )
116+ UnsetEnv (keys ... string )
116117 Process () processHandle
117118}
118119
@@ -221,6 +222,33 @@ func (r *realCmd) SetEnv(env map[string]string) {
221222 r .cmd .Env = out
222223}
223224
225+ func (r * realCmd ) UnsetEnv (keys ... string ) {
226+ if r == nil || r .cmd == nil || len (keys ) == 0 {
227+ return
228+ }
229+ // If cmd.Env is nil, Go inherits all parent env vars.
230+ // Populate explicitly so we can selectively remove keys.
231+ if r .cmd .Env == nil {
232+ r .cmd .Env = os .Environ ()
233+ }
234+ drop := make (map [string ]struct {}, len (keys ))
235+ for _ , k := range keys {
236+ drop [k ] = struct {}{}
237+ }
238+ filtered := make ([]string , 0 , len (r .cmd .Env ))
239+ for _ , kv := range r .cmd .Env {
240+ idx := strings .IndexByte (kv , '=' )
241+ name := kv
242+ if idx >= 0 {
243+ name = kv [:idx ]
244+ }
245+ if _ , ok := drop [name ]; ! ok {
246+ filtered = append (filtered , kv )
247+ }
248+ }
249+ r .cmd .Env = filtered
250+ }
251+
224252func (r * realCmd ) Process () processHandle {
225253 if r == nil || r .cmd == nil || r .cmd .Process == nil {
226254 return nil
@@ -1126,6 +1154,13 @@ func RunCodexTaskWithContext(parentCtx context.Context, taskSpec TaskSpec, backe
11261154
11271155 injectTempEnv (cmd )
11281156
1157+ // Claude Code sets CLAUDECODE=1 in its child processes. If we don't
1158+ // remove it, the spawned `claude -p` detects the variable and refuses
1159+ // to start ("cannot be launched inside another Claude Code session").
1160+ if commandName == "claude" {
1161+ cmd .UnsetEnv ("CLAUDECODE" )
1162+ }
1163+
11291164 // For backends that don't support -C flag (claude, gemini), set working directory via cmd.Dir
11301165 // Codex passes workdir via -C flag, so we skip setting Dir for it to avoid conflicts
11311166 if cfg .Mode != "resume" && commandName != "codex" && cfg .WorkDir != "" {
0 commit comments