Skip to content

🤖 feat: RLM Mode — kernel-first exclusive PTC posture with persistent kernel, context isolation, and continual-harness features - #3900

Merged
ThomasK33 merged 242 commits into
mainfrom
research-qr9r
Aug 24, 2026
Merged

Conversation

@ThomasK33

Copy link
Copy Markdown
Member

Summary

Adds RLM Mode — an opt-in, kernel-first execution posture for PTC inspired by PrimeIntellect's prime-agent architecture — plus the continual-harness features around it (refinement journal with rollback, /refine trajectory distillation, family messaging, branch summarization, compaction improvements) and a measurement harness (shux rlm-eval) that every major design decision in this PR was validated against.

With the RLM experiment off, behavior is byte-identical to main (pinned by composition tests and replay-verify on live sessions). With it on, code_execution becomes the primary tool backed by a persistent per-workspace QuickJS kernel.

Background

Research into prime-agent (which posted strong vendor-reported eval results) identified two core ideas worth porting: a single persistent code kernel where in-kernel data never transits model context, and a self-modifying harness with journaled, reversible edits. Mux's Track 1 foundation (journal kit, durable events, sandbox host, replay harness — #3865/#3872) provided the substrate; this PR is "Track 2" built on it, implemented via the phased conductor workflow in workflows/track2-rlm-implementation.js (per-phase quality gates, adversarial review, live dogfooding).

Implementation

RLM kernel (phases r1, r4, r5, r12):

  • rlm-mode experiment, nested under PTC; exclusive-only — enabling it forces the kernel-first narrowed toolset (supplement-mode RLM measured ~2x flat cost and was removed)
  • Persistent per-workspace mount: guest vars survives calls/turns/restarts via journaled snapshots
  • Kernel context isolation: nested shux.* results never enter model context (compact {tool, ok, bytes} summaries); the model's channels are its return value (offloaded via handles >16KB), capped console output, and vars
  • shux.load({path, key}): host-side bulk file ingestion straight into vars (record shows {key, bytes, lines, preview} only)
  • shux.task_spawn + shux.events(): fire-and-forget sub-agents with admission handles, asyncify-safe event drain
  • Batching guidance baked into the kernel-first preamble ("write complete programs")

Continual harness (r2, r6, r11):

  • Every memory/skill mutation journals an invertible refinement durable event (blob-backed inverses)
  • Rollback engine with rollbackOf lineage: shux run debug refinements CLI + RLM-gated refinement_rollback tool
  • /refine: bounded trajectory-distillation pass (dream-agent machinery) applying smallest evidence-backed edits, journaled and reversible

Agent ops (r3, r7, r8, r9):

  • Nuclear-family messaging: task_message_parent / task_message_sibling (RLM stamped on task records at spawn; strict same-parent scoping; server-side labels)
  • RLM-gated compaction keep-recent floor + cumulative read-file tracking
  • Branch summarization on fork/edit-resend (background generation, tail-guarded append)
  • scripts/gate_fingerprint.sh verification-loop memoizer

Measurement (scripts/rlm-eval/, make rlm-eval): scenario x config x seed A/B runner extracting mechanical metrics (tokens, cost, wall time, peak context, vars adoption, batch factor, compactions) from session artifacts.

Validation

  • Key measured results (sonnet-5 / opus-5 / gpt-5.6-sol; fable-5 at medium):
    • Context isolation: 504KB file load -> 867 bytes model-visible (0.17%); pre-fix the same task leaked 610KB into context and cost 10x flat tools
    • RLM-exclusive vs flat tools: -30 to -63% cost in 7/8 model x scenario pairs, faster in 6/8, all cells correct; organic vars adoption 15/16
    • Batching preamble (cross-build A/B): sonnet organic batch factor 2.7 -> 3.5 (3/4 seeds fold all 6 loads into one eval, -42% tokens)
  • Every phase passed an independent gate run + adversarial review + live dev-server-sandbox dogfood with replay-verify PASS (evidence in the workflow run reports)
  • Post-rebase onto the Shux rename: full static-check green; kernel suites (code_execution 50, toolBridge/typeGenerator 43, toolAssembly 14, sandboxHost 25) green; kernel surfaces adopt shux-primary naming with the mux.* alias intact

Risks

  • RLM-off regression risk is the headline concern and is heavily defended: composition tests pin byte-identity per flag combination, and replay-verify was run on live RLM-off control sessions at each phase. Highest-traffic shared code touched: toolAssembly, code_execution, compaction paths (RLM-gated), task spawn paths (flag stamping).
  • RLM-on surfaces are experimental by declaration; known rough edges: peak per-request context is higher when shux.load materializes large files (latent pressure on multi-MB corpora), and one sonnet seed still fragments batching.
  • /refine auto-applies edits (no approval UI in v1) — mitigated by journal + rollback + immutable-base guard rails.

