From 6942847abc546e390a167f7efe2330edae83134c Mon Sep 17 00:00:00 2001 From: Chris Buryta Date: Fri, 10 Apr 2026 23:39:55 -0400 Subject: [PATCH 1/2] feat(cli): inject codebase env vars for bash nodes Bash nodes in CLI workflows were not receiving codebase env vars from the database. After codebase resolution, load env vars and merge into process.env so all child processes (bash and AI nodes) inherit them. --- packages/cli/src/commands/workflow.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/cli/src/commands/workflow.ts b/packages/cli/src/commands/workflow.ts index 89dd5911e4..068359278e 100644 --- a/packages/cli/src/commands/workflow.ts +++ b/packages/cli/src/commands/workflow.ts @@ -30,6 +30,7 @@ import { } from '@archon/core/operations/workflow-operations'; import * as conversationDb from '@archon/core/db/conversations'; import * as codebaseDb from '@archon/core/db/codebases'; +import * as envVarDb from '@archon/core/db/env-vars'; import * as isolationDb from '@archon/core/db/isolation-environments'; import * as messageDb from '@archon/core/db/messages'; import * as workflowDb from '@archon/core/db/workflows'; @@ -591,6 +592,25 @@ export async function workflowRunCommand( renderWorkflowEvent(event, verbose ?? false); }); + // Inject codebase env vars into process.env so bash nodes inherit them. + // AI nodes already receive them via the Claude SDK client, but bash nodes + // are spawned directly and only see process.env. + if (codebase) { + try { + const codebaseEnvVars = await envVarDb.getCodebaseEnvVars(codebase.id); + const injectedCount = Object.keys(codebaseEnvVars).length; + if (injectedCount > 0) { + Object.assign(process.env, codebaseEnvVars); + getLog().info({ codebaseId: codebase.id, injectedCount }, 'cli.codebase_env_vars_injected'); + } + } catch (error) { + getLog().warn( + { err: error as Error, codebaseId: codebase.id }, + 'cli.codebase_env_vars_load_failed' + ); + } + } + // Execute workflow with workingCwd (may be worktree path) let result: Awaited>; try { From 108addfb5a6a2458f9b35a4dd8eac7cc4826f61a Mon Sep 17 00:00:00 2001 From: Chris Buryta Date: Sat, 11 Apr 2026 21:27:14 -0400 Subject: [PATCH 2/2] fix(cli): restore process.env after codebase env var injection Snapshot injected env var keys before mutation and restore previous values in a finally block after workflow execution completes. Prevents env var bleed if workflowRunCommand is ever called multiple times in the same process (e.g. future long-lived process reuse). --- packages/cli/src/commands/workflow.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/cli/src/commands/workflow.ts b/packages/cli/src/commands/workflow.ts index 068359278e..92a93c70ac 100644 --- a/packages/cli/src/commands/workflow.ts +++ b/packages/cli/src/commands/workflow.ts @@ -595,11 +595,16 @@ export async function workflowRunCommand( // Inject codebase env vars into process.env so bash nodes inherit them. // AI nodes already receive them via the Claude SDK client, but bash nodes // are spawned directly and only see process.env. + // Snapshot previous values so we can restore after execution. + const previousEnvForInjectedKeys: Record = {}; if (codebase) { try { const codebaseEnvVars = await envVarDb.getCodebaseEnvVars(codebase.id); const injectedCount = Object.keys(codebaseEnvVars).length; if (injectedCount > 0) { + for (const key of Object.keys(codebaseEnvVars)) { + previousEnvForInjectedKeys[key] = process.env[key]; + } Object.assign(process.env, codebaseEnvVars); getLog().info({ codebaseId: codebase.id, injectedCount }, 'cli.codebase_env_vars_injected'); } @@ -625,6 +630,14 @@ export async function workflowRunCommand( codebase?.id ); } finally { + // Restore process.env to its pre-injection state + for (const [key, previousValue] of Object.entries(previousEnvForInjectedKeys)) { + if (previousValue === undefined) { + Reflect.deleteProperty(process.env, key); + } else { + process.env[key] = previousValue; + } + } unsubscribe?.(); }