Codex Desktop deletes heartbeat automation definition after restart when target thread is archived

Open 💬 4 comments Opened May 24, 2026 by jiadizhunine
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Summary

Codex Desktop appears to have silently removed one heartbeat automation after restart. This was not only a sidebar display issue: the automation definition was missing from both $HOME/.codex/automations and the SQLite automations table, while archived automation run threads still existed.

This looks related to automation/session persistence issues such as #23895, but seems more severe because the automation definition itself disappeared.

Environment

  • Codex Desktop: 26.519.41501
  • Codex app bundle version: 3044
  • Codex CLI: codex-cli 0.130.0
  • Platform: Darwin 25.5.0 arm64 arm
  • Automation type: heartbeat automation attached to a thread
  • Automation schedule: daily evening run
  • Target thread state found later: archived

I have intentionally redacted local usernames, exact local thread ids, and account-specific prompt content from this report.

What Happened

Before restarting Codex Desktop, I had two active automations:

  • a Gmail automation
  • a GitHub automation

After restarting Codex Desktop, only the Gmail automation was visible in the Automations sidebar.

Local inspection matched the UI state:

$HOME/.codex/automations/gmail/automation.toml

The missing GitHub automation was absent from both persistence layers:

$HOME/.codex/automations/github/automation.toml  # did not exist
$HOME/.codex/sqlite/codex-dev.db                # automations table only contained gmail

However, archived session state still contained previous GitHub automation run threads. The latest matching archived thread had metadata like:

title: Automation: GitHub
Automation ID: github
cwd: <project path containing spaces>
archived: 1

Archived automation transcript text also referenced:

Automation: GitHub
Automation ID: github
Automation memory: $CODEX_HOME/automations/github/memory.md
Last run: <timestamp>

So the automation appears to have existed and run before restart, then disappeared as a definition while its archived run threads remained.

Expected Behavior

Restarting Codex Desktop should not silently remove a heartbeat automation definition from:

  • $HOME/.codex/automations/<automation-id>/automation.toml
  • $HOME/.codex/sqlite/codex-dev.db, table automations

If the target thread has been archived, the automation should remain visible with a warning, keep running against that thread, or ask the user to choose a new target thread. It should not be removed without confirmation.

Actual Behavior

The GitHub heartbeat automation disappeared from:

  • the Automations sidebar
  • $HOME/.codex/automations
  • the SQLite automations table

Archived automation run threads remained, which makes this look like an automation definition persistence, cleanup, or rehydration bug rather than an intentional deletion.

Recovery

I recreated the missing automation from Codex Desktop. After recreation, both persistence layers contained the automation again:

$HOME/.codex/automations/github/automation.toml
$HOME/.codex/automations/github/memory.md
codex-dev.db automations row: id=github, status=ACTIVE

Why This Is Not Exactly #23895

#23895 reports automation run history disappearing while definitions remain on disk.

In this case, the archived run history still existed, but the automation definition itself was missing from both the file-backed automation directory and the SQLite automations table.

Suggested Investigation Points

  • Whether heartbeat automations whose target_thread_id points at an archived thread are pruned on startup.
  • Whether a failed automation rehydration can delete the automation definition instead of only hiding it from the sidebar.
  • Whether project-scoped automation threads under paths containing spaces are matched incorrectly after restart.
  • Whether the Automations sidebar is rebuilt from codex-dev.db, $HOME/.codex/automations, session_index.jsonl, or another cache, and whether those sources can diverge.

View original on GitHub ↗

4 Comments

github-actions[bot] contributor · 3 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #23895

Powered by Codex Action

jiadizhunine · 3 months ago

Thanks for flagging #23895. I reviewed it, and I think this is related but not a duplicate.

Evidence for the distinction:

  • In #23895, the automation definitions are explicitly reported to still exist on disk under ~/.codex/automations/*/automation.toml; the problem is that visible automation run history fails to rehydrate after restart.
  • In this issue, the missing github heartbeat automation definition was absent from both persistence layers after restart:
  • ~/.codex/automations/github/automation.toml did not exist
  • ~/.codex/sqlite/codex-dev.db automations table no longer contained the github row
  • Archived session records still contained previous Automation: GitHub / Automation ID: github run threads, so this was not a never-created automation. It had existed and run, then the definition disappeared.
  • After manually recreating the automation, both persistence layers contained it again: automation.toml was present and the SQLite automations row existed with id=github, status=ACTIVE.

So #23895 looks like a UI/run-history rehydration issue where definitions remain present. This issue looks like automation definition persistence/deletion across both the file-backed automation directory and SQLite state. I am keeping it open unless maintainers prefer to consolidate it intentionally.

jiadizhunine · 3 months ago

Additional observation: I just saw a related but slightly different failure mode, this time without restarting Codex Desktop.

Previously reported failure mode in this issue:

  • the github heartbeat automation definition disappeared from both ~/.codex/automations/github/automation.toml and the SQLite automations table after restart.

New failure mode observed now:

  • the github heartbeat automation definition still exists and is still ACTIVE.
  • ~/.codex/automations/github/automation.toml still contains:
  • kind = "heartbeat"
  • id = "github"
  • status = "ACTIVE"
  • target_thread_id = "019e55d6-0301-73e0-b7a8-12ade9105a96"
  • the SQLite automations row also still exists:
  • id=github
  • name=GitHub
  • status=ACTIVE
  • last_run_at=2026-05-24 04:39:30 UTC
  • next_run_at=2026-05-24 13:01:32 UTC

However, the target thread is no longer visible in the left sidebar. Locally, that target thread exists only under archived sessions:

~/.codex/archived_sessions/rollout-2026-05-24T01-15-49-019e55d6-0301-73e0-b7a8-12ade9105a96.jsonl

and there is no corresponding active session file under ~/.codex/sessions for that target thread id.

The file under archived_sessions continued to be modified later (mtime around 2026-05-24 12:53 local time), so this does not look like a stale leftover file only. It appears the heartbeat target thread can be archived/hidden while the automation definition remains active and still points at that archived thread.

Visible symptom in Codex Desktop:

  • Automations page still shows 2 automations.
  • The GitHub automation row displays the raw target thread id (019e55d6-...) instead of resolving to the conversation name.
  • The corresponding GitHub conversation is missing from the left sidebar.
  • Gmail, by contrast, still resolves normally because its target thread still has an active session file.

This makes the issue look broader than definition deletion on restart. There may be two related lifecycle bugs:

  1. startup/rehydration can delete or fail to persist a heartbeat automation definition when its target thread is archived;
  2. while the app is running, a heartbeat target conversation can be archived or hidden even though an active automation still points to it, leaving the automation visible but its target conversation unresolved in the UI.

Expected behavior: a conversation used as a heartbeat automation target should not be silently archived/hidden, or the automation should clearly ask the user to rebind it instead of continuing to point at a hidden archived thread id.

jiadizhunine · 3 months ago

Additional update after re-running/restarting the heartbeat automation:

After manually starting the github heartbeat again, the previously missing GitHub conversation reappeared in the left sidebar with its previous history. The Automations UI still displayed the target as the raw thread id (019e55d6-...), and the UI showed a toast: Heartbeat thread is busy right now.

Verified local state after this observation:

  • ~/.codex/automations/github/automation.toml still exists and is ACTIVE, with target_thread_id = "019e55d6-0301-73e0-b7a8-12ade9105a96".
  • The SQLite automations row is also still ACTIVE; last_run_at advanced to 2026-05-24 09:18:18 UTC.
  • There is still no active session file for that id under ~/.codex/sessions.
  • The target thread file exists under ~/.codex/archived_sessions/rollout-2026-05-24T01-15-49-019e55d6-0301-73e0-b7a8-12ade9105a96.jsonl.
  • That archived session file was modified after the manual start (May 24 17:20:22 local time) and contains the heartbeat output through 2026-05-24T09:20:02Z.
  • automation_runs has no rows for automation_id = 'github' or for that target thread id, while other heartbeat automations do have rows there.

Current interpretation:

  • The target conversation/history is not actually lost.
  • A heartbeat can still write to a target thread that currently only exists under archived_sessions.
  • Starting the heartbeat can make that archived conversation reappear in the sidebar with history, but the Automations page still shows the raw thread id and may show the busy-thread error.
  • This looks like a mismatch between archived-thread lifecycle, sidebar/session rehydration, and heartbeat automation bookkeeping, with a possible separate inconsistency in automation_runs persistence for this heartbeat.

Expected behavior: if a heartbeat target thread is archived/hidden, the app should consistently rehydrate/show/rebind it, or warn that the target is archived, instead of letting the sidebar hide it and then resurrect it only after a manual automation start.