Pains

  • The mid-series mux -> shux rename on main required conflict resolution across the kernel commits (namespace, type-generator identifiers, description text).
  • Sub-agent dogfooding infrastructure failures (background-monitor wakes, uncommitted-work timeouts, transient gateway model errors) shaped several workflow-hardening commits.

Generated with mux • Model: anthropic:claude-fable-5 • Thinking: xhigh • Cost: $763.80

@mintlify

mintlifyBot commented Aug 20, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

ProjectStatusPreviewUpdated (UTC)
Mux🟢 ReadyView PreviewAug 20, 2026, 5:42 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@ThomasK33

Copy link
Copy Markdown
MemberAuthor

@codex review

…inement journal, RLM mode experiment)
Conductor for implementing prime-agent-inspired RLM/continual-harness features behind an opt-in RLM sub-experiment of PTC. Mirrors workflows/track1-implementation.js: per-phase implement -> gate+adversarial-review -> fix rounds -> dogfood.
… code_execution
RLM Mode is an opt-in sub-experiment of Programmatic Tool Calling (flat
flag, gated on the PTC parent at call sites, nested under the PTC toggle
in Settings, mirroring the Memory Hot Set precedent). When enabled with
PTC and sandbox context, code_execution runs on the persistent
per-workspace kernel mount: the guest vars namespace survives across
calls/turns and restarts via snapshots, and the tool description
advertises those kernel semantics. MUX_SANDBOX_PERSISTENT_MOUNTS=1
remains a dev/test override with unchanged behavior. With the experiment
off (and env unset) behavior is byte-identical to before: fresh runtime
per call and today's description.
The rlm flag plumbs through the experiments path end to end:
ExperimentsSchema (send options) -> aiService.streamMessage ->
applyToolPolicyAndExperiments.
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Every mutating memory command (create/str_replace/insert/delete/rename) and
every agent_skill_write/agent_skill_delete now appends exactly one
'refinement' durable event to the acting workspace's session journal
(sharedDurableEventJournal), carrying an inverse payload that byte-exactly
restores the prior file state. Prior contents over 4KB are offloaded to the
session blob store (BlobRef), mirroring hook-context. Evidence records
{workspaceId, toolName, toolCallId?, actor?}.
Always-on and purely additive: journaling failures never fail the tool
(log.debug + continue), read-only ops and failed mutations write no rows.
Cross-workspace caveat (v1): memory/skill files are global/project-scoped
while the journal is per-session; rows land in the acting workspace's log.
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Standalone, always-on-by-usage gate memoizer: 'fingerprint' hashes HEAD sha +
'git diff HEAD' + sorted untracked-not-ignored files with content hashes;
'record <gate> <pass|fail>' and 'check <gate>' store/look up results in a JSON
file inside the worktree-local git dir (git rev-parse --git-path), so records
are never committed and never invalidate themselves.
wait_pr_ready.sh integration was skipped intentionally: it has no local
validation step (it only orchestrates remote Codex/review/CI gates), per the
phase brief's conditional.
Tests spawn the real script against hermetic temp git repos and cover
stability, pass/fail round-trip, tracked-edit / untracked-file / staged-change
invalidation, and corrupt-store self-healing.
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…-handle events
Under an RLM persistent mount, nested mux.* results and code_execution
return values whose JSON serialization exceeds 16KB stop entering the
model context: the model-visible record becomes {handle, preview, size}
(plus a follow-up hint for return values) while the full value stays in
the guest at vars.__hN (monotonic per scope via vars.__handleSeq, so it
snapshots/restores with vars), in the content-addressed blob store, and
in one result-handle durable event whose preview mirrors the
model-visible string exactly. Handle bytes retained in vars are capped
with oldest-first eviction (never the newest handle); the blob remains
the durable copy. RLM off / ephemeral runtimes are byte-identical to
today.
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…escription)
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…ervice
finalizeAgentTaskReport now invokes sandboxHostService.postTaskTerminalEvent
(fire-and-forget, gated on no foreground waiters) so spawned-task completions
reach the guest host-event queue in production — previously the hook had zero
production callsites and mux.events() always drained empty. Regression tests
cover both the posted-event and waiter-suppression branches.
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…h lineage
listRefinements/rollbackRefinement make the r2 journal actionable: rollbacks
apply the recorded inverse (inline or blob-backed) through atomic writes,
journal their own refinement row with rollbackOf (so double inversion works),
refuse already-rolled-back targets, refuse divergence (later overlapping rows,
deleted/recreated files, content drift for rollback rows) unless forced, and
confine every touched path to memory scope roots / skill directories with
lexical + symlink escape checks that force can never override.
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…orce
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Assembled in toolAssembly from the sandbox context inside the PTC branch, so
the tool only exists when RLM mode is on (nested under the PTC parent); with
the experiment off the toolset — and thus every provider request — stays
byte-identical. Force stays CLI-only: divergence overrides are a human call.
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…refinement_rollback
Signed-off-by: Thomas Kosiewski <tk@coder.com>
… memory to current session
- P1: the later-rows divergence check now nets out rollback lineage: rows
whose effect was itself rolled back are skipped, and live rollback chains
conflict only when their parity re-applies an edit or rewinds past the
target — so LIFO multi-edit unrolling works for model tool calls without
force, while re-applied edits (rollback-of-rollback) still refuse.
- P2: workspace-scope memory confinement resolves strictly to the current
session's memory root (<sessionDir>/memory) instead of any session subdir
under sessionsDir, closing the cross-workspace write leak.
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…tCode on undefined assignment)
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…action)
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…oundary copies, read-file tracking
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…rendering
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…est metadata, optional chain
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…tch + staleness guard)
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@chatgpt-codex-connector

