From 84b19930aa87cbcd2d02521256f3d6aedc2aa5b7 Mon Sep 17 00:00:00 2001 From: Alexey Klimkin Date: Sun, 18 Jan 2026 13:36:30 -0800 Subject: [PATCH 1/2] feat(tool): expose OPENCODE_SESSION_ID to child processes Exposes the current opencode session ID to user-facing command execution contexts via the OPENCODE_SESSION_ID environment variable. This allows user scripts and tools (e.g., Ralph loop iterations) to correlate their logging and output with the specific opencode session they're running in. - bash tool: adds OPENCODE_SESSION_ID from ctx.sessionID to spawn env - prompt shell: adds OPENCODE_SESSION_ID from input.sessionID to spawn env - test: verifies env var is correctly passed to child processes --- packages/opencode/src/session/prompt.ts | 1 + packages/opencode/src/tool/bash.ts | 1 + packages/opencode/test/tool/bash.test.ts | 23 +++++++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index f4793d1a798..04354225ec7 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -1484,6 +1484,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the env: { ...process.env, TERM: "dumb", + OPENCODE_SESSION_ID: input.sessionID, }, }) diff --git a/packages/opencode/src/tool/bash.ts b/packages/opencode/src/tool/bash.ts index f3a1b04d431..9cdc87ef8d6 100644 --- a/packages/opencode/src/tool/bash.ts +++ b/packages/opencode/src/tool/bash.ts @@ -159,6 +159,7 @@ export const BashTool = Tool.define("bash", async () => { cwd, env: { ...process.env, + OPENCODE_SESSION_ID: ctx.sessionID, }, stdio: ["ignore", "pipe", "pipe"], detached: process.platform !== "win32", diff --git a/packages/opencode/test/tool/bash.test.ts b/packages/opencode/test/tool/bash.test.ts index 750ff8193e9..2f46c79327d 100644 --- a/packages/opencode/test/tool/bash.test.ts +++ b/packages/opencode/test/tool/bash.test.ts @@ -36,6 +36,29 @@ describe("tool.bash", () => { }, }) }) + + test("exposes OPENCODE_SESSION_ID environment variable", async () => { + await Instance.provide({ + directory: projectRoot, + fn: async () => { + const bash = await BashTool.init() + const sessionID = "session_abc123" + const testCtx = { + ...ctx, + sessionID, + } + const result = await bash.execute( + { + command: process.platform === "win32" ? "echo %OPENCODE_SESSION_ID%" : "echo $OPENCODE_SESSION_ID", + description: "Print session ID env var", + }, + testCtx, + ) + expect(result.metadata.exit).toBe(0) + expect(result.metadata.output.trim()).toBe(sessionID) + }, + }) + }) }) describe("tool.bash permissions", () => { From 391148ad8c62db2c69a17a39899270099e8b7619 Mon Sep 17 00:00:00 2001 From: Alexey Klimkin Date: Sun, 18 Jan 2026 13:36:30 -0800 Subject: [PATCH 2/2] feat(tool): expose OPENCODE_SESSION_TITLE to child processes Exposes the current opencode session title to user-facing command execution contexts via the OPENCODE_SESSION_TITLE environment variable. This allows user scripts and tools to reference the session name when logging or tracking work across multiple sessions. - bash tool: adds OPENCODE_SESSION_TITLE from session.title to spawn env - prompt shell: adds OPENCODE_SESSION_TITLE from session.title to spawn env - test: verifies OPENCODE_SESSION_TITLE env var is correctly passed - graceful fallback: session lookup errors don't prevent command execution --- packages/opencode/src/session/prompt.ts | 1 + packages/opencode/src/tool/bash.ts | 9 ++++++++ packages/opencode/test/tool/bash.test.ts | 26 ++++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 04354225ec7..fc4f7e86578 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -1485,6 +1485,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the ...process.env, TERM: "dumb", OPENCODE_SESSION_ID: input.sessionID, + OPENCODE_SESSION_TITLE: session.title, }, }) diff --git a/packages/opencode/src/tool/bash.ts b/packages/opencode/src/tool/bash.ts index 9cdc87ef8d6..a7204ae52a3 100644 --- a/packages/opencode/src/tool/bash.ts +++ b/packages/opencode/src/tool/bash.ts @@ -16,6 +16,7 @@ import { Shell } from "@/shell/shell" import { BashArity } from "@/permission/arity" import { Truncate } from "./truncation" +import { Session } from "@/session" const MAX_METADATA_LENGTH = 30_000 const DEFAULT_TIMEOUT = Flag.OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS || 2 * 60 * 1000 @@ -154,12 +155,20 @@ export const BashTool = Tool.define("bash", async () => { }) } + const session = await (async () => { + try { + return await Session.get(ctx.sessionID) + } catch { + return undefined + } + })() const proc = spawn(params.command, { shell, cwd, env: { ...process.env, OPENCODE_SESSION_ID: ctx.sessionID, + ...(session?.title && { OPENCODE_SESSION_TITLE: session.title }), }, stdio: ["ignore", "pipe", "pipe"], detached: process.platform !== "win32", diff --git a/packages/opencode/test/tool/bash.test.ts b/packages/opencode/test/tool/bash.test.ts index 2f46c79327d..a8a5a4624b6 100644 --- a/packages/opencode/test/tool/bash.test.ts +++ b/packages/opencode/test/tool/bash.test.ts @@ -5,6 +5,7 @@ import { Instance } from "../../src/project/instance" import { tmpdir } from "../fixture/fixture" import type { PermissionNext } from "../../src/permission/next" import { Truncate } from "../../src/tool/truncation" +import { Session } from "../../src/session" const ctx = { sessionID: "test", @@ -59,6 +60,31 @@ describe("tool.bash", () => { }, }) }) + + test("exposes OPENCODE_SESSION_TITLE environment variable", async () => { + await Instance.provide({ + directory: projectRoot, + fn: async () => { + const title = "My Custom Session Title" + const session = await Session.create({ title }) + const bash = await BashTool.init() + const testCtx = { + ...ctx, + sessionID: session.id, + } + const result = await bash.execute( + { + command: process.platform === "win32" ? "echo %OPENCODE_SESSION_TITLE%" : "echo $OPENCODE_SESSION_TITLE", + description: "Print session title env var", + }, + testCtx, + ) + expect(result.metadata.exit).toBe(0) + expect(result.metadata.output.trim()).toBe(title) + await Session.remove(session.id) + }, + }) + }) }) describe("tool.bash permissions", () => {