diff --git a/app/src/app/(app)/runs/page.tsx b/app/src/app/(app)/runs/page.tsx
index 7d4b411..01d1e55 100644
--- a/app/src/app/(app)/runs/page.tsx
+++ b/app/src/app/(app)/runs/page.tsx
@@ -23,11 +23,18 @@ export const metadata: Metadata = { title: "Run History" };
const PAGE_SIZE = 25;
+// Duration isn't a stored column - it's derived from started_at/ended_at (both unix seconds), so
+// it needs a SQL expression rather than a plain column reference to be sortable. Still-running
+// rows (ended_at IS NULL) count as elapsed-so-far; never-started (queued) rows sort as NULL,
+// which SQLite puts first in ASC / last in DESC - keeping them out of the way either direction.
+const durationExpr = sql`case when ${runs.startedAt} is null then null else coalesce(${runs.endedAt}, unixepoch()) - ${runs.startedAt} end`;
+
const SORT_COLUMNS = {
script: runs.scriptName,
status: runs.status,
triggeredBy: runs.triggeredBy,
started: runs.startedAt,
+ duration: durationExpr,
} as const;
type SortKey = keyof typeof SORT_COLUMNS;
const DEFAULT_SORT: SortKey = "started";
@@ -172,7 +179,7 @@ export default async function RunsPage({ searchParams }: RunsPageProps) {
{sortHeader("status", "Status")}
{sortHeader("triggeredBy", "Triggered by")}
{sortHeader("started", "Started")}
- Duration
+ {sortHeader("duration", "Duration")}