This comment has been minimized.

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

awaitsandboxHostService.dropScope(workspaceId);

P2 Badge Bound persistent-mount teardown waits

When an RLM code_execution has finished guest evaluation but stalls while persisting its vars snapshot, it still holds SandboxHostService's per-scope lock and the stream abort no longer cancels that post-eval filesystem work. dropScope() waits for the same lock without a timeout, so deleting the workspace hangs indefinitely on a wedged snapshot write and never reaches session/config removal. Make persistence cancellation-aware or give teardown a bounded path that safely prevents the detached snapshot from committing later.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadsrc/node/services/workspaceService.ts Outdated
Comment threadsrc/node/services/workspaceService.ts
Comment threadsrc/node/services/workspaceRemoval.ts
…stone rollback (Codex r66)
- Relocate the refine serialization lock outside the session directory
(refineApplyLockPath under <rootDir>/locks, r63 history-lock precedent):
acquireProcessFileLock mkdirs the lock's parent, so a foreign /refine or
context-discard landing after removal recreated the deleted session
directory just by locking. Removal now holds this lock across its
tombstone+delete critical section, and both refine paths recheck the
durable removal tombstone in-lock before staged-set writes.
- Partial flushes (writePartial) now ride the cross-process history lock
with an in-lock tombstone gate: a foreign backend's active stream survives
process-local cancellation, and its next delta's ensurePrivateDir would
otherwise resurrect the deleted session directory.
- Tombstone rollback after failed config deregistration is now
ownership-checked (per-attempt ID stamped into the marker, verified with
registration state under the sessionDir target lock): an unconditional rm
could delete the marker a concurrent backend's removal republished or
completed with, reopening the durable removal gate.
@ThomasK33

Copy link
Copy Markdown
MemberAuthor

@codex review
Please take another look.

@chatgpt-codex-connector

This comment has been minimized.

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:bc2b781fa1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadsrc/node/services/sandbox/sandboxHostService.ts
Comment threadsrc/node/services/refinement/refinementRollback.ts Outdated
Comment threadsrc/node/services/tools/code_execution.ts Outdated
Comment threadsrc/node/services/workspaceRemoval.ts Outdated
… r67)
- P1: track per-mount snapshot lineage (journal seq of the newest vars-snapshot
row) so a foreign backend's ORDINARY persist invalidates a live mount at the
next lease and stale persists are refused inside the blob lock, instead of
silently superseding the foreign write (sandboxHostService).
- P1: acquire the refine serialization lock BEFORE the teardown target/history
locks in removeSessionDirUnderMemoryLocks — /refine apply acquires refine ->
target/history, so the old inner acquisition deadlocked with an admitted
apply in opposite lock order until timeout (workspaceRemoval).
- P2: represent mixed force-apply pre-state completely: restore-files inverses
gain optional deletePaths so a double rollback deletes force-created files
instead of leaving them behind (refinement schema + rollback engine).
- P2: track xum.load keys host-side in ToolBridge at the moment the vars write
succeeds — an oversized hookResult annotation could get the record replaced
by a keyless __kernelBounded marker, letting annotated loads bypass the
managed-vars retention cap (toolBridge + code_execution).
@ThomasK33

Copy link
Copy Markdown
MemberAuthor

@codex review
Please take another look. All four round-67 findings addressed in a4163e5: per-mount snapshot lineage (foreign ordinary snapshots now invalidate leases and refuse stale persists), refine lock acquired before teardown's inner locks (matches /refine apply's order), restore-files inverses carry deletePaths for mixed force pre-states, and xum.load keys tracked host-side so bounded records can't bypass vars retention.

@chatgpt-codex-connector

