@@ -34,6 +34,12 @@ class RunForegroundService : Service() {
3434 val sessionTitle = intent?.getStringExtra(EXTRA_SESSION_TITLE)?.takeIf { it.isNotBlank() }
3535 val sessionId = intent?.getStringExtra(EXTRA_SESSION_ID)?.takeIf { it.isNotBlank() }
3636 val progress = intent?.getStringExtra(EXTRA_PROGRESS)?.takeIf { it.isNotBlank() }
37+ // The service is re-started per progress update (AppContainer re-sends the intent on
38+ // each _runProgressText change). Capture the wall-clock start of the *first* intent
39+ // of this run and reuse it across rebuilds so the chronometer's base doesn't jump
40+ // back to 0:00 every time the agent advances a step. Reset to 0 in onDestroy once
41+ // the run ends (stop() → onDestroy) so the next run starts fresh.
42+ if (runStartMillis == 0L) runStartMillis = System.currentTimeMillis()
3743 val notification = buildNotification(sessionTitle, sessionId, progress)
3844 // startForeground can throw ForegroundServiceStartNotAllowedException on
3945 // Android 12+ if the app is in the background when the service starts. Wrap
@@ -81,7 +87,9 @@ class RunForegroundService : Service() {
8187 .setOngoing(true)
8288 // Show a live elapsed timer so the user can see how long the current run has
8389 // been going — no per-tick plumbing needed; the system renders the chronometer.
84− .setWhen(System.currentTimeMillis())
90+ // runStartMillis is captured once at the start of the run (see onStartCommand)
91+ // and reused across progress-driven rebuilds so the chronometer base is stable.
92+ .setWhen(runStartMillis)
8593 .setUsesChronometer(true)
8694 .setShowWhen(true)
8795 .setPriority(NotificationCompat.PRIORITY_LOW)
@@ -150,6 +158,9 @@ class RunForegroundService : Service() {
150158 // Safety net: if the process is being killed while a run is in progress,
151159 // ensure the notification is removed rather than lingering.
152160 ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
161+ // Reset the run start so the next run's chronometer begins fresh instead of
162+ // inheriting the previous run's elapsed base.
163+ runStartMillis = 0L
153164 super.onDestroy()
154165 }
155166
@@ -159,6 +170,10 @@ class RunForegroundService : Service() {
159170 private const val TAG = "RunForegroundService"
160171 private const val NOTIF_ID = 1
161172 private const val NOTIF_TIMEOUT_ID = 2
173+ // Wall-clock time the current run started, captured on the first onStartCommand of
174+ // the run and reused across progress-driven notification rebuilds so the chronometer
175+ // base is stable. Reset to 0 in onDestroy when the run ends.
176+ @Volatile private var runStartMillis: Long = 0L
162177 // Brand accent for the foreground notifications' small-icon tint circle. Resolved
163178 // from resources (R.color.notif_brand) so it follows the app theme (light/dark)
164179 // instead of a hardcoded constant. Lazily computed on first use from the app context.