diff --git a/frontend/src/components/workflows/AgentCodeInspector.test.tsx b/frontend/src/components/workflows/AgentCodeInspector.test.tsx
index 0ffb68c94..22771dfed 100644
--- a/frontend/src/components/workflows/AgentCodeInspector.test.tsx
+++ b/frontend/src/components/workflows/AgentCodeInspector.test.tsx
@@ -144,6 +144,28 @@ describe("AgentCodeInspector", () => {
expect(onConfigChange).toHaveBeenCalledWith({ harness: "codex-cli", approvalConversationId: "conv1" });
});
+ it("shows and edits the primary repository's base ref as an expression-capable input", () => {
+ const onInputsChange = vi.fn();
+ render();
+
+ expect(screen.getByText("Base ref / 基础分支")).toBeInTheDocument();
+ const input = screen.getByLabelText("Default branch");
+ expect(input).toHaveValue("{{trigger.sourceBranch}}");
+
+ fireEvent.change(input, { target: { value: "release/2.x" } });
+
+ expect(onInputsChange).toHaveBeenCalledWith({ repositoryId: "p1", baseRef: "release/2.x" });
+ });
+
+ it("preserves baseRef when the repository workspace changes", () => {
+ const onInputsChange = vi.fn();
+ render();
+
+ fireEvent.click(screen.getByText("add-row"));
+
+ expect(onInputsChange).toHaveBeenCalledWith(expect.objectContaining({ baseRef: "release/2.x" }));
+ });
+
// The picker's blank-row channel: "Add a repository" creates a row with an empty id, which neither
// repositoryId nor relatedRepositories can carry. Both directions of the wiring must therefore survive —
// feed drafts DOWN, and hand the emitted drafts back UP on onChange. Dropping either end makes the click a
diff --git a/frontend/src/components/workflows/AgentCodeInspector.tsx b/frontend/src/components/workflows/AgentCodeInspector.tsx
index 0ac86f85c..dba360d99 100644
--- a/frontend/src/components/workflows/AgentCodeInspector.tsx
+++ b/frontend/src/components/workflows/AgentCodeInspector.tsx
@@ -40,6 +40,7 @@ export function AgentCodeInspector({ config, inputs, onConfigChange, onInputsCha
const credentialId = str(config.modelCredentialId);
const credentialedModelId = str(config.modelCredentialModelId);
const repositoryId = str(inputs.repositoryId);
+ const baseRef = str(inputs.baseRef);
const approvalConversationId = str(config.approvalConversationId);
const timeoutSeconds = typeof config.timeoutSeconds === "number" ? config.timeoutSeconds : undefined;
const network = config.network === true;
@@ -187,6 +188,17 @@ export function AgentCodeInspector({ config, inputs, onConfigChange, onInputsCha
The first repo is the primary — the writable workspace root the agent runs in. Add more to clone alongside it for a coordinated change (e.g. a frontend + its backend).
+
+