This comment has been minimized.

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:a4163e573e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadsrc/node/services/sandbox/sandboxHostService.ts
Comment threadsrc/browser/stores/WorkspaceStore.ts
…ndered rows (Codex r68)
- P1: type the persist precondition's foreign-conflict refusals as
SandboxSnapshotConflictError (reset r52 + snapshot lineage r67) and have
code_execution fail the whole call as a retryable conflict instead of
reporting eval success: the eval may have read stale vars mid-window and
its mutations were refused, so a success report would silently drop them
and leave stale computed results model-visible. Load records get a
conflict-specific rewrite instead of the free-vars-space advice.
- P1: getDisplayedRefineProposalHash now restricts its newest-first scan to
rows the transcript actually renders (getDisplayedMessages, DOM display
cap): a staged proposal hidden past the cap could otherwise be approved
sight-unseen. Extracted findRenderedRefineProposalHash for tests.
@ThomasK33

Copy link
Copy Markdown
MemberAuthor

@codex review
Please take another look. Both round-68 P1s addressed in cb36413: persist-precondition refusals are now typed (SandboxSnapshotConflictError) and code_execution fails the call as a retryable conflict instead of reporting success (with conflict-specific load-record rewrites), and the refine approval hash scan is restricted to rows the transcript actually renders (display-cap-aware via getDisplayedMessages), so a hidden staged proposal can no longer be approved sight-unseen.

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:cb36413aec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadsrc/node/services/tools/code_execution.ts Outdated
…ed side effects (Codex r69)
A snapshot conflict only rejects vars persistence — nested xum/mux tool
calls that completed inside the eval (task messages, file mutations) are
not rolled back. The conflict error previously said 're-run this call',
which would replay those externally visible effects. When any non-load
nested call completed, the error now names the tools and instructs the
model to re-derive the lost vars state WITHOUT repeating completed side
effects; the plain re-run advice remains only when no side-effecting call
completed. Loads stay excluded: they are reads whose vars entries did not
survive, so re-issuing them is the fix, not a hazard.
@ThomasK33

Copy link
Copy Markdown
MemberAuthor

@codex review
Please take another look. Round-69 P1 addressed in ccb3069: when a snapshot conflict occurs after nested non-load calls completed, the error now enumerates them and instructs re-deriving the lost vars state without repeating the completed side effects; the plain re-run advice is kept only when no side-effecting nested call completed (loads stay excluded — re-issuing those reads is the fix, not a hazard).

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:ccb3069981

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadsrc/node/services/tools/code_execution.ts Outdated
Comment threadsrc/node/services/taskService.ts
Comment threadscripts/rlm-eval/run.ts
…unting fixes (Codex r70)
- P1: offloadTaskTerminalEvent acquired the scope lock a polling guest eval
already holds — a child's oversized report could never become visible to
xum.events() until the eval timed out. Added AsyncMutex.tryAcquire
(synchronous check-and-take); when the scope is leased, the bounded
preview event posts immediately (lock-free queue push, single event per
task) and the handle upgrade is skipped — the full report still arrives
via the durable top-level task wake. Handle offload runs only when the
lock is free at that instant.
- P2: a nested call record carrying an error is not proof of no side effect
(a tool can mutate then reject, e.g. a post-hook throws) — the snapshot
conflict advice now warns for every invoked non-load call.
- P2: rlm-eval turn accounting (waitForTurn + extractMetrics) now excludes
synthetic user snapshot rows (@file / agent-skill / MCP-prompt), which
carry synthetic:true but a normal muxMetadata type, so they no longer
open phantom scenario turns or shift positional verifier answers.
@ThomasK33

Copy link
Copy Markdown
MemberAuthor

@codex review
Please take another look. All three round-70 findings addressed in f2c2b43: task-terminal event visibility is decoupled from the eval lease via a synchronous AsyncMutex.tryAcquire (busy scope → immediate bounded preview event, lock-free, single event per task; handle offload only when the lock is free), snapshot-conflict advice now conservatively warns for every invoked non-load nested call (an errored record is not proof of no side effect), and rlm-eval turn accounting excludes synthetic user snapshot rows in both waitForTurn and extractMetrics.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit:f2c2b4384f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

This comment has been minimized.

@ThomasK33
ThomasK33 added this pull request to the merge queueAug 24, 2026
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to failed status checks Aug 24, 2026
@ThomasK33
ThomasK33 added this pull request to the merge queueAug 24, 2026
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to failed status checks Aug 24, 2026
@ThomasK33
ThomasK33 added this pull request to the merge queueAug 24, 2026
Merged via the queue into main with commit 695e562Aug 24, 2026
35 of 39 checks passed
@ThomasK33
ThomasK33 deleted the research-qr9r branch August 24, 2026 11:38
@mux-botmux-botBot mentioned this pull request Aug 24, 2026
Sign up for freeto 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.

1 participant

@ThomasK33