Skip to content

feat(parser): add TraeX (TRAE CLI 2.0) as a first-class agent - #1349

Merged
wesm merged 3 commits into
kenn-io:mainfrom
GhostFlying:feat/traex-agent
Aug 10, 2026
Merged

feat(parser): add TraeX (TRAE CLI 2.0) as a first-class agent#1349
wesm merged 3 commits into
kenn-io:mainfrom
GhostFlying:feat/traex-agent

Conversation

@GhostFlying

Copy link
Copy Markdown
Contributor

TRAE CLI 2.0 (traex) is a closed-source fork of codex-rs. It writes rollout
JSONL that is field-for-field the Codex shape into ~/.trae/cli/sessions,
including the subagent session_meta, token_count records, and a sibling
history.jsonl at the same position relative to the sessions root. Until now
the only way to index it was to declare that root as a codex source, which
gives the sessions the wrong agent and an ID prefix whose one-click resume
command (codex resume <id>) cannot resume them.

This adds traex as its own agent, served by the Codex provider through a
relabel hook — the same shape opencode_provider.go already uses to serve
Kilo, MiMoCode, and Icodemate from one implementation. Parsing, discovery,
fingerprinting, and JSONL-tail incremental appends are shared; only the agent
label and the traex: ID prefix differ. internal/parser/traex.go is the
whole fork-specific surface and is the first place to look.

The relabel covers more than Kilo's does. Besides the session ID, parent, and
source-session ID, the Codex parser stamps codex: onto the
SubagentSessionID of tool calls and their result events, so a partial
relabel would leave a TraeX parent pointing at codex:<uuid> rows the
traex: namespace never stores. The provider's incremental path returns
appended messages with no session, so the hook takes (*ParsedSession, []ParsedMessage) and treats a nil session as that path.

Discovery keys are now agent-scoped (CodexSourceKey takes an agent). Both
agents name files by UUID, so a shared key would let one agent's session
resolve to the other's file.

In internal/sync, the branches that describe the format — same-UUID
duplicate resolution, dated-over-flat layout preference, reconciliation
identity, the incremental file_mtime basis, and the parse-diff raced guard —
move behind a new isCodexFormatAgent predicate. The branches that describe
Codex's out-of-band files stay keyed to parser.AgentCodex alone, because
TraeX writes neither: there is no session_index.jsonl sidecar (so no title
backfill, no index-driven cache invalidation, and no index watch or changed-path
fan-out), and no s3://.../raw/codex/... archive convention, so a traex root
that looks like an S3 URI is skipped rather than imported under Codex's
identity. That split is the main thing worth reviewing.

Two consequences of having no index file are worth stating. Titles come from
the rollout head only, so a TraeX session never picks up a renamed thread name.
And ~/.trae/cli is not watched shallowly, unlike ~/.codex, since the only
reason to watch it would be the index file and the directory otherwise holds
constantly-rewritten SQLite WALs.

Evidence for the format is observational and documented as no-public-source
in the format inventory: TRAE CLI ships only as a binary, and neither Trae's
product site nor the public Trae-AI/Trae repository publishes a session
schema. A de-identified rollout with subagent spawn/wait records is kept as a
fixture.

Switching an existing installation from the codex-source workaround to
agent = "traex" is not handled: the stored rows are keyed by file path, so
the old codex:<uuid> rows would satisfy the freshness skips and the new rows
would never be written. A full resync into a fresh database is the intended
path.

🤖 Generated with Claude Code

@roborev-ci

roborev-ci Bot commented Aug 5, 2026

Copy link
Copy Markdown

roborev: Combined Review (fc9dffd)

Changes requested: one medium-severity provider-isolation issue could corrupt session attribution.

Medium

  • internal/sync/engine.go:9962 — Incremental and freshness lookups remain keyed only by file path. If a TraeX rollout was previously indexed as Codex, or configured roots overlap, an unchanged TraeX source may be skipped using the Codex row. After an append, GetSessionForIncremental may return the Codex session ID and append relabeled TraeX messages to that session.

    Fix: Scope incremental lookups, database freshness checks, and skip-cache identities by agent. Reject incremental results whose stored session belongs to another agent, and add a Codex-to-TraeX reassignment regression test.


Reviewers: 2 done | Synthesis: codex, 11s | Total: 9m14s

@wesm

wesm commented Aug 9, 2026

Copy link
Copy Markdown
Member

looking

@wesm
wesm force-pushed the feat/traex-agent branch from fc9dffd to fe90f9e Compare August 9, 2026 14:18
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (fe90f9e)

Code changes require fixes before approval: two medium-severity agent-isolation issues remain in TraeX sync handling.

