diff --git a/apps/web/hooks/domains/kanban/use-kanban-data.ts b/apps/web/hooks/domains/kanban/use-kanban-data.ts
index 8b37eee385..3922b8c023 100644
--- a/apps/web/hooks/domains/kanban/use-kanban-data.ts
+++ b/apps/web/hooks/domains/kanban/use-kanban-data.ts
@@ -71,6 +71,7 @@ export function useKanbanData({
description: task.description,
position: task.position,
repositoryId: task.repositoryId,
+ repositories: task.repositories,
primarySessionId: task.primarySessionId,
sessionCount: task.sessionCount,
reviewStatus: task.reviewStatus,
diff --git a/apps/web/hooks/domains/kanban/use-task-repositories.ts b/apps/web/hooks/domains/kanban/use-task-repositories.ts
index ba1bd807a8..b86ef74a86 100644
--- a/apps/web/hooks/domains/kanban/use-task-repositories.ts
+++ b/apps/web/hooks/domains/kanban/use-task-repositories.ts
@@ -3,7 +3,14 @@
import { useMemo } from "react";
import { useAppStore } from "@/components/state-provider";
import type { KanbanState } from "@/lib/state/slices";
-import { primaryTaskRepository, type TaskRepository } from "@/lib/types/http";
+
+/**
+ * Slim per-task repository shape carried in the kanban store. Mirrors
+ * KanbanState["tasks"][number]["repositories"][number].
+ */
+export type KanbanTaskRepository = NonNullable<
+ KanbanState["tasks"][number]["repositories"]
+>[number];
/**
* Returns the repositories linked to a task, ordered by Position. Empty
@@ -11,7 +18,7 @@ import { primaryTaskRepository, type TaskRepository } from "@/lib/types/http";
* use this instead of poking task.repositories directly so multi-repo
* consumers all share one source of truth.
*/
-export function useTaskRepositories(taskId: string | null | undefined): TaskRepository[] {
+export function useTaskRepositories(taskId: string | null | undefined): KanbanTaskRepository[] {
const task = useAppStore((state) =>
taskId
? (state.kanban.tasks.find((t: KanbanState["tasks"][number]) => t.id === taskId) ?? null)
@@ -28,7 +35,7 @@ export function useTaskRepositories(taskId: string | null | undefined): TaskRepo
*/
export function useTaskPrimaryRepository(
taskId: string | null | undefined,
-): TaskRepository | null {
+): KanbanTaskRepository | null {
const repos = useTaskRepositories(taskId);
- return primaryTaskRepository(repos) ?? null;
+ return repos.length > 0 ? repos[0] : null;
}
diff --git a/apps/web/lib/ssr/mapper.ts b/apps/web/lib/ssr/mapper.ts
index f7efcae211..b66a94684b 100644
--- a/apps/web/lib/ssr/mapper.ts
+++ b/apps/web/lib/ssr/mapper.ts
@@ -1,4 +1,5 @@
import type { AppState, KanbanState } from "@/lib/state/store";
+import { primaryTaskRepository } from "@/lib/types/http";
import type { WorkflowSnapshot, Message, Task } from "@/lib/types/http";
import {
isPRReviewFromMetadata,
@@ -26,6 +27,7 @@ export function snapshotToState(snapshot: WorkflowSnapshot): Partial
{
.map((task) => {
const workflowStepId = task.workflow_step_id;
if (!workflowStepId) return null;
+ const primary = primaryTaskRepository(task.repositories);
return {
id: task.id,
workflowStepId,
@@ -33,7 +35,14 @@ export function snapshotToState(snapshot: WorkflowSnapshot): Partial {
description: task.description ?? undefined,
position: task.position ?? 0,
state: task.state,
- repositoryId: task.repositories?.[0]?.repository_id ?? undefined,
+ repositoryId: primary?.repository_id ?? undefined,
+ repositories: task.repositories?.map((r) => ({
+ id: r.id,
+ repository_id: r.repository_id,
+ base_branch: r.base_branch,
+ checkout_branch: r.checkout_branch,
+ position: r.position,
+ })),
primarySessionId: task.primary_session_id ?? undefined,
primarySessionState: task.primary_session_state ?? undefined,
sessionCount: task.session_count ?? undefined,
diff --git a/apps/web/lib/state/slices/kanban/types.ts b/apps/web/lib/state/slices/kanban/types.ts
index 25838bfc61..c82520853f 100644
--- a/apps/web/lib/state/slices/kanban/types.ts
+++ b/apps/web/lib/state/slices/kanban/types.ts
@@ -28,7 +28,20 @@ export type KanbanState = {
description?: string;
position: number;
state?: TaskStatus;
+ /** Primary repository id (lowest position). Kept for backwards compat. */
repositoryId?: string;
+ /**
+ * All repositories linked to the task, ordered by Position. Optional so
+ * legacy SSR payloads still parse; multi-repo UI consumers should prefer
+ * this over repositoryId.
+ */
+ repositories?: Array<{
+ id: string;
+ repository_id: string;
+ base_branch: string;
+ checkout_branch?: string;
+ position: number;
+ }>;
primarySessionId?: string | null;
primarySessionState?: string | null;
sessionCount?: number | null;