Heartbeat Automation Prompt¶
This is the public copy-paste template for a Codex App heartbeat automation that advances one LoopX goal without hiding compute policy inside the timer.
The timer only wakes the executor. LoopX decides whether that wakeup should spend delivery compute.
The unified-contract RFC keeps Codex App heartbeat as a required product qualification path. Its proposed controller session would consume one canonical contract and delegate ordinary work to an executor. That profile is not enabled by this template: continue to use the installed runtime's fresh contract and existing scheduler/stop rules.
中文:统一契约提案 将 Codex App heartbeat 列为必验产品路径。拟议 controller 消费统一契约后向 executor 交付业务任务;本模板不启用该模式,仍以已安装运行时的最新契约和调度/停止规则执行。
Two Prompt Layers¶
Keep the Codex App visible goal text and the heartbeat automation task body as two separate layers:
- Visible goal text: short and human-scannable, for example
按 ACTIVE_GOAL_STATE.md,基于 LoopX 体系,推进项目. - Persistent heartbeat entrypoint: generated by
loopx heartbeat-prompt --bootstrap --thin --codex-app; save the v2 loader in the automation. It binds the task's goal and agent and fetches the current contract on every wake. - Execution or audit body: generated without
--bootstrap. Thin is the normal fresh execution body; compact, brief and full expose other levels of detail. These changing bodies are not the persistent automation prompt.
Prompt compression must preserve both conditions and required responses. A
missing concrete user action under NOTIFY calls for state-projection repair,
not just a diagnostic label. Under DONT_NOTIFY, repair stays internal; it
does not grant notification authority. Keep these semantics in brief and thin
prompts as well as the expanded contract, within their existing size budgets.
Reward Memory outcome guidance is a deliberate prompt increment, not a reason
to remove the validator, digest/evidence, writeback/readback, zero-provider-call,
or private-material boundaries. When automatic outcome ingestion is enabled, the
generated heartbeat body receives a fixed +640-character headroom (and the
corresponding bounded line/UTF-8 allowance) for this contract. The CLI output
differential also grants that allowance once during the none-to-v1 migration;
unrelated later growth still uses the ordinary gate. Keep the explanation
readable, while visible Goal prompts and other surfaces retain their own limits.
All generic heartbeat and native Goal bodies match the user's current language, fall back to English when no user language is available, and do not mix languages unless the user asks or a scoped capability requires bilingual output. This policy applies to full, compact, brief, thin, visible Codex and TraeX Goal, and Ark Managed Agent bodies. Capability-specific bilingual contracts remain authoritative for their own output surfaces.
Do not paste the full lifecycle protocol into the visible goal text, and do not use a short goal text such as "advance TODO" as the recurring automation body. The short text names the goal; the generated task body enforces quota, gates, steering audit, writeback, refresh, and spend accounting.
Ark Managed Agent is not an automation profile. Its integration uses one transport-neutral goal prompt and lets the goal runtime own inner iteration; see the host integration protocol instead of adapting this recurring automation contract.
Native Goal bootstrap and live execution instructions¶
Full, compact and brief automation use the same fully qualified notification/execution rule
as thin, including heartbeat_recommendation.agent_must_attempt and
execution_obligation.must_attempt_work. None embeds a second
static refresh/spend sequence: after validated work it follows the current
interaction_contract.cli_channel.settlement_plan.ordered_steps, or current
next_cli_actions when there is no plan. Generator command fields remain for
compatibility, not as a stale fallback. Todo acceptance alone is not Turn
settlement or terminal vision closure. The brief base budget is 4,800 characters; reward-memory headroom remains separate.
Markdown prints a complete guard command once when the successful task body already contains that exact command as a whole line. Generator Inputs then points to the body; JSON fields remain complete. Missing, different, partial or failed bodies retain the complete diagnostic command.
成功正文已按完整行包含同一 guard 命令时,Markdown 诊断区指向正文,避免重复长命令; JSON 字段保留全文。正文缺失、不同、仅匹配前缀或生成失败时,诊断区仍打印完整命令。
Brief 与 thin 共用完整执行义务路径;full、compact、brief 均移除固定结算配方,而不是 删除结算义务。真实 App preflight、registry scope、完整 guard 和静态安全规则 均保留;结算顺序与身份以本轮动态 contract 为准,vision replan 不由历史成功清账。
First-connect messages and supported host activations use heartbeat-prompt --bootstrap: a saved
loader requests the installed rules rather than freezing a long execution body.
The loader and automation bootstrap share rendering and successful-response
checks. Registry-derived state is resolved at load time; explicitly supplied
policy remains bound. The inner command does not request another bootstrap.
Claude Code loads its inner body through the bound MCP host_prompt tool.
TraeX's separate capability projection remains separate, not embedded by this
loader. See prompt upgrade lifecycle
for automatic exact-managed adoption during update --apply, including the
closed-App SQLite/TOML adapter and conflict recovery boundary. Running Apps
require their native automation API.
Static semantics retained across hosts¶
Thinning removes duplicated recipes, not authority boundaries. The shared
runtime body keeps repository rules, credential/private-material protection,
explicit authorization for destructive Git/production actions, and exception
routes (loopx-project for lifecycle/registry, loopx-self-repair for drift).
These routes are conditional, not mandatory skill calls on every iteration.
Ordinary Claude MCP iterations still use MCP; the CLI route is not a second
accounting path.
| Semantic | Owner after thinning |
|---|---|
| Privacy, repository rules, dangerous-action authority | Shared static safety rule; a trusted host is not blanket permission |
| Lifecycle or projection repair | Conditional static repair route; repair does not bypass gates |
| Selection, claims, vision replan, exact settlement identities/order | Current successful interaction contract, not saved command recipes |
| Blocked path vs whole Goal | Gate only the affected path; continue independent admitted work; only terminal no-follow-up completes the Goal |
| Git branch/worktree/PR policy | User and repository rules; no generic No project branches restriction |
| Prompt authoring/maintenance advice | Documentation, not per-iteration executor instructions |
For heartbeat shells, assign LOOPX_TURN in a separate statement before the
guard, in the same shell invocation. A command-prefix assignment does not make
the variable available to argument expansion in Bash/zsh. Reuse the same value
on retries. Native Goal entry remains host-specific and does not inherit this
heartbeat bootstrap.
Thin's presentation regression ceiling is 3,600 characters; compact remains 6,700. The same 320-character scope plus observed-capability fixture grew from 3,172 to 3,577 normalized characters: explicit reuse of existing action authority, continued integration/negative-case/readback work, recovery evidence and exact current settlement are retained rather than abbreviated away. This is a measured presentation allowance, not an external host limit, execution quota or permission increase. The supported registry-profile brief fixture grows from 4,447 to 4,638; its base ceiling is 4,800 rather than 4,600. Reward-memory headroom remains separately feature-scoped. Larger custom inputs can still exceed a presentation budget and must be measured as supplied. Peer workspace and claim/lease requirements come from the current quota contract and repository rules; registration alone does not impose an independent worktree. Repository-specific worktree requirements still apply.
The automation lifecycle is the reference for shared execution, not a wrapper around native Goal behavior. Thin automation and Codex CLI/SSH, TraeX and Ark Managed Agent Goal bodies share quota dispatch: selection/re-entry, admitted work and validation, then the current writeback/settlement instructions. They do not share scheduler ownership, host completion, or blocked/resume rules.
Native Goal bodies share a compact bootstrap.
Generate it with the host's existing profile (for example heartbeat-prompt
--runtime-profile codex_cli --goal-id <GOAL_ID> --agent-id <AGENT_ID>).
The persistent body binds the Goal/Agent and quota entrypoint; each work iteration
reads the current complete, successful quota JSON. The inner execution
instructions remain in interaction_contract, including selection/re-entry,
admitted work, and exact cli_channel.settlement_plan.ordered_steps.
Native Goal bodies no longer embed a second static accountable refresh/spend
template. Those command fields remain available in the generator response for
compatibility/inspection, but are not a fallback for the live settlement plan.
When no ordered settlement plan applies, consume the current next_cli_actions,
including any required re-entry; do not substitute a saved generator command.
Execute selection/re-entry before work and writeback/spend only after the
corresponding validated work; a projected accounting command is not evidence
that work happened. Preserve the plan's identity and flags, and follow readback
or recovery after an ambiguous write instead of retrying a guessed command.
Failed or incomplete contract reads permit neither work nor spend.
An unbound Codex CLI or Ark Goal with selected Todo/replan work now receives a
quota re-entry template with --turn-instance-id. Fill it with one public-safe
unique work-iteration id and reuse that id on retries. The next packet supplies
the same ordered settlement machinery used by automation, with visible-goal
attribution. SSH Goal continues to use its existing --begin-turn path. This
fixes the previous unbound native refresh/spend projection: those commands could
not satisfy the existing settlement identity guard. It does not turn CLI/Ark
Goals into App heartbeat receipts or move scheduler ownership into LoopX.
The bootstrap retains work-sizing guidance and the distinction between progress and Goal completion. A new Todo is not a new host Goal; quiet/blocked states are not terminal no-follow-up. Codex alone retains its native blocked/resume rule. User/repository authority still applies; a trusted host is not blanket permission. This changes newly generated native Goal bodies and thin automation dispatch, not active host Goal objectives or benchmark prompts already pinned to a run. An installed runtime supplies updated dynamic contracts on later reads; upgrading it does not retroactively remove old text from an existing Goal.
Current instructions follow one chain: fresh guard → typed work_context and
pending required_reads → full quota or TurnEnvelope → Host. Use these sources
for a bounded working brief of evidenced progress/change, current blockers,
next work, acceptance and stops. Missing comparison evidence is unknown, not
unchanged. Preserve complete requirement reads and original settlement identity;
do not freeze a progress summary into the recurring automation or call another
model merely to rewrite it. A changed source requires the existing re-entry.
This is context delivery and Agent guidance, not proof of adoption or improvement.
Behavior change: generated full/compact/thin bodies and the managed project skill no longer invent two-stall replan/self-pause thresholds or a fixed count of alternative candidates. All modes defer to current Core obligations and explicit stop boundaries. Existing Core stall detection and periodic-review cadence remain; local correction preserves valid work, a due review may retain its path, and broader changes need relevant current evidence. The generic external worker also rejects non-boolean admission before its configured wake command; a terminal directive still wins. App-owned automations require the existing Host stop/update and readback path, so this does not promise a pre-model App dispatch hook.
Claude Code's MCP-backed loop.md follows the same work-sizing rule and current
quota contract, without a fixed one-segment limit or empty-Todo-list completion
shortcut. Its complete_task tool already owns the ordered writeback/spend
transaction: callers must not perform a second accounting sequence through CLI.
Partial work is not Todo completion. Native /loop remains Claude's scheduler;
only the current Goal's wakeup may be cancelled after terminal no-follow-up.
These changes apply when loop.md is regenerated, not by editing active user files.
The MCP tool now exposes successor_todo_ids, reusing CLI/TS completion semantics
to link known follow-up without creating another Todo. Ordinary acceptance and
Turn settlement are distinct: the adapter validates/completes work before its
writeback/spend; only terminal closeout requires the full receipt chain. This
removes the former delivery-class circular prerequisite, not validation or
accounting. See the release test guide.
For Codex App, the generated quota command carries the compact explicit runtime
profile --runtime-profile codex_app_heartbeat (generated commands use the
equivalent compact alias --codex-app). The prompt does not restate the
three scheduler ownership fields as prose. Other hosts generate their real typed
execution context instead of inheriting App cadence by omission.
Do not hand-edit per-project lifecycle branches into one automation prompt.
Project-specific behavior belongs in the LoopX registry, active-state
sections, adapter output, or narrow boundary rules. If a lifecycle rule is
generally useful, add it to loopx heartbeat-prompt and its smoke
contract so every project inherits it.
Executable versus watch-only agent follow-up should be registered through the
todo CLI (--task-class and optional --action-kind), then projected by
quota should-run; it should not be encoded as benchmark- or project-specific
prompt text.
When the generated prompt and the installed skill disagree, the worker should
trust the current CLI interaction_contract first, then use the skill as the
operation manual and the prompt only as a bootstrap.
Within that contract, the worker should execute
agent_channel.primary_action. An optional agent_channel.resolution_trace
is for debugging route selection and drift; it should not be treated as another
action to run or as permission to rewrite active-state Next Action.
For a recurring Codex App automation, generate the persistent entrypoint:
loopx --format json --registry <GLOBAL_REGISTRY> heartbeat-prompt \
--bootstrap --thin --codex-app --goal-id <GOAL_ID> --agent-id <AGENT_ID>
Require ok=true and save the returned task_body through automation_update.
It starts with LoopX managed heartbeat bootstrap v2 and loads the current thin
contract on every wake. The embedded command omits --bootstrap, preventing
recursive loaders. New $loopx App activation and existing automation upgrades
use this same renderer. Native /goal hosts retain their own scheduler binding.
--thin, --compact, --brief and --full without --bootstrap return the
current execution or audit body; do not save that changing policy as the recurring
prompt. Connected goals resolve their active-state path from the registry.
Explicit detached-state overrides remain available through --active-state.
Use loopx automation-prompts plan --codex-home <ACTIVE_CODEX_HOME> to inspect
existing prompts, then apply the reviewed desired_prompt through the App API.
Preserve each automation's own goal/agent/task binding, cadence and notification
setting, and read back the result. The offline adapter requires the App closed;
while running, its cached scheduler can overwrite direct database/file changes.
Installing a binary or changing a TOML file alone does not prove migration.
When multiple agents share the same project control plane, first register the public-safe agent ids on the goal, then give each automation an explicit identity and natural-language scope:
loopx configure-goal \
--goal-id <GOAL_ID> \
--registered-agent codex-main-control \
--registered-agent codex-side-bypass \
--agent-model peer_v1 \
--execute
loopx heartbeat-prompt \
--goal-id <GOAL_ID> \
--bootstrap --thin --codex-app \
--agent-id codex-main-control \
--agent-scope "benchmark readiness, benchmark execution, and benchmark writeback"
For another peer, use a different id and a disjoint scope:
loopx heartbeat-prompt \
--goal-id <GOAL_ID> \
--compact \
--agent-id codex-side-bypass \
--agent-scope "control-plane coordination and todo claim ergonomics" \
--agent-scope "do not take benchmark execution todos unless reassigned"
The generated body tells the agent to claim only in-scope todos with
loopx todo claim --claimed-by <agent-id>. --agent-scope requires
--agent-id, and the CLI accepts that agent id only when it is registered for
the goal. Scope stays in the automation prompt or handoff; todo metadata records
only the soft claimed_by owner. Registered identities are peers. Functional
profile roles are advisory, while workspace isolation and continuation behavior
come from the selected task, goal policy, and typed continuation policy.
Generated scoped heartbeat commands pass the same --agent-id to both
quota should-run and quota spend-slot, so workspace guards and quota
accounting evaluate the same identity.
Host capabilities are declarations, not permission grants. When the selected Codex App, CLI, or external launcher already has a capability required by its todos, declare it while generating the heartbeat:
loopx heartbeat-prompt \
--goal-id <GOAL_ID> \
--thin \
--agent-id <AGENT_ID> \
--available-capability network \
--available-capability external_evidence_poll
The generated quota guard and spend command preserve the same declarations. Do not declare credentials, production access, or another capability merely to bypass a gate; the launcher must actually provide it.
When a thin prompt is generated without explicit declarations, it still tells
the runtime worker to project non-basic capabilities that are actually present
with --available-capability. This prevents an observed network or polling
capability from becoming a false user gate without guessing capabilities the
host does not have. Explicit generator arguments remain preferred for hosts
whose capabilities are known when the automation is installed.
- for small AGENTS-eligible validated changes, self-merge and complete the todo
with
--self-merged --evidence "<commit and validation summary>"; - for an independent continuation, create
--next-agent-todoand optionally select a registered peer with--next-claimed-by; - when independent review is required, use
--next-action-kind reviewwith an ordinaryindependent_handoff; add--next-excluded-agent <author>only when the author must not reclaim the unclaimed successor; - when a validated pull request merely needs human review, keep the reminder
non-blocking with
--next-user-todo "<review action>"and--next-user-task-class user_action, then create the next runnable agent todo in the same completion. Add a separatecontinuous_monitorfor the PR lifecycle when merge/readback must be observed. Do not turn review latency into a gate; - when an open advancement Todo reaches an external-only wait before completion,
do not end the heartbeat after polling it. Keep it open and atomically bind
resume_when=monitor_changed:<monitor-todo-id>plus an independent runnable--successor-todo-id, rerun quota, and continue the successor. The typed wait transition is a no-spend lifecycle repair; only later validated delivery is accountable work; - every selected Todo-bound, delivery-enabled must-attempt guard persists
closeout_required=true. A fresh heartbeat checks the immediately preceding flagged guard against its exact writeback/spend receipts and typed Todo lifecycle. If neither is present,unsettled_host_turn_recovery_v0preempts ordinary work selection. For an open advancement Todo without a resume gate, the typedresume_prior_turnroute re-enters the original Turn guard: inspect existing effects first, follow its current eligibility and settlement contract, and account only verified work under that original identity. Missing receipts are not evidence of an external wait; never inventmonitor_changedor a successor to clear recovery. After legal closeout, rerun the same current Turn and continue eligible work. Recovery selection itself is idempotent and no-spend; actual validated delivery retains normal accounting. Genuine external waits and monitor observations retain their existing typed closeouts. Receipts created before the explicit flag are not retroactively treated as unsettled. Exact-ID lifecycle reads include retainedCompleted Work Archiverows, while ordinary Todo lists remain active-only; an archived terminal fact closes recovery without rewriting archive history; - use
user_gateonly for an exact authority boundary such as approval to merge an aggregate branch intomain, release, launch a benchmark, or perform a protected action; - when work is blocked without a valid successor, keep the todo with the current peer and write a concrete blocker rather than inventing a hierarchy route.
Once a goal has coordination.registered_agents, prompt generation without
--agent-id fails closed. That is the lightweight migration signal for stale
Codex App automations: the next refresh attempt surfaces a concrete
identity/scope upgrade command instead of returning a legacy unscoped prompt.
quota should-run follows the same rule for executor safety: an unscoped call
returns automation_prompt_upgrade.required=true,
blocks_should_run=true, and should_run=false instead of allowing delivery.
For a hierarchy-era registry, quota should-run and upgrade-plan return one
stable migration id, one heartbeat command per registered peer, and a completion
command. The host update may be retried with that idempotency key; the completion
command atomically records the migration once, and later quota checks do not
project it again. A registry without coordination.registered_agents must first
register the peer identity before a scoped prompt can be generated.
To inspect a smaller execution body for debugging, generate the brief body:
This is an execution/audit view, not the persistent automation prompt. Use it only when the target agent has LoopX CLI access. It is intentionally small and treats the compact/full lifecycle contract like a skill-style interface that the agent fetches when quota says real work can run or when an edge branch is ambiguous.
To inspect the thin execution body for the current turn:
Use the thin body only when the controller is expected to do a fresh registry/quota/state/status/repo inspection on each wakeup. It should stay project-agnostic; if a behavior needs to be remembered across workers, write it to active state, run history, the registry, or a generated prompt contract rather than hand-editing the automation body.
loopx heartbeat-prompt --thin --format json emits the versioned
heartbeat_agent_input_v1 Agent-input envelope. Its compact
interface_budget reports mode, normalized budget_char_count, max_chars,
and within_budget; generator diagnostics and duplicate commands stay out of
the recurring Agent hot path. Human-readable Markdown and non-thin JSON modes
retain the richer generator packet, including char_count and line_count.
upgrade-plan --format json also carries that richer budget summary inside
each generated prompt, so local default-promotion checks can flag prompt bloat
without parsing prose or relying on a chat thread.
upgrade-plan --format json also carries a compact prompt_policy_audit for
installed prompts when their body is available through the local Codex App
automation record or an explicit manifest. The audit does not echo the prompt
body. It only reports warning kinds such as a generic should_run=false
hard-stop appearing before safe-bypass handling, embedded project policy blocks,
or pinned --active-state arguments. Any warning should be treated as upgrade
work: regenerate the installed heartbeat from the current CLI contract and keep
project-specific policy in registry/state/status/review-packet payloads.
For gray rollout, generate the brief body through loopx-canary and pass
--cli-bin loopx-canary so only the selected goal controller uses the
live checkout:
Opt-in native context delivery¶
--context-delivery {off,on} defaults to on for supported native Codex App/SSH and benchmark heartbeat entries; save the machine setting as off or pass --context-delivery off to disable. An explicitly saved off is preserved. Other hosts and ordinary CLI keep full delivery. It reuses
existing scheduler-owned host declarations and the benchmark worker's explicit
execution settings; it does not guess a host from process names or ambient native
session variables. These declared run modes can activate it:
| Supported entry | Existing host declaration |
|---|---|
| Codex App heartbeat, same-session resume and recovery | --codex-app, equivalently --runtime-profile codex_app_heartbeat (or its complete explicit host tuple) |
| Interactive Codex App SSH Goal | --runtime-profile codex_app_ssh_goal; retains native --begin-turn and visible-Goal settlement |
| Codex benchmark heartbeat worker | Existing generic_cli profile plus the worker-owned LOOPX_EXECUTION_MODE=heartbeat and LOOPX_CONTEXT_DELIVERY=on declarations; its execution owner rejects other modes |
--codex-app is a shortcut for a complete runtime profile. --host-surface alone
is only one field. With on, missing, incomplete, contradictory or unsupported
run-mode declarations are configuration errors: the CLI exits nonzero with a
reason before admission or transport writes, including in native hooks. Correct
the declaration or select off; there is no owner question or new approval.
In a supported run mode, a missing or invalid continuity basis still
delivers the same original full capture. The current recovery reference is saved
before optional delta computation, so an oversized warm request or failed
candidate update cannot select an older capture after compaction or resume.
If the current recovery cannot be saved, the old session lookup is invalidated;
use the explicit original capture reference. If preparation fails before that
can be established, or invalidation also fails, the CLI reports
quota_decision_transport_failed with the saved decision and receipt. Do not
rerun admission to recover a presentation failure.
When the caller also selects --record-host-poll, the existing liveness owner
records that observation once before the original capture. The saved decision,
ordinary/envelope output and native recovery view retain the same
host_poll_receipt, including an unreadable-receipt diagnostic. A capture or
handoff failure still reports an already-recorded poll; its count can advance
even when presentation fails. Reading the original evidence never records
another poll, launches work or spends quota. Without this flag, capture and
context delivery do not create a liveness receipt.
off creates no native journal, hook configuration or input
observation; directories alone never turn it on. This declaration check is not
host authentication, execution authority or proof of retained input. Native
delivery uses the explicit lifecycle assumption described below; final-input
Host clients keep their independent retained-input confirmation contract.
Other generic CLI and native Goal profiles, Claude and other hosts remain outside
this opt-in. Harbor/container and installed desktop adoption retain their separate
unqualified boundaries; listing an entry does not certify live adoption.
For a trusted Codex host, render the native setup through the installed CLI. Private context/capture directories are selected and created automatically under the resolved machine runtime; advanced callers may override those locations:
loopx --format json quota context-config --context-delivery on --codex-app \
--goal-id <goal> --agent-id <agent>
The result contains native_config.config_overrides, native_config.hooks and
native_config.developer_instructions. Merge the hooks into the host's existing
hooks.json or inline hook configuration, and append the recovery instruction to
its existing developer instructions. Apply each flat key/value in config_overrides
to the native host configuration (or as a -c key=value override). This selects
64000-byte context continuations, a 20000-token history limit, and a shell-scoped
reader budget declaration. The initial guard uses the same output budget. Its instruction requests
22000 tokens per reader result and 24000 for code-mode emission, with one directly
forwarded stdout per call. Native paging uses this default without the shell declaration;
the isolated benchmark worker applies this profile automatically when opted in.
Keep short context readers in the foreground (exec_command's normal 10000 ms
wait). Early output followed by polling can leave the native post-tool hook with
only an empty tail, so a visibly complete page still cannot establish a baseline.
Consume every chunk if a command yields and preserve full fallback when hook
coverage is incomplete; do not re-admit or invent a retention receipt.
Preserve other configuration. Review and
trust only these exact hooks through Codex's native hook trust surface; the CLI
does not install files, approve hashes, enable diagnostics or run a guard.
Rollback removes these generated output overrides along with the context hooks
and recovery instruction; restore any previous host values. The profile does not
establish model retention, task gains or net fee savings.
An already loaded native thread may keep its earlier hook configuration even
when hooks/list discovers the new handlers as enabled and trusted. That readback
does not deliver SessionStart or initialize its context journal. After active
work reaches its normal safe boundary, use the host's start/resume path with the
resulting configuration and verify actual lifecycle delivery before qualifying
live use. Do not restart an active host merely to manufacture a sample. Until
then, preserve full delivery and the original capture; do not fabricate events
or borrow another session's journal.
Use one configuration for the declared Goal/Agent. A shared private root keeps
different native sessions in separate journals, including interleaved sessions.
For an interactive SSH Goal, use --runtime-profile codex_app_ssh_goal in place
of --codex-app for both setup and the thin prompt. It retains the 4000-character
native Goal limit and the full command paths, with the same live contract and
native blocked/resume rules; it does not become a hosted heartbeat.
Generate the normal bootstrap with heartbeat-prompt --thin --codex-app
--bootstrap, its existing Goal/Agent/registry arguments, and
--context-delivery on; optionally add --turn-envelope or explicit private paths. The loader preserves
these options without freezing a Turn ID. Each wake loads current instructions
and binds the existing LOOPX_TURN before its generated guard. Selection keeps
the same transport. An unset wake identity fails in the shell before admission.
Native guards and JSON recovery readers use the existing 64000-byte output profile even when an App shell lacks the configuration environment override. Small captures finish inline; larger captures continue with the same large-page budget. Explicit smaller budgets remain available for truncated-range recovery. The native hook accepts complete JSON records alongside other shell output and still verifies each record against the trusted original capture before reuse.
Native reuse assumes a normally completed full read was read and remains
available until a lifecycle invalidation. PostToolUse merges complete reader
ranges in the existing private session journal. EOF alone, known read failures,
malformed/truncated pages and interrupted paging cannot establish a baseline.
Compaction, clear, fork, session/workspace change and unqualified SessionStart
invalidate it; ordinary tools and turn endings do not. A same-session resume can
retain its baseline only when the native replay checkpoint verifies continuity.
Read the pinned original completely before establishing a new differential chain.
Repeated events and parallel pages are idempotent.
Workspace identity comes from native lifecycle events, not a shell command's
working directory. The same native session can run projection and recovery
commands in a subdirectory or another checkout without discarding its baseline.
A native SessionStart reporting a changed workspace still retires the previous
candidate and recovery selector. Session, Goal and Agent isolation remains in
force; changing command directories grants no work or publication authority.
工作区身份由原生生命周期事件确定。命令切换到子目录或另一 checkout 不会清除同一
原生会话的差分基线;原生 SessionStart 报告工作区变化时仍清除旧基线和恢复选择器。
Session、Goal 和 Agent 隔离保持不变,切换命令目录不授予工作或发布权限。
This replaces per-request input-history proof, not the capture integrity check.
It preserves native providers, authentication, endpoints and connection mode,
including implicit history. No input diagnostics or forced HTTP is required.
Unreported downstream output loss or missed/externally disabled hooks can escape
detection; this is an engineering assumption, not measured retention or a model ACK.
Read back native hook discovery/trust and the generated guard options, then
verify cold full, warm delta after completed reader delivery,
resume and compaction recovery on the actual host. The persistent instruction
names quota context-read --codex-context-root ... when an entire hook is lost;
lookup is read-only and subsequent pages pin the original file/hash. It never
readmits or spends. Normal native trust/settings UI remains the activation and
error surface; failed setup keeps the full path. Explicit off stops projection.
Replacing machine configuration also invalidates reuse, so an off/on round trip
cannot reuse a baseline that missed lifecycle events while disabled.
An existing decision-handoff socket may use this same capture. Handoff validates
and releases the immutable original first; native projection follows release.
It does not create a second checkpoint or change the handoff's failure/recovery
rules. If interrupted while held, consume the original full continuation packet.
For a host that already saved the quota decision before invoking Codex, present that immutable snapshot from the native tool instead of running its guard again:
loopx --format json quota context-project --context-delivery on --codex-app \
--capture-file <original-quota-json> --capture-sha256 <original-sha256> \
--goal-id <goal> --agent-id <agent> --turn-instance-id <original-turn> \
--codex-context-root <private-context-root> --decision-output-root <private-capture-root>
The JSON response supplies mode, the digest-pinned read command, the target
when available, and an original full recovery reference. Cold mode delivers
complete context plus its target; a warm delta names its native-hook continuity
basis. Follow every page and reconstruct before dependent work. Optional codec
or delivery-cache failure after recovery publication falls back to that same
full capture. Enabled native preparation or unsafe recovery publication fails
with ok: false, quota_decision_transport_failed, and the original recovery
reference and receipt; follow that explicit reference instead of a session lookup.
Invalid source hash or Goal/Agent/Turn refuses publication. This is integrity-checked presentation of
the caller's snapshot, not fresh authority, registry lookup, installation,
admission or accounting. The original file stays unchanged; generated caches
remain private. A missing projection command can use quota context-read with
the original file/hash. Set --context-delivery off and remove context options from generated host
configuration to restore ordinary full-read instructions. Remove only these generated hook entries and
appended recovery instruction from native configuration. Preserve unrelated
diagnostics, providers, hooks and settings; the CLI does
not edit host configuration. No stored decision or receipt is rewritten.
To roll back, remove the context/capture options from this bootstrap and remove
only the generated hooks/recovery instruction from the native configuration.
Existing captures remain private recovery evidence. This opt-in does not grant
execution authority or prove installed App adoption or net token savings.
Template¶
Generate the persistent prompt from the installed runtime:
loopx --format json heartbeat-prompt --bootstrap --thin --codex-app \
--goal-id <GOAL_ID> --agent-id <AGENT_ID>
Read the successful result and install its task_body through the authorized
host automation API, preserving the existing automation identity, schedule and
notification preference. Read back the saved prompt and status before claiming
activation. Omit --agent-id only for a goal with no registered peer requirement.
For native Goal hosts, use their actual --runtime-profile instead of --codex-app.
Optional --active-state, material and permission overrides bind only explicitly
selected policy. Connected goals normally resolve state from the current registry.
Do not hand-copy a generated execution body, Turn id, settlement command or project
policy into this persistent template. The loader fetches those current instructions
on every entry; an unsuccessful/incomplete read authorizes neither work nor spend.
Minimal User-Facing Form¶
Keep the visible objective short, for example “Advance this Goal within its current authority and acceptance criteria.” Set the generated host-specific loader as the execution entrypoint. The visible objective is not an alternative quota, authorization or settlement contract.
The old hand-written full and minimal templates duplicated runtime rules and could direct a stale refresh/spend or reuse the wrong host binding. They are replaced by the generator above. Existing saved prompts need the ordinary upgrade/readback flow; editing this document does not migrate active automations or pinned benchmark runs.
Host Scheduling And Stop Readback¶
When creating a heartbeat in Codex App, keep the visible instruction short and
use the generated bootstrap loader as the automation task body. The default onboarding cadence
starts at 3 minutes; after the first guard, follow
quota should-run.scheduler_hint to back off long waits and stop external loops
after a final quota/replan check confirms repeated unchanged polls. App-hosted
heartbeats should search/use automation_update when available. If
scheduler_hint.action=stop_until_explicit_resume and
scheduler_hint.app_automation.host_action=pause_or_delete_current_heartbeat: in
that stop case, call automation_update once to pause the current heartbeat,
verify the host result, spend no quota, and end the turn without a scheduler ACK.
Full, compact, brief and thin generated bodies retain this same stop clause.
If the tool is unavailable or the result does not confirm the current heartbeat
stopped, leave that outcome unresolved; do not claim success, retry, change the
RRULE as fallback, or perform new work/spend. Output still follows the user
notification contract. An App-owned wake may already have invoked the model
before it reaches this guard. Regenerating a body does not update an existing
installed automation: apply the new body through the existing host update flow,
retain its identity, and read back its prompt/status. Otherwise call it only when
scheduler_hint.app_automation.stateful_backoff.apply_needed=true and
scheduler_hint.app_automation.recommended_rrule is present. After a successful
RRULE update, run loopx with
scheduler_hint.app_automation.ack_hint.cli_args; current payloads use
quota scheduler-ack-current so LoopX re-reads the latest hint and owns the
progression/reset state. The ACK settles that RRULE; an immediate final guard
may verify the same target but must not be treated as another elapsed poll.
Attempt the host update at most once per hint and
turn. If it fails or times out, do not retry or ACK; run
scheduler_hint.app_automation.failure_hint.cli_args once to persist the failed
target and observed host RRULE without spending quota. Exact repeats are then
suppressed until either value changes. Continue any allowed delivery under the
observed host cadence. When the desired RRULE is already applied, skip
automation_update; if stateful_backoff.ack_needed=true, run the bound ack
hint directly, otherwise do nothing. For the uniquely matched current heartbeat,
quota should-run reconciles the installed RRULE with the ACK ledger; a
host_observation.status=drift_detected result reopens apply_needed.
If automation_update is unavailable in the session and
scheduler_hint.app_automation.fallback_hint.available=true, run the bound
fallback_hint.cli_args (loopx-apply-rrule) once instead. The fallback
requires the projected registered --agent-id; there is no implicit Agent
default. It backs up
codex-dev.db, syncs the automation TOML and SQLite row, and runs the bound
ACK; direct SQLite edits bypass the app API, so this is a bounded fallback and
never the routine path. The bridge reuses the provided parent Turn for its
internal quota should-run query. That same-Turn replay preserves the committed
receipt's bound Todo, observed capabilities, and settlement identity; an
explicitly conflicting identity still fails closed. When the automation id
could not be resolved,
fallback_hint.available=false and the pasteable heartbeat gate is the correct
stop - never guess an automation id.
Agent Checklist¶
For every automatic heartbeat turn, the agent-facing checklist is:
- Guard first:
quota should-run --turn-instance-id <HEARTBEAT_TURN_ID>using this trigger's<current_time_iso>and reusing it for same-heartbeat retries. If the caller has already chosen the unfinished work for this new Turn, append--todo-id <chosen-id>to that first guard. This requests current qualification and complete required context in one call; it does not adopt the previous Turn's authority, read coverage or settlement. Read the current contract before work and follow rejection/recovery when the choice is stale or gated. When the choice is unknown, discover candidates and then use the returnedselection_command. Never guess a Todo or change an existing Turn binding to avoid a read. Same-Turn compaction alone does not start this flow. 若本次新 Turn 已明确继续哪项未完成工作,可在首次 guard 中直接附加--todo-id <chosen-id>,一次取得当前资格及必要上下文。旧任务引用不继承旧 权限、阅读覆盖或结算身份;仍须读取当前合同,过期或受限时按返回结果恢复。 尚未选定工作则先发现候选,再用selection_command;不猜测任务、不为少读 一次而更换既有 Turn 绑定,同一 Turn 的压缩恢复也不触发这条新准入路径。 Ifloopxis not initially on PATH, export$HOME/.local/bin:$PATHand run the local installer fallback before declaring preflight failure. - If
should_run=falsewithstate=operator_gate, ask the user/controller the current gate unless the same unresolved gate was already surfaced recently. Every heartbeat guard commits one idempotent receipt. Ifeffective_action=monitor_quiet_skip, it also commits the no-spend stall observation and returns the follow-up decision; do not append another manual poll. Return quietDONT_NOTIFYif it remains monitor-only. Keep monitor todos visible but do no delivery edits and no spend until material evidence changes or the guard exposesautonomous_replan_required/execution_obligation.must_attempt_work=true. - For
notify_user_on_open_todo=true, follow the currentinteraction_contract.user_channelfor the concrete notice and cooldown. This notification flag does not decide delivery or accounting:interaction_contract.agent_channelowns admitted work, andinteraction_contract.cli_channelowns its settlement. A pureuser_todo_blocker_pushlane with no admitted work does no delivery or spend;bounded_delivery_with_user_noticeor an admitted safe bypass still requires its work and current settlement. Ifopen_todo_notification_policy=repeat_until_resolved, repeat the concrete notice only while the current user channel returnsNOTIFY, until the todo is done, deferred, or replaced. Ifuser_gate_notification_cooldown.notification_suppressed=true, keep the gate pending but return quietDONT_NOTIFYuntil its bounded reminder window or a material gate/host change. Otherwise, ordinary blocker-push asks may be de-duplicated when the same blocker was surfaced recently. - If
effective_action=outcome_floor_recoveryorrecovery_delivery_allowed=true, treatshould_run=trueas a recovery turn: run only the bounded evidence/blocker recovery and spend only after validated writeback. - If the gate was already surfaced and
safe_bypass_allowed=true, either take one independent safe-bypass step or report the pending gate compactly. - If the current goal is eligible, dependency or sibling-goal open user todos must not stop the whole turn; record or surface them, then keep looking for a gate-independent P0/P1/P2 candidate for the current goal.
- Run the steering audit before choosing the work.
- Use
attention_queue.items/project_assetas current routing authority; if project_asset is absent or legacy/raw fallback, raw queue fields are not owner/gate/stop authority. Userun_history.latest_runsonly as evidence or drill-down. - Follow
execution_obligationbefore deciding quiet no-op:heartbeat_recommendation.notifyis not an execution gate. Ifmust_attempt_work=true, do one bounded progress batch or segment even whennotify=DONT_NOTIFY; quiet no-op only whenmust_attempt_work=falseand the currentinteraction_contract.user_channel.notify=DONT_NOTIFY. Then followheartbeat_recommendation: first connected read-only goals should run one realread-only-map, while already mapped unchanged goals should return a quiet no-op without another dry-run or quota spend. - Check
delivery_batch_scale,delivery_outcome,post_handoff_outcome_gap_streak, andhandoff_delivery_contract; for repeated-small or surface-only loops, obey the contract. - Follow current Core repair/replan obligations. Correct the affected work first; widen only on relevant evidence and check subsequent adoption/results. A due review may keep the route. Wake counts grant no replan or self-pause authority; explicit/Core/host stops and original settlement still apply.
- Complete the Todo under its original declaration and current lease; do not
invent a successor or
--no-follow-up. Todo completion does not settle the Turn: follow its current ordered settlement, then read back continuation or terminal Goal completion. A real follow-up reuses the existing successor. - Plans/top todos/route changes need LoopX todo / Next Action writeback or a no-writeback rationale.
- Reuse existing action-specific authority for public-safe commit, push and PR creation after validation and boundary checks. Gate missing authority only on the affected path; protect private evidence and credentials. Destructive Git, production and explicit repository review gates retain their authority.
- Continue authorized work through implementation, integration, negative cases and readback while feasible. Preserve evidence, remaining gaps and the next action for recovery; a tool call or writeback does not complete the Goal. Obey explicit user, Core and host stops and preserve owed settlement.
- Validate before reporting.
- After validation/writeback, follow the current typed settlement plan. An exact committed receipt-bound monitor poll already closes that Turn with no accountable refresh or quota spend, including a material poll that releases an independent successor. Other accountable delivery refreshes use explicit scale/outcome hints and spend exactly once against that record.
- Refresh state-only metadata after spend only when needed; never emit another accountable progress refresh after accounting.
- Report compactly.
This prompt is intentionally a lifecycle template. Scheduling policy lives in
quota should-run.scheduler_hint, so per-project heartbeats, a shared
controller loop, Codex CLI TUI, Claude Code loop, or future Codex goal-mode
automations can all share the same LoopX quota guard without hard-coding
different wait loops. Host implementations should first honor a terminal
app_automation.host_action=pause_or_delete_current_heartbeat by stopping the
current heartbeat once, verifying the result, and ending without scheduler ACK
or quota spend. Otherwise they should read the compact
app_automation.stateful_backoff packet, call automation_update only when
apply_needed=true, and then let quota scheduler-ack-current persist the
applied RRULE state from the latest scheduler hint without spending quota. A
matching reset readback may instead set ack_needed=true; in that case skip the
host write and execute the bound ack directly.