Medium

  • Verified-source state is keyed only by pathinternal/sync/verified_source_gate.go:216,244

    When Codex and TraeX share or reassign a root, one agent’s trusted signature and current database row can cause the other agent’s sync to be skipped, leaving its missing row unrepaired.

    Fix: Include the agent in verified-source cache keys and add an agent-scoped equivalent of GetSourceRepairStateByPath.

  • TraeX incorrectly inherits Codex session-index behaviorinternal/sync/engine.go:10152,10437

    TraeX uses Codex-specific session_index.jsonl logic through CodexEffectiveMtime, LookupCodexThreadName, and the index-title skip branch. A copied index or reassigned root can apply Codex titles to TraeX sessions or consult the Codex row when evaluating freshness.

    Fix: Gate index lookup, effective-mtime folding, eviction, and title comparison on AgentCodex; use transcript-only metadata for TraeX.


Reviewers: 2 done | Synthesis: codex, 12s | Total: 8m48s

@wesm
wesm force-pushed the feat/traex-agent branch from fe90f9e to 03c0a34 Compare August 9, 2026 23:06
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (03c0a34)

Medium-severity synchronization issues remain and should be fixed before merging.

Medium

  • internal/sync/engine.go:8998 — Appending ?agent=... breaks remote skip-cache translation for exact-file mappings such as Hermes state.db. The qualified path is treated as a sibling of the mapped file, causing tempPathToRemotePath and remoteArchiveRel to reject it and silently drop the cache entry. Split recognized cache qualifiers before remote path translation and reattach them afterward in both directions; add an ExtraFiles round-trip test with an agent-qualified key.

  • internal/sync/engine.go:9970 — TraeX’s incremental gate uses the path-only pathNeedsProjectReparse; the cached-skip check at line 8304 has the same unscoped lookup. If Codex and TraeX rows share a path, another agent’s newer project can mask stale TraeX metadata, allowing an incremental append that preserves it. Pass the provider agent through the repair helpers and use GetProjectByAgentPath, GetFileInfoByAgentPath, and GetDataVersionByAgentPath.


Reviewers: 2 done | Synthesis: codex, 10s | Total: 8m52s

@roborev-ci

roborev-ci Bot commented Aug 10, 2026

Copy link
Copy Markdown

roborev: Combined Review (caa475c)

No issues found.


Reviewers: 2 done | Synthesis: codex | Total: 11m54s

- test(cli): pin TraeX live-activity hint target collection
- fix(traex): scope Codex sidecars and guard path-keyed skips
- revert: drop the in-place codex-to-traex adoption guard
- docs: drop the build-channel detail from the TraeX evidence note
- fix(sync): isolate provider freshness by agent
- fix(sync): scope DB-backed freshness by agent
- fix(sync): isolate verified-source repair state by agent
- fix(traex): keep Codex index metadata out of TraeX sync
- docs: design agent-scoped remote cache repair
- fix(sync): preserve agent scope across cache repairs

Co-authored-by: Wes McKinney <wesmckinn+git@gmail.com>
@wesm
wesm force-pushed the feat/traex-agent branch from caa475c to ebe92ac Compare August 10, 2026 02:27
@roborev-ci

roborev-ci Bot commented Aug 10, 2026

Copy link
Copy Markdown

roborev: Combined Review (ebe92ac)

Medium-severity issue found in TraeX repeat-sync handling.

Medium

  • internal/sync/engine.go:10933 — An unchanged TraeX rollout always enters the equal-size incremental branch. Because that branch exempts only Codex, it sets forceReplace and bypasses later database freshness checks, causing every periodic sync to reparse and replace all messages indefinitely.
    • Fix: Use isCodexFormatAgent(agent) so TraeX reaches the fingerprint-based freshness check. Add a repeat-sync test verifying that an untouched TraeX session is skipped.

Reviewers: 2 done | Synthesis: codex, 11s | Total: 13m54s

wesm added 2 commits August 9, 2026 21:53
An unchanged TraeX rollout can bypass database freshness and replace its stored messages on every periodic sync. Record the narrow format-family boundary and the observable regression before changing the incremental gate.
An unchanged TraeX rollout fell through the equal-size incremental gate with forceReplace set, so scheduled syncs reparsed and rewrote its messages before fingerprint freshness could apply. Treat Codex-format rollouts consistently at that gate so untouched TraeX sessions reach database freshness while true appends retain incremental parsing.
@roborev-ci

roborev-ci Bot commented Aug 10, 2026

Copy link
Copy Markdown

roborev: Combined Review (eff90e8)

Code review passed with no medium-or-higher severity findings.


Reviewers: 2 done | Synthesis: codex, 10s | Total: 23m27s

@wesm
wesm merged commit df0b77c into kenn-io:main Aug 10, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants