Status Data Contract
August 2, 2026 · View on GitHub
loopx --format json status is the stable first-screen data contract for
agents, heartbeat jobs, dashboards, and local UI experiments.
The command is an export: it reads the registry, compact run indexes, and the
public/private contract check, then emits one JSON object. It does not inspect
private run payloads beyond compact index fields and does not mutate files.
The export is agent-facing machine state. A dashboard should consume this
contract and translate it into a human operator view rather than treating raw
CLI fields as product copy.
In particular, first-screen dashboards should translate raw machine fields such
as single_surface, focus_wait, quota_slot_spent, or concurrency snippets
into the operator's language before presenting them as primary copy. The
machine tokens may remain in drill-down views, logs, or packets where exact
debuggability matters.
When a command is run outside a project-local .loopx/registry.json,
the CLI falls back to the shared local global registry at
~/.codex/loopx/registry.global.json if it exists. That registry is
maintained automatically by connect and refresh-state so each project agent
can update its own local state while dashboards still see the multi-project
view.
For local dashboards, the same JSON shape can be served over loopback HTTP:
loopx serve-status --global-registry --port 8766 --limit 80
The default endpoint in that example is http://127.0.0.1:8766/status.json.
--global-registry is the canonical multi-project dashboard mode: it serves
the shared global registry even when launched from inside a project checkout,
avoiding a project-local registry scope warning. For project-local debugging,
omit --global-registry or pass the project registry explicitly. The server is
intended for local dashboard development and includes CORS headers so a Vite app
on another localhost port can fetch it.
The disposable loopx demo path intentionally uses a project-local
server on 127.0.0.1:8765; it does not sync the temporary demo into the shared
global registry.
Each project-backed attention_queue.items[] row may include a read-only
goal_channel_projection object with
schema_version=goal_channel_projection_v0. This is the dashboard/frontstage
projection of the same status item: current decision frame, user and agent
todos, quota, soft claims, compact run events, source warnings, and an explicit
truth contract. It is not a write API. Dashboards may render it as a channel
card or timeline, but project truth still comes from the registry, active
state, quota guard, and append-only run history.
Rows may also include an optional task_graph_projection object with
schema_version=task_graph_projection_v0. The default status hot path omits
this graph to preserve the dashboard interface budget; callers that need the
graph can request it with loopx --format json status --include-task-graph, or
use a full review packet. This is a compact graph-shaped view over existing
todos, gates, leases, run ids, and event-ledger state. It is read-only and
exists only to show dependency, validation, repair, audit, continuation, and
handoff relationships that are hard to scan in a flat todo list. It must not
introduce a second scheduler, graph write API, hidden lease store, or alternate
task truth.
The protocol is defined in
docs/reference/protocols/task-graph-projection-v0.md;
consumers should ignore the field when absent.
Rows may also include an optional openviking_session_memory_adapter object
with schema_version=openviking_session_memory_adapter_v0. This is a
public-safe session-runtime specialization for OpenViking-style issue memory:
compact issue refs, session refs, memory refs, retrieval gates, status
projection, and evidence projection. It is read-only and must not perform live
OpenViking retrieval, write memory, read issue/comment bodies, ingest raw tool
outputs or trajectories, or publish external issue comments/PRs. The protocol
is defined in
docs/reference/protocols/openviking-session-memory-adapter-v0.md;
consumers should ignore the field when absent.
Rows may also include an optional local_agent_launch_plan object with
schema_version=local_agent_launch_plan_v1. This is a dry-run preview over
configured agents, role assignments, non-executable launch preview rows,
status projection, evidence projection, and future gates. It is read-only and
must not start local workers, call external agent services, expose shell
commands, write LoopX state, or grant host authority. The protocol is defined
in
docs/reference/protocols/local-agent-launch-plan-v1.md;
consumers should ignore the field when absent.
Loopback status exports include status_contract.schema_version. The dashboard
uses that small protocol marker to detect when 127.0.0.1:8766 is still served
by an older daemon or release snapshot after the checkout has moved forward. If
the field is absent or below the dashboard's expected version, the product UI
should warn the operator and point to the safe reload path:
scripts/macos-dashboard-launchagent.sh restart.
The same local server exposes POST /reward/dry-run for dashboard reward
validation. It accepts the selected goal_id, run_generated_at, compact
reward fields, and public-safe summary text, then returns a compact validation
result with appended=false. It also returns the same coordination fields as
the CLI: active_state_summary and project_agent_visibility. It does not
mutate the run index and does not return private artifact paths.
When status is served over loopback HTTP, /status.json also includes an
optional local_dashboard_api capability block. CLI status exports may omit it
because they are plain read-only snapshots. The block is the dashboard's machine
contract for local write affordances:
{
"local_dashboard_api": {
"source": "serve-status",
"reward_dry_run_url": "/reward/dry-run",
"reward_append_url": null,
"reward_write_enabled": false,
"configure_goal_dry_run_url": "/control-plane/configure-goal/dry-run",
"configure_goal_apply_url": null,
"control_plane_write_enabled": false
}
}
The dashboard frontstage ops route uses a TanStack Query-backed local status
reader for /frontstage?mode=ops&statusUrl=<relative-or-loopback>. Showcase
mode still ignores statusUrl; only explicit ops mode may fetch a status feed.
The query layer validates status_contract.schema_version before trusting a
loopback feed. If the feed is below the dashboard's expected schema version,
the route shows stale-daemon repair copy using status_contract.reload_hint
instead of silently rendering an old protocol.
The same frontstage query layer projects local_dashboard_api as capabilities,
not browser authority. It may show that reward dry-run or control-plane dry-run
URLs are advertised, but write affordances stay disabled unless the feed is
relative or loopback, the matching URL is present, and the corresponding
*_write_enabled flag is true. The frontstage must remain read-only by default;
any future write UI must still use preview-locked local APIs and keep CLI/event
ledger state as the source of truth.
The control-plane settings write path follows the same opt-in rule as reward
append. By default serve-status validates dashboard setting drafts through
POST /control-plane/configure-goal/dry-run but does not expose an apply
capability. Starting the loopback server with
--enable-control-plane-write-api exposes
POST /control-plane/configure-goal/apply; the dashboard should enable Apply
only when local_dashboard_api.control_plane_write_enabled=true and the apply
URL is present. Apply requests must reuse the fresh preview_id from the
dry-run response.
Control-plane setting drafts may use multi_subagent_feature="enabled" to opt
into bounded child-agent orchestration, or "off" to keep the default
single-agent mode. This is a product wrapper over the registry spawn_policy;
dashboard surfaces should prefer it over exposing raw orchestration_mode plus
spawn_allowed toggles.
Command
loopx --format json status > goal-status.json
By default, status scans the LoopX install root for public/private
contract health. Use narrow scan paths only when you intentionally want the
status export to check a specific public-safe project surface:
loopx --format json status \
--scan-path README.md \
--scan-path docs/ \
--scan-path examples/
For compute allocation, loopx quota status and
loopx quota plan derive an agent-facing grouping from this same status
payload. loopx --registry "$HOME/.codex/loopx/registry.global.json" quota should-run --goal-id <goal-id> derives a per-goal automation guard from
that grouping for project heartbeats. These are read-only views, not a separate
source of truth. Scripts should treat summary.next_automatic_turn in the
quota-plan JSON as advisory and still respect the displayed health, operator,
and evidence gates.
The per-goal guard also emits heartbeat_recommendation, a compact executor
hint for generic lifecycle cases such as first read-only map runs and quiet
mapped no-ops. Project-specific policy should still come from the registry,
active state, adapter output, or boundary rules rather than ad hoc scheduler
prompt branches.
Registry entries may also declare compact control_plane settings. These
settings are per-goal policy, not global prompt text. By default
control_plane.self_repair.enabled=false; only registry-enabled goals can turn
health or waiting-projection stalls into a quota should-run self-repair
machine contract.
When the selected attention item is project-asset backed, the per-goal guard
also carries compact handoff_readiness with handoff_status and
post_handoff_run_seen. Heartbeat jobs can therefore tell whether the selected
goal is still waiting for a target run or has already seen post-handoff work
without parsing the full status payload.
For replan and handoff, the guard and review packet may also carry
required_reads / project_agent_required_reads entries that point to
loopx evidence-log --goal-id <goal-id> --agent-id <agent-id> --thin. Treat
that command as the cold-path chronology for the selected agent lane: it expands
the current agent's public-safe events, keeps other agents compressed to
frontier context, and does not replace status, quota, review packets, or the
append-only event sources.
The same guard may include work_lane_contract. Schema
work_lane_contract_v1 is the compatibility drill-down for monitor versus
advancement routing under the guard's first-class interaction_contract. It
distinguishes lane=continuous_monitor from lane=advancement_task, carries
the next lane, and exposes one obligation string such as
advance_unless_material_monitor_transition. Agent todo items
may include task_class=advancement_task or
task_class=continuous_monitor, plus optional action_kind such as
run_eval, validate, rebuild, writeback, monitor, or poll. Explicit
task_class is authoritative for the todo item itself; recognized generic
action_kind can infer the lane when task_class is absent; legacy todo text
is only a compatibility fallback. The selected goal's
next_action/recommended_action can still promote an otherwise monitor-only
todo set back to lane=advancement_task when it names an executable chain such
as collecting repeats, rebuilding labels, rerunning a scorer, or validating an
eval gate. Hidden open todos are treated as advancement work rather than as
monitor-only work, so a truncated top-N todo projection cannot accidentally
silence an executable backlog.
For a dependency-observation projection with open agent todos, the guard sets
next_lane=advancement_task, must_attempt_work=true, and
reason_codes=["dependency_observation", "open_agent_todo"] only when at least
one open todo is advancement-class work. If all visible open todos are
monitor-class and no open todo is hidden, the guard sets
obligation=quiet_until_material_monitor_transition and
must_attempt_work=false. One narrow exception prevents long autonomous
projects from stalling after finishing their last visible delivery todo: when
the current next_action/recommended_action explicitly points at an
advancement-class executable chain, monitor-only todos are promoted to
lane=advancement_task with
obligation=materialize_advancement_todo_or_blocker. That obligation requires
the worker to create a concrete advancement todo or write a blocker instead of
quietly waiting on monitors. The heartbeat recommendation may say
follow_work_lane_contract or monitor_quiet_until_material_transition, but it
should not restate the lane semantics; unchanged monitor polls remain quiet
no-spend checks with should_run=false and
effective_action=monitor_quiet_skip, while a material dependency-state
transition may be written back once when it changes the selected goal decision.
When final agent-scope projection selects a non-execution wait such as
effective_action=agent_scope_wait, the exposed work_lane_contract must also
be non-executing (must_attempt_work=false) even if a goal-level next action
would otherwise derive an advancement obligation. The original goal-level lane
may remain as compact deferred diagnostic context, but executors must not treat
it as a competing obligation.
handoff_readiness.handoff_interface_budget declares the machine-readable
budget for the minimal project-agent handoff: mode=project_agent_handoff,
max_lines=16, and max_chars=1800. loopx review-packet --handoff-only --format json returns the same contract plus live line_count,
char_count, and within_budget, so a short heartbeat can reject handoff
bloat without carrying this rule in prompt text.
For spend accounting, status derives spent_slots from compact
quota_slot_spent runtime events in the current quota window. The registry
remains the policy source for compute share and window size, not the spend
ledger.
quota_slot_spent is status-neutral accounting: it must remain visible in run
history for quota audit, but status and attention queues should use the latest
non-accounting run as the current work state.
More generally, status should expose projections over the append-only event
ledger rather than acting as the ledger itself. Work classifications, human
reward overlays, operator-gate resume contracts, quota spend rows, evidence
polls, blocker writebacks, and artifact validations should remain auditable as
events; dashboards and heartbeat prompts consume compact projections of those
events for current-state decisions.
In lane terms, next_automatic_turn may only name the first eligible goal;
operator-gated, focus-waiting, waiting, throttled, paused, and health-blocked
goals must stay out of the eligible lane even when they have a high
quota.compute.
Top-Level Shape
{
"ok": true,
"registry": ".loopx/registry.json",
"runtime_root": "./runtime",
"goal_count": 3,
"run_count": 2,
"goal_filter": null,
"status_contract": {
"schema_version": 2,
"minimum_dashboard_schema_version": 2,
"producer": "loopx status",
"reload_hint": "scripts/macos-dashboard-launchagent.sh restart"
},
"contract": {
"ok": true,
"summary": {
"errors": 0,
"warnings": 0,
"checks": 4
},
"errors": [],
"warnings": [],
"checks": [
"registry goals checked: 3",
"runtime indexes checked: 3",
"run-history goals=3 runs=2",
"public boundary scan clean: 12 files"
]
},
"global_registry": {
"available": true,
"ok": true,
"registry": "~/.codex/loopx/registry.global.json",
"current_registry": ".loopx/registry.json",
"current_registry_is_global": false,
"global_goal_count": 4,
"current_goal_count": 3,
"source_registry_count": 2,
"summary": {
"high": 0,
"action": 0,
"info": 1,
"checks": 2,
"findings": 1
},
"findings": [],
"checks": []
},
"attention_queue": {
"available": true,
"item_count": 2,
"needs_user_or_controller": 1,
"needs_controller": 0,
"needs_codex": 1,
"watching_external_evidence": 0,
"watching_monitor": 0,
"autonomous_backlog_candidates": {
"source": "attention_queue.agent_todos",
"open_count": 1,
"task_class": "advancement_task",
"items": [
{
"goal_id": "loopx-meta",
"quota_state": "eligible",
"priority": "P1",
"todo_index": 1,
"task_class": "advancement_task",
"text": "Add an autonomous backlog candidate surface for eligible goals.",
"source": "agent_todos"
}
]
},
"items": []
},
"run_history": {
"available": true,
"goal_count": 3,
"run_count": 2,
"goals": [],
"recent_runs": []
},
"event_ledger_summary": {
"available": true,
"source": "run_history",
"sample_run_count": 2,
"proxy_note": "append-only run-history projection; compact event-class counts only",
"event_classes": ["accounting", "decision", "evidence", "state", "work"],
"totals": {
"events_24h": 2,
"events_7d": 2,
"benchmark_runs_24h": 0,
"benchmark_runs_7d": 0,
"by_class_24h": {
"accounting": 1,
"decision": 0,
"evidence": 0,
"state": 1,
"work": 0
},
"by_class_7d": {
"accounting": 1,
"decision": 0,
"evidence": 0,
"state": 1,
"work": 0
}
},
"goals": []
},
"promotion_readiness_summary": {
"available": true,
"source": "runtime_release_ledger",
"evidence_scope": "runtime_release",
"goal_id": null,
"dashboard_readiness": "passed",
"generated_at": "2026-06-01T00:08:00+00:00",
"classification": "canary_promotion_readiness_smoke_group",
"delivery_batch_scale": "multi_surface",
"delivery_outcome": "primary_goal_outcome",
"json_exists": true,
"markdown_exists": true,
"freshness_window_hours": 24,
"freshness_status": "fresh",
"is_fresh": true,
"requires_readiness_run": false,
"age_seconds": 120,
"age_hours": 0.03,
"sample_run_count": 1,
"proxy_note": "canary promotion-readiness projection from the runtime release ledger with legacy goal-history fallback; exact evidence stays in append-only artifacts"
},
"promotion_gate": {
"ok": true,
"gate": "promotion_readiness",
"gate_state": "ready",
"can_promote": true,
"should_warn": false,
"non_blocking": true,
"recommended_action": "promotion readiness is fresh",
"readiness": {
"freshness_status": "fresh",
"requires_readiness_run": false
}
},
"decision_freshness_summary": {
"available": true,
"source": "run_history",
"sample_run_count": 2,
"window_days": 7,
"proxy_note": "checkpointed decision freshness projection; rebase old decisions at the decision point before reuse",
"summary": {
"decision_count": 1,
"stale_count": 0,
"rebase_required_count": 1,
"fresh_count": 0
},
"items": [
{
"goal_id": "loopx-meta",
"decision_kind": "operator_gate",
"decision_at": "2026-06-01T00:05:00+00:00",
"classification": "operator_gate_approved",
"age_days": 0.2,
"stale_by_age": false,
"newer_event_count_7d": 1,
"newer_event_classes_7d": {
"accounting": 1,
"decision": 0,
"evidence": 0,
"state": 0,
"work": 0
},
"freshness_state": "rebase_required",
"requires_decision_point_rebase": true,
"reason": "newer sampled events exist after decision; rebase at decision point"
}
]
},
"usage_summary": {
"available": true,
"source": "run_history",
"sample_run_count": 2,
"proxy_note": "run-history proxy; excludes token counts and raw thread logs",
"totals": {
"runs_24h": 2,
"runs_7d": 2,
"quota_spend_slots_24h": 1,
"quota_spend_slots_7d": 1,
"automation_run_count_24h": 1,
"automation_run_count_7d": 1,
"progress_signal_run_count_24h": 1,
"progress_signal_run_count_7d": 1
},
"goals": []
}
}
By default loopx status is the multi-goal dashboard/control-plane view.
loopx status --goal-id <goal-id> keeps global health fields such as
global_registry, while its contract projection contains only global errors
plus errors owned by the selected goal. It also focuses goal-scoped sections
such as attention_queue, run_history, event_ledger_summary,
usage_summary, and todo_index on the requested goal. Use
loopx diagnose --goal-id <goal-id> when an agent needs the richer reasoning
packet for one goal.
Consumers should treat unknown fields as additive. Required fields for a
first-screen UI are ok, contract, and attention_queue.
status_contract, event_ledger_summary, promotion_readiness_summary,
promotion_gate, decision_freshness_summary, and usage_summary are optional and should be
treated as compact protocol or run-history projections, not as the ledger
itself, billing telemetry, token telemetry, or a release operation source. A
missing status_contract means an older status producer; loopback dashboards
should surface that as a daemon freshness warning rather than silently hiding
newer panels.
Interface Budget Cadence
When a run-history record includes interface_budget_cadence,
loopx status projects a compact copy under
attention_queue.items[].project_asset.interface_budget_cadence. For the
selected goal, quota should-run also mirrors the same object at top level as
interface_budget_cadence.
This field is a restraint signal for heartbeat workers, not a dashboard feature
request. It records the latest clean hot-path budget check, the tightest
headroom observed, and when the next check is due. Fresh clean checks can
support a quiet skip for the ongoing interface-budget guard only while the
tightest metric still has positive headroom; overdue, out-of-budget, or
zero-headroom checks should prompt python3 examples/control_plane/hot-path-interface-budget-smoke.py or an equivalent explicit
drift-check run.
Stable fields:
checked_atfreshness_hoursnext_check_due_atoverduewithin_budgetsurface_countminimum_headroom_ratiotightest_surfacetightest_metricheadroom_remainingrecommendation
Promotion Gate JSON
loopx promotion-gate --format json is the compact machine-readable
gate for local release promotion. It reads the same append-only readiness event
as doctor, status, and install-local.sh, then returns a small operation
result that scripts can assert without parsing installer stderr.
This command is read-only and non-blocking. can_promote=false means the
installer should warn before promotion, not that the CLI refuses to install.
The warning remains a human-facing guardrail; automation should use
gate_state, can_promote, should_warn, and readiness.freshness_status as
the stable fields.
loopx status --format json embeds the same compact result under
promotion_gate, so dashboard panels, installer smoke, and CLI gate checks
consume one state contract instead of re-deriving release-readiness state
separately.
After the release checks pass, the canary uses the explicit write boundary:
loopx promotion-readiness record \
--dashboard-readiness passed \
--execute
Without --execute, this command only previews the runtime-level append. The
canary supplies skipped only for an explicit dashboard omission; dependency
failures on a present dashboard source must not be recorded as passed.
Fresh shape:
{
"ok": true,
"registry": ".loopx/registry.json",
"runtime_root": "~/.codex/loopx",
"gate": "promotion_readiness",
"gate_state": "ready",
"can_promote": true,
"should_warn": false,
"non_blocking": true,
"recommended_action": "promotion readiness is fresh",
"readiness": {
"available": true,
"source": "runtime_release_ledger",
"evidence_scope": "runtime_release",
"goal_id": null,
"dashboard_readiness": "passed",
"classification": "canary_promotion_readiness_smoke_group",
"freshness_status": "fresh",
"requires_readiness_run": false,
"freshness_window_hours": 24,
"json_exists": true,
"markdown_exists": true
}
}
Missing or stale shape:
{
"ok": true,
"gate": "promotion_readiness",
"gate_state": "warning",
"can_promote": false,
"should_warn": true,
"non_blocking": true,
"recommended_action": "python3 examples/canary/canary-promotion-readiness-smoke.py",
"warning_message": "promotion-readiness evidence is stale; ...",
"readiness": {
"freshness_status": "stale",
"requires_readiness_run": true
}
}
warning_message is intentionally human-facing and may change. It exists so
scripts/install-local.sh can keep its operator warning, but automation should
prefer the structured fields above.
Global Registry Health
global_registry is the local multi-project health surface. It checks the
shared registry.global.json even when the current command is pointed at a
project-local registry, so dashboard users can see registry scope problems
before they turn into ghost projects.
Health findings are compact and local-only. They may include local filesystem paths in a developer machine export, so do not publish a raw local status JSON outside the machine.
Registry boundary should be checked with:
loopx registry-boundary --path <registry.json> --require-gitignored
The shared registry.global.json is classified as shared_local_registry and
must not be pushed. Project .loopx/registry.json files are
project_local_private_registry. Generated public-safe registry projections are
still runtime artifacts by default: they can be useful for review or handoff,
but github_push_allowed=false unless the file is an explicitly authored
example fixture under examples/. Dashboard/status JSON should therefore treat
registry data as a local control-plane view, not as a repository artifact.
Finding shape:
{
"kind": "stale_source_registry",
"severity": "action",
"goal_id": "project-main-control",
"message": "`project-main-control` source registry changed after its last global sync",
"recommended_action": "run `loopx sync-global --goal-id project-main-control` from the source project",
"path": "/path/to/project/.loopx/registry.json"
}
Current finding kinds:
duplicate_goal_id: the global registry contains more than one entry for the same goal id; this is high severity because routing is ambiguous.source_registry_missing: a global entry points at a source registry that no longer exists.stale_source_registry: the source registry changed after the last recordedsynced_at, so the global entry may be stale.state_file_missing: the goal's declared active state file no longer exists.state_file_not_declared: the global entry has no durable active state file.current_registry_scope_excludes_global_goals: informational reminder that a project-local registry view excludes goals that are present in the shared global registry.
High and action findings are also lifted into attention_queue.items with
source=global_registry; informational scope findings stay in the global
registry panel so local project views are not noisy. Source-registry provenance
findings (source_registry_missing / stale_source_registry) are collapsed into
the live quota-backed queue item for the same goal_id when one exists, under
global_registry_shadow_findings, so stale source shadows do not become a second
quota health blocker while the fact remains visible in global_registry.findings.
Contract Health
contract.ok=false means the UI should show a blocking health state before
encouraging more adapter work.
The summary counters are intentionally small:
errors: boundary or registry problems that should block progress.warnings: non-blocking issues worth showing in a secondary health panel.checks: successful observations, useful for audit trails.
error_diagnostics is the source of truth for error ownership. Each row has a
stable code, a human-readable message, and either scope=global or
scope=goal with a goal_id; a finding shared by a known subset may use
scope=goals with goal_ids. Registry parse failures, ambiguous goal identity,
registry boundary violations, and public-boundary violations are global.
Goal-entry, active-state, and todo contract failures are owned by the goal or
known goal set that produced them.
errors, global_errors, and goal_errors are compatibility projections
derived from those structured diagnostics; consumers must not infer ownership
from message prefixes. warnings and checks remain short strings. Checks
should be concrete enough to support an operator decision without exposing
local paths or private evidence. They must be public-safe before a project
exposes this export outside the local machine.
Attention Queue
The attention queue is sorted by LoopX status logic. A UI should render it as the primary worklist.
Counters:
item_count: all visible queue items.needs_user_or_controller: items waiting on either a human user or a target controller.needs_controller: subset waiting on a target controller or adapter connection.needs_codex: items ready for a Codex action.watching_external_evidence: items that should be monitored but not acted on until outside evidence changes.watching_monitor: monitor-only items that remain visible without implying immediate Codex work.
Item shape:
{
"goal_id": "complex-project-main-control",
"status": "ready_for_controller_opt_in",
"lifecycle_phase": "controller_gated",
"lifecycle_flags": [
"controller_gated",
"adapter_inspected"
],
"waiting_on": "user_or_controller",
"severity": "action",
"recommended_action": "先在 LoopX 完成 operator 判断;同意后项目 Agent 只执行 read-only map dry-run",
"project_asset": {
"owner": "user_or_controller",
"gate": "operator_question",
"next_action": "先在 LoopX 完成 operator 判断;同意后项目 Agent 只执行 read-only map dry-run",
"stop_condition": "record aligned eval evidence and one human reward event",
"user_todos": {
"open": 1,
"done": 2,
"total": 3,
"next": "Record the owner/SOP conclusion in the review worksheet."
},
"agent_todos": {
"open": 1,
"done": 0,
"total": 1,
"next": "Run the read-only validation map after approval."
},
"quota": {
"compute": 0.5,
"state": "operator_gate",
"spent_slots": 0,
"allowed_slots": 720,
"reason": "operator gate blocks gated delivery"
},
"latest_validation": {
"generated_at": "2026-06-02T12:00:00+00:00",
"classification": "ready_for_controller_opt_in",
"summary": "read-only map available; write-control not approved"
}
},
"handoff_readiness": {
"ready": false,
"codex_ready": false,
"source": "project_asset",
"quota_state": "operator_gate",
"handoff_status": "not_ready",
"post_handoff_run_seen": false,
"checks": {
"project_asset_backed": true,
"same_source_should_run": true,
"codex_ready": false,
"handoff_has_next_action": true,
"handoff_has_stop_condition": true,
"handoff_sanitized_surface": true
},
"next_probe": "loopx review-packet --goal-id complex-project-main-control --handoff-only"
},
"operator_question": "是否同意 `complex-project-main-control` 先执行 read-only map opt-in?",
"agent_command": "loopx read-only-map --goal-id complex-project-main-control --dry-run",
"quota": {
"compute": 0.5,
"window_hours": 24,
"slot_minutes": 1,
"allowed_slots": 720,
"spent_slots": 0,
"state": "operator_gate",
"reason": "planned goal needs operator opt-in before spending agent turns"
},
"source": "latest_run",
"controller_stage": "ready_for_read_only_not_decision",
"missing_gates": [
"human_reward_capture",
"aligned_eval_decision_evidence"
],
"next_handoff_condition": "record aligned eval evidence and one human reward event"
}
Item fields:
goal_id: stable goal identifier from registry or runtime.status: adapter classification or derived status.lifecycle_phase: derived state-interaction phase for first-screen visualization.lifecycle_flags: all compact phases that apply to the latest state.waiting_on:user_or_controller,controller,codex,external_evidence, ormonitor_signal.severity:high,action, orwatch.recommended_action: exactly one next action.project_asset: a compact control-plane projection derived from the same item. It must carryowner,gate,support_mode,next_action, andstop_condition, and may include compactuser_todos,agent_todos,quota, andlatest_validationsummaries. Registry-backed project assets also includeexecution_profile, the project-level delivery floor created byloopx connect, andorchestration, the compact projection of registryspawn_policywithmode,spawn_allowed,max_children, and optionalallowed_domains. They may also includecontrol_plane, the compact per-goal policy projection for settings such as self-repair, andstale_latest_run_warning, a compact warning that the current active-state file appears newer or different from the latest run's captured state projection. This warning is a repair hint, not a scheduler gate: consumers should runrefresh-statebefore trusting latest-run-derived routing, while quota eligibility still comes from the quota guard. When orchestration mode ismulti_subagent, project assets may also includesubagent_activity, a compact child-run projection derived from run history. It records child run ids, roles, state, parent links, public-safe scope summaries, and quota-spend counts for observation only; it is not a lock service or write arbiter. This is the first-screen project asset surface for agents and dashboards; it lets consumers avoid reconstructing owner, gate, support mode, next action, stop condition, todo counts, compute state, and latest validation from scattered fields. It also keeps delivery-floor and orchestration policy close to the project asset instead of forcing agents to infer them from history.support_modeis a compact product-mode label:read_only_observer,decision_support,reward_capture, orselective_assist. It describes the current operator/agent relationship; it is not a permission bit and does not overridegate,quota, oragent_command. When an approvedagent_commandis present and public-safe,project_asset.next_safe_commandmay repeat that command so first-screen dashboards and handoff packets can show the next executable local step without scanning top-level queue fields. Advisory dreaming outputs may include bothdreaming_proposalanddreaming_lane_badge. The proposal carries compact rationale and promotion requirements; the badge carries only routing facts for UI/heartbeat consumers:lane=dreaming,advisory=true,interrupts_delivery=false,review_required=true,execution_allowed=false,delivery_spend_allowed=false, andpromoted_to_delivery=false. Consumers should render the badge as a separate Dreaming lane or secondary badge and must not treat it as delivery authorization. Markdown renderers should include the first unfinished user and agent todo here when available, so hot-path readers do not need to scan the detailed todo sections. The richer top-leveluser_todos,agent_todos, andquotafields remain available for detailed views.- Current routing authority: consumers should choose the current owner, gate,
waiting party, and next action from
attention_queue.itemsand itsproject_asset.run_history.latest_runsis an evidence and drill-down surface; it may be limited by status command limits or filters, so consumers must not use it as the sole source for deciding whether a gate is still pending or already approved. handoff_readiness: optional project-asset consistency and follow-through summary.ready=truemeans the current queue item is Codex-runnable under the same source, quota, next-action, stop-condition, and public-safety checks.handoff_status=ready_waiting_for_runmeans a handoff is ready or approved but no later non-accounting run has appeared in the compact history window.handoff_status=post_handoff_run_seenmeans a later non-neutral run exists;post_handoff_latest_runidentifies that latest seen run by timestamp and classification, anddelivery_batch_scalelabels whether the observed delivery is test-only, single-surface, multi-surface, implementation-shaped, or still unknown. Status prefers an explicit compact run field such asdelivery_batch_scale=multi_surfaceover classification-name inference, so a verified browser-smoke-plus-docs artifact is not misclassified astest_onlymerely because the classification containssmoke.post_handoff_recent_runsis a compact newest-first slice of recent post-handoff work runs, andpost_handoff_small_scale_streakcounts the leadingtest_only/single_surface/unknownscale streak so heartbeat jobs and review packets can request a larger validated delivery batch only after repeated small-scale follow-through. Whenproject_asset.execution_profile.outcome_floordeclares outcome markers or surface-only hints, compact runs may also includedelivery_outcome(outcome_progress,surface_only, oroutcome_gap), and status also honors an explicit refresh-statedelivery_outcomebefore falling back to marker/hint inference.primary_goal_outcomeis accepted as a compatible progress label for refresh-state records that want to mirror the default execution profile wording.post_handoff_outcome_gap_streakcounts consecutive work runs that did not advance the declared outcome floor.quota_slot_spentevents do not count as post-handoff work.operator_question: optional human-facing gate to show in the LoopX operator view. This is the canonical place for user/controller judgment.agent_command: optional command or instruction for the target project agent after the operator gate is approved. Dashboard consumers should not treat it as approval by itself.quota: optional compact compute-quota state. It should summarize the compute share (1.0,0.5,0.3, or0), eligibility, recent spend, and a public-safe reason without exposing private evidence. See quota-allocation.md.control_plane: optional compact registry policy for this goal. Current settings includeself_repair.enabled,self_repair.allow_health_blocker_repair, andself_repair.allow_waiting_projection_repair. Missing settings mean default off, so ordinary goals remain in their existing skip/wait lanes.user_todos: optional checkbox summary parsed from the active state's## User Todo .../## Owner Review Reading Queuesection. Dashboard consumers should render the first unfinished item as the human-facing next step, while keepingrecommended_actionas routing context. The compactproject_asset.user_todosprojection keeps legacynext/next_indexfields and may also include up to three unfinisheditemsfor thin workers that need more than the first open todo.agent_todos: optional checkbox summary parsed from## Agent Todo,## Codex Todo, or## Project Agent Todo. Agent-facing consumers may use it to choose implementation work after gates and quota allow execution; it is not a user approval signal. Status, quota, and review-packet projections should preserve up to three unfinished agent todo items so short heartbeats do not confuse "first visible item" with the whole backlog. Todo summaries also exposefirst_executable_itemsfor advancement-class work andmonitor_open_itemsfor continuous-monitor work; executable items are the primary action surface, while monitor items are supplemental context that should not consume the selected goal's advancement slot unless they record a material transition or blocker.issue_meta_surface: optional public-safe issue/PR anchor projection parsed from an active-state## Issue Meta Surfacesection and mirrored underproject_asset.issue_meta_surface. Schemaissue_meta_surface_v0carries a bounded list of compactissue_meta_surface_item_v0rows withrepo_handle,issue_handle, GitHub-stylelabels,owner_route,related_code_hint,validation_surface,promotion_target,status, andfreshness. It is a scenario state surface for issue/PR solver anchors, not a command to read private source, publish comments, or open PRs.capability_gate: optional per-goal quota projection derived from visible executable agent todos that declarerequired_capabilities. Whenaction=run, the gate projectsrunnable_candidatesandblocked_candidates;decision_owner=agentmeans the agent chooses the actual todo from the runnable set during its steering audit. The gate must not rewriterecommended_actioninto a single selected todo.required_capabilitiesmeans a prerequisite for directly executing that todo, not the capability the todo is trying to build. A todo may separately declaretarget_capabilitiesfor capabilities it is developing, repairing, materializing, or parity-checking. Target capabilities are not hard gates. If a target bridge such asbenchmark_runneris absent, the candidate may still appear inrunnable_candidateswithcapability_repair_mode=true,capability_action=repair_bridge, andmissing_target_capabilitieson the candidate. When no visible executable candidate is runnable, the gate owns the decision and returnsrepair_bridge,ask_owner, orskipwith concrete missing capability details.project_asset.todo_projection_gap: optional explicit gap object emitted when status cannot projectuser_todosand/oragent_todosfor a connected project. This means "the first-screen todo state is unknown", not "there are zero todos". Consumers should surface the missing roles and ask for a parseable active-state todo section or state-file repair before treating the project asset as first-screen complete.- Todo summaries use
schema_version=todo_summary_v0; parsed todo items useschema_version=todo_item_v0. The source active state can remain ordinary Markdown checkboxes, but status/quota/dashboard consumers should prefer the structured item fields when present:todo_id,role,status,priority,title,archive_state,source_section,index,text,task_class,action_kind,note,evidence,reason,completed_at,updated_at,superseded_by, andclaimed_by. Todo summaries may also exposeclaimed_open_countandunclaimed_open_countso dashboards and heartbeat dispatchers can show soft ownership without inferring a lock.claimed_byis a visibility hint written through the todo CLI, not a lease or permission grant; claim ids must be registered on the goal's coordination contract, and agents must still obey quota, gates, write-scope checks, and their automation/handoff scope.todo_idis first-class when written by the todo CLI; legacy Markdown without metadata still gets a parser-derived compatibility id from the current item text and section, and the first lifecycle command materializes that id back into metadata. The first open item is still available throughfirst_open_itemsfor older heartbeats. Frontstage consumers should not treat that top-N scheduler view as the whole backlog. Todo summaries may also project visibility lanes:unclaimed_priority_open_itemsfor priority-ranked unclaimed candidates,claimed_open_itemsfor claimed work that may be outside the top-N,claimed_advancement_open_itemsfor claimed executable delivery work, andclaimed_monitor_open_itemsfor claimed continuous-monitor work. Agent-aware quota/status projections may further includecurrent_agent_claimed_open_items,current_agent_claimed_advancement_items,current_agent_claimed_monitor_items, andclaimed_by_others_items. The scheduler can still select from a narrower executable candidate set; the dashboard/frontstage uses these lanes to keep ownership visible. Visibility lanes may be wider than scheduler lanes, but remain bounded; the default agent-facing cap is 16 items per lane. Consumers should use the corresponding counts to indicate when more claimed work exists than is expanded in the current payload, and richer frontstage views should use a future paged/filtered projection instead of forcing larger heartbeat payloads. The canonical todo drill-down contract isdocs/reference/protocols/todo-detail-cold-path-v0.md: hot-path summaries may carry only a compacttodo_detail_ref_v0pointer for one selected item, while full notes, evidence summaries, related lifecycle references, and page tokens stay intodo_detail_cold_path_v0cold-path responses. Status, quota, heartbeat, and handoff payloads must not inline full todo detail in order to make hidden backlog visible. When claimed lanes exceed the cap, producers should avoid raw top-N truncation. Sort by priority and source position, group byclaimed_by, take a fair per-claimant slice, then fill remaining slots from the sorted remainder. Agent-scoped projections should then order focus as current-agent claimed items, unclaimed items, and lower-weight other-agent claimed items. Other-agent claims are visibility context and last-resort candidates; they are not a hard lock, but they also should not outrank the current agent's own claimed work or unclaimed work. Deferred todos are projected after sorted open todo lanes throughdeferred_itemsand, when a machine-readable resume condition is satisfied,deferred_resume_candidates. This is a gate-resume lane, not no-candidate evidence and not executable backlog. The default deferred visibility cap is eight items. Parsed deferred items may includeresume_when,resume_condition, andresume_ready; consumers should not merge these intofirst_open_itemsor executable backlog until a lifecycle command reopens or supersedes the todo. Agent-scoped quota may further split ready candidates intocurrent_agent_deferred_resume_candidates,unclaimed_deferred_resume_candidates, andother_agent_deferred_resume_candidates, where only the first two can wake the current peer before an agent-scoped no-candidate wait is allowed. Open todos may also carryresume_when; status should attachresume_condition/resume_readybut keep the item out of executable backlog untilresume_ready=true. This lets agents see not-yet-unlocked successors without accidentally selecting them as current work. Optional future fields such ascreated_at, lease TTLs, dependencies, or evidence links should extend this item shape rather than inventing another todo surface. - Agent-scoped quota payloads may include
agent_todo_summary.claim_scopewithschema_version=agent_claim_scope_v0. The quota guard should select current-agent claimed todos before unclaimed todos, then expose other-agent claimed todos as lower-weight candidates. Compatibility payloads may still includeblocked_claimed_items, but new consumers should preferother_agent_claimed_itemsandother_agent_claimed_open_count. This is claim-aware routing, not a hard lease: every peer can inspect the goal-wide backlog, while claims, task policy, capabilities, and boundaries determine what it may execute. A current-agent claimed todo may be selected even when the active state's globalNext Actionnames another peer's lane; that is not a state projection mismatch. - Agent-scoped quota payloads also expose the versioned
task_scopeenumgoal_all_read_claimed_run_global_read_v0. It means the peer may read all ordinary todos in the current goal, may consider its own claimed or an eligible unclaimed candidate, must claim before execution, and may execute only its claimed eligible todo. Other-agent claims are diagnostic only. Cross-goal reads stay outside goal-local routing and require an explicit read-only global-manager inventory such asloopx global-summary; they never grant cross-goal execution. Existing goal, agent, and cold-path command fields supply the binding parameters without duplicating them. TurnEnvelope retains this compact enum so the model sees the same boundary as the full quota decision. dependency_blockers: optional compact summary of unfinished user todos from other current attention-queue goals. This lets dashboards and heartbeat dispatchers show sibling/project dependency gates separately from the current goal's ownuser_todos; it is visibility context only and must not by itself change the current goal's quota or owner decision.- Local active-state file paths are intentionally omitted from queue items.
They are useful debug/source metadata, but the public-safe status queue should
identify work by
goal_id, project asset state, and compact todos instead of exposing machine-specific paths. source:contract,registry,run_history, orlatest_run.controller_stage: optional compact controller-readiness classification from the latest run.missing_gates: optional public-safe gate ids that explain why a goal cannot advance to the next controller stage yet.next_handoff_condition: optional public-safe condition for advancing the controller handoff.
status=unregistered_runtime_goal is emitted when runtime has an actionable
goal that is not present in the registry. Dashboard consumers should show this
as controller work: register the goal if it is active, or archive the runtime
record if it is old. Watch-only legacy records remain visible in run history
without entering the queue.
status=state_refreshed is emitted for registered goals when the latest compact
run came from loopx refresh-state. Dashboard consumers should show it
as Codex-ready work: the controller state changed, and the next agent turn
should inspect the refreshed active state before continuing.
If the refresh command was run without --recommended-action, the compact
recommended_action should be the first local control-plane item from the
refreshed active state's ## Next Action, including wrapped continuation
lines; only when that durable section is absent should it fall back to the first
open Agent Todo, and finally to a generic refresh notice. This field may carry
stable local routing references such as todo ids, branch names, agent ids, PR
refs, or private-material pointers because it serves the individual operator's
local loop. It must not carry credentials, auth headers, or inline secrets.
Public/export sinks are responsible for redacting or omitting local/private
references before rendering shareable surfaces. The record includes
recommended_action_source (explicit_arg, active_state_next_action,
agent_todo_fallback, or default_refresh_action) so consumers can distinguish
run guidance from durable-state projection and last-resort compatibility
fallback.
--recommended-action describes the appended run record; it does not rewrite
the active state's durable ## Next Action. To intentionally change that
durable route in a multi-agent goal, a registered peer must run
refresh-state --agent-id <registered-peer> --progress-scope goal --next-action <local control-plane action>. Status projections may expose both
active_state_next_action and
latest_run_recommended_action; when they differ, next_action_projection_warning
marks the drift instead of silently choosing one as the only truth.
Executable dispatch should use agent_lane_next_action / todo projection rather
than treating shared ## Next Action as a per-agent work item.
In a multi-agent goal, refresh-state requires an explicit --agent-id; text
or todo-title inference is not a valid identity source. When a refresh is
scoped with --agent-id and no --progress-scope, the run records
progress_scope=agent_lane. This is a lane note, not a project-level status
transition: status/quota keep selecting the latest non-agent-lane run for the
goal-level status and recommended_action, while exposing the lane note as
agent_lane_recommendation on the attention item and project asset. A
goal-level refresh in a multi-agent goal must use a registered peer with
--progress-scope goal.
Use agent-lane scope for a peer-local recommendation that should not replace the
durable goal route.
If a peer self-merged slice materially advanced the public product or case
path, that peer or another registered peer should also write a project-level
refresh with the matching delivery_outcome=outcome_progress (or skip the
extra project-level sync entirely). A later surface_only project-level sync
will become the latest non-agent-lane run, so quota may correctly ask for
follow-through even though the peer-lane note recorded real progress.
For registered connected, connected-read-only, and pre-tick-runnable
adapters, custom compact progress classifications that are not blocker, gate,
or watch classifications also remain Codex-ready. This lets a controller record
a validated progress run before quota accounting without forcing an extra
state-only refresh solely to make quota spend-slot eligible.
Autonomous Backlog Candidates
attention_queue.autonomous_backlog_candidates is an optional compact list of
unfinished advancement_task agent todos from current queue items where
waiting_on=codex and the goal quota is eligible. Monitor-class todos are
intentionally excluded from this backlog so dependency/readiness observation
cannot crowd out implementation, planning, or blocker-writeback candidates.
attention_queue.autonomous_monitor_candidates may separately expose compact
continuous_monitor todos from waiting_on=codex or
waiting_on=monitor_signal queue items so heartbeat dispatchers still see the
current watch surfaces without treating them as primary advancement work.
Both candidate surfaces preserve action_kind when the agent registered one
with the todo CLI.
Both lists are candidate surfaces only: consumers must still obey the selected
goal's quota, goal_boundary, owner/gate, public/private boundary, and
validation/writeback rules before spending a turn.
quota should-run includes goal_boundary.orchestration when the selected goal
has registry spawn_policy or project-asset orchestration state. Consumers use
that boundary to decide whether the next bounded turn should stay in default
single-worker mode or may launch child workers under the declared limits.
Registry entries may override first-screen attention with optional public-safe
fields: waiting_on, attention_status, recommended_action,
operator_question, and next_handoff_condition. Status respects this before
classifying the latest run, so a goal with a fresh state_refreshed record can
still remain in waiting_on=user_or_controller when the active state says a
human or target controller decision is the real next gate. This is intended for
state-truth corrections, not for granting project-agent execution. Global
registry sync preserves an existing attention override when a different later
source for the same goal omits these fields, so a controller-authored gate is
not accidentally lost during ordinary project sync. When the same source
registry syncs again and omits these fields, that source is treated as
authoritative and the stale override is cleared. A syncing registry entry can
also set clear_attention_override=true to clear an override explicitly.
Todo extraction is independent of attention overrides. A goal can stay in the
operator lane because the registry says waiting_on=user_or_controller, while
the active state exposes a more concrete user checklist. This is the preferred
shape for complex project review: keep recommended_action short enough to
route the queue, and put ordered user work in checkbox sections the dashboard
can summarize. This routing text belongs to the user's local control plane: it
may include private project refs, but it must not include AK/SK values, tokens,
auth headers, passwords, or inline credentials.
For registered planned high-complexity goals with a compatible
*_read_only_map_v0 adapter and no run yet, status keeps the queue item in
waiting_on=user_or_controller, emits an operator_question for the Goal
Harness operator view, and puts the dry-run preview in agent_command. The
preview should report opt_in_required=true and append nothing; dashboard
consumers must not treat the command as controller opt-in or a durable map run.
The human-readable Markdown status view may also render an
operator_gate_dry_run helper before agent_command; that helper is a
user-owned gate recording preview, not a JSON contract field or project-agent
command.
Executor-facing guards are stricter than status display: quota should-run
must keep these planned items at should_run=false, state=operator_gate, and
must not include agent_command until an approved operator-gate run makes the
goal eligible. This keeps a preview command from becoming an automatic project
agent handoff. When the quota payload includes agent_todo_summary, the target
project agent can use it as the safe follow-up checklist for its own next action
instead of re-reading chat history. When the quota payload includes
safe_bypass_allowed=true, that permission only covers independent read-only
steering or analysis from the active state's priority stack; it still must not
execute the gated preview command, adapter work, write-control, or production
actions. When the payload also includes gate_prompt, operator_question,
user_todo_summary, or agent_todo_summary, the executor should ask that
concrete gate in the visible thread with NOTIFY unless the same unresolved
gate was already asked recently; the guard should not collapse a user decision
into a silent skip.
When a goal has coordination.registered_agents, identity-aware heartbeat
prompts should call quota should-run --agent-id <registered-agent>. If an
old installed prompt omits that flag, the quota payload should include
decision=automation_prompt_upgrade,
effective_action=automation_prompt_upgrade_required,
automation_prompt_upgrade.required=true, blocks_should_run=true, and
example heartbeat-prompt --agent-id ... --agent-scope ... commands. Executors
should treat this as a prompt-upgrade action, not as delivery permission, a
quiet no-op, or a new operator gate. should_run, normal_delivery_allowed,
and interaction_contract.agent_channel.delivery_allowed must stay false
until the automation reruns quota should-run with a registered --agent-id.
When v0.1 hierarchy fields are still present, the same object also carries a
stable migration_id, host_update_idempotency_key, and completion_command.
The host may retry regeneration and automation update with that same id; the
registry cutover happens only after the host update succeeds and the completion
command acknowledges that exact id. Completion removes the hierarchy fields,
records coordination.completed_migrations.peer_agent_runtime_v1, and is an
idempotent no-op when repeated with the completed id. Once that marker exists,
quota should-run must never project this registry migration again. This is a
stable, retryable migration until acknowledgment, not a recurring notification
and not permission to update an automation more than once under different keys.
The selected identity is part of the turn envelope. Follow-up lifecycle
commands that interpret or account for the same turn, including scoped
refresh-state and quota spend-slot, should preserve the same --agent-id
when the subcommand supports it. A spend preview that drops the identity may
correctly show automation_prompt_upgrade_required for an unscoped automation,
but that is an accounting/projection mismatch for the scoped turn, not evidence
that the earlier peer guard was invalid.
An accountable refresh-state normally records the current checkout as
delivery_workspace. When implementation and validation happened in an
independent worktree but registry/state projection must run from another
checkout, pass --delivery-workspace-path <delivery-worktree>. LoopX validates
the referenced checkout against the peer-isolation policy and persists only its
credential-free repository identity and workspace class, never the local path.
An explicit canonical checkout is rejected for peer delivery, so this causal
override cannot turn non-isolated work into an accountable delivery.
For registered agent-scoped turns, quota should-run --agent-id may include
agent_lane_next_action.schema_version=agent_lane_next_action_v0. This is a
read-only derived pointer to the current agent's selected advancement slice,
chosen from runnable capability candidates first and then the agent-scoped
executable todo summary. It may point to a current-agent claimed todo even when
the active state's global Next Action is still owned by another route; the
field must therefore carry preserves_goal_next_action=true and must not be
treated as a project-level status overwrite. status --agent-id may reuse the
same quota-derived object as item/project-asset observation data; consumers must
render it as an agent-lane pointer, not as recommended_action replacement.
Human markdown should label this pointer as the current agent's todo and mark
co-displayed global agent todo rows as goal-wide, so --agent-id is not
mistaken for a filter that replaces the goal-wide queue.
The same scoped guard may include
goal_route_hint.schema_version=goal_route_hint_v0. This is a goal-level
read-path synthesis over the current agent_lane_next_action,
agent_scope_frontier, and compact per-agent todo lanes. It carries
preserves_goal_next_action=true and goal_next_action_mutation=none so hosts
can explain the lane decision without mutating shared ## Next Action or
collapsing other agents' queues into the current agent's route.
Within a candidate source, selection is ordered by current-agent claim first,
then capability_repair_mode=true, then priority/index. A repair-mode item
therefore stays visible as the suggested agent-lane slice even when an older
ordinary runnable P0 todo appears earlier in the active state; otherwise a todo
that exists to build the missing capability can be starved by work that depends
on that capability becoming reliable.
For any registered peer, quota should-run also enforces the workspace
boundary when the selected task writes repository state. If the guard is being
run from a non-git directory, from an unrelated git worktree, or from a checkout
that does not satisfy the task/repository isolation policy, the payload should include
workspace_guard.schema_version=agent_workspace_guard_v1,
workspace_guard.action=move_to_independent_worktree,
workspace_repair_allowed=true, normal_delivery_allowed=false, and
effective_action=agent_workspace_repair. The interaction contract should
use mode=agent_workspace_repair, require the peer to create or switch to
an independent worktree/branch, and require rerunning quota should-run with
the same --agent-id before repository edits. This preflight does not spend
quota; quota spend-slot should fail closed until the guard is rerun from the
independent worktree.
Workspace and boundary guards must bind to the final work-lane selected_todo
after due-monitor, capability-fallback, and scoped-gate routing. They must not
inherit repository or write-scope semantics from an unrelated first executable
backlog item; in particular, a selected read-only continuous monitor stays
monitor work even when a separate repository repair is also runnable.
If the selected todo declares task_repository, the guard should also project
that credential-free identity with
workspace_guard.repository_source=selected_todo.task_repository; otherwise
repository_source=goal.repo. A matching repository identity is necessary but
not sufficient: the current checkout must still be a linked worktree rather
than that repository's canonical checkout. task_repository is not a write
scope or permission grant.
Dashboard and Review Packet consumers should project workspace_guard as an
agent-channel workspace repair, not as an operator or user gate. The first
screen can render the current workspace class, required workspace class, repair
action, and whether normal delivery is allowed. It should not ask the user to
approve the move, mark the selected todo as blocked by the user, or hide open
same-scope work. If a peer is also looking at a todo claimed by another peer,
the packet should explain both boundaries separately: the workspace guard
requires moving to an independent worktree, while the claim boundary requires
choosing an in-scope current-agent or unclaimed todo, transferring the claim, or
creating an explicit successor.
When the payload includes notify_user_on_open_todo=true, the open
user_todo_summary is the current blocker-push surface even if there is no
operator gate. This is intended for focus_wait, waiting,
and external_evidence lanes where a short user/owner answer can unlock
progress or stop repeated meaningless polling. Executors should list at most
three open todos, include
open_todo_notify_reason, skip implementation work, and skip quota spend for
that blocker-push turn. When the payload also includes
open_todo_notification_policy=repeat_until_resolved, the
executor should repeat the notification until the todo is done, deferred, or
replaced. A user_gate_notification_cooldown_v0 packet with
notification_suppressed=true is the narrow exception: the gate and open-count
remain visible, while interaction_contract.user_channel becomes
action_required=false, notify=DONT_NOTIFY until the bounded reminder window
or a material gate/host change. Other blocker-push
cases may still be de-duplicated when the same blocker was surfaced recently.
Eligible monitor-only no-transition polls keep open user todos in
user_todo_summary, but do not force repeated notification or set
requires_user_action=true; they should surface as a quiet
monitor_quiet_skip rather than an executable run.
When the payload includes external_evidence_observation, the goal is waiting
on an external monitor that still requires a read-only observation contract.
This is not prompt-specific advice: quota should-run should also set
effective_action=external_evidence_observe and
execution_obligation.kind=external_evidence_observation_required. Executors
must check for a concrete observable handle or compact writeback surface, such
as a thread id, automation id, job id, lock/result marker, or result path. If no
handle exists, the correct action is a compact blocker or launch-readiness
writeback, not a quiet no-op and not benchmark execution.
When the payload includes heartbeat_recommendation, executors should follow
that generic lifecycle hint before inventing local automation behavior:
run_first_read_only_map runs and saves one real read-only map before spending
once, while mapped_noop_if_unchanged returns a quiet no-op without another
dry-run or quota spend if no new instruction, evidence, todo, stale source, or
safe handoff exists.
When the payload includes stale_latest_run_warning, the current active-state
projection has moved ahead of the latest run-history snapshot. Executors should
repair the control-plane projection with a fresh state refresh before relying on
latest-run status, review packets, or handoff fields, but the warning alone does
not authorize production actions or override should_run.
When the payload includes backlog_hygiene_warning, the active state has
multiple public-safe durable follow-up items in Next Action or
Operating Lessons while the active Agent Todo checklist has no open item.
Executors should mirror the durable follow-up work into concrete Agent Todo
checkboxes before heartbeat scheduling relies on those narrative sections. The
warning is a checklist hygiene signal only: it does not change quota eligibility,
grant write or production permission, or make a quiet no-op valid when
execution_obligation.must_attempt_work=true.
When the payload includes completed_todo_archive_warning, the active
Agent Todo checklist has accumulated too many completed entries for the
dashboard/status surface to keep current open work visible. Executors should
move older completed entries into a dedicated Completed Work Archive section
and keep only current open work plus a small recent-done tail under active
Agent Todo. The warning's archive_command_template includes the projected
default_archive_keep_count as --max-active-done, so the copyable command and
the warning's recent-done tail contract stay aligned. Archive sections are
intentionally ignored by active todo parsing.
This warning is a checklist hygiene signal only: it does not change quota
eligibility, grant write or production permission, or supersede open user/agent
todo blockers. It also does not mark an open todo complete; executors should
use loopx todo complete, todo update, or todo supersede for
structured lifecycle transitions by todo_id.
When the payload includes autonomous_replan_obligation, the active state's
current Next Action or Operating Lessons, or the recent public run history,
carries public-safe evidence that the controller may be stuck in a
periodic-review threshold, no-progress streak, repeated-action loop, phase
transition, backlog mismatch, evidence contradiction, or two repeated public
monitor/no-progress run records. Historical progress entries and completed
todos are intentionally not active-state trigger sources. Executors should
treat the object as a machine-readable planning contract, not prompt advice:
inspect triggers, apply the compact todo_actions as split/add/retire
guidance, write the selected todo/vision/blocker delta, and stop at
stop_condition. Validation remains part of the normal delivery evidence or
PR review path, not a command projected to the runtime agent. The default stall
threshold is 2 consecutive stalled turns or
public run records. A quota_monitor_poll record is status-neutral for latest
dashboard state, but it is still public stalled-run evidence for this specific
replan detector. For eligible goals,
heartbeat_recommendation.recommended_mode may become
autonomous_replan_required, and execution_obligation.kind may become
autonomous_replan_required with must_attempt_work=true, even when open user
todos remain visible, as long as the selected slice stays outside private,
destructive, production, or owner-only authority and honors stop_condition.
An open typed user_action remains a non-blocking notice even when no agent
todo is currently runnable; it must not force waiting_on=controller. When two
bounded stalls leave that agent frontier empty, the obligation sets
agent_todo_writeback_required=true. The interaction contract then projects a
concrete claimed todo add action and requires a runnable_todo_set repair
delta. Explicit terminal no-follow-up may replace the new todo only when
closure evidence is authoritative. The user reminder stays visible throughout
this replan path.
This is intended to keep monitor-only work from consuming the primary
executable backlog, not to bypass real gates.
quota should-run and status --agent-id may also expose
goal_frontier_projection.schema_version=goal_frontier_projection_v0. This
projection is owned by loopx.control_plane.goals.goal_frontier: it is a
compact per-goal progress/frontier view, not another quota sub-state. When it contains
autonomous_replan_decision, that decision is made before lane-local
monitor_quiet_skip, agent_scope_wait, or agent_scope_exhausted projection,
so those local no-candidate states cannot mask a required bounded replan.
The payload includes interaction_contract.schema_version = loopx_interaction_contract_v0, which is the primary user/agent/CLI
protocol for a selected goal. It groups the current turn into a stable
mode such as bounded_delivery, user_gate, user_todo_blocker_push,
external_evidence_observation, monitor_quiet_skip, autonomous_replan,
outcome_floor_recovery, mapped_noop_if_unchanged, or quota_throttled.
Its user_channel says whether to interrupt the user and why;
agent_channel says whether Codex must attempt work, whether delivery is
allowed, whether quiet no-op is allowed, and the primary action; cli_channel
says which CLI transitions and spend policy apply. Executors should read
interaction_contract first, with
interaction_contract.agent_channel.primary_action as the only executable
action entrypoint for the current turn. Optional
agent_channel.resolution_trace.summary is diagnostic: it compactly records
the source signal matched by primary_action and whether drift was detected. Existing
state_action_projection_warning / next_action_projection_warning fields
carry any writeback review guidance. The trace is not an independent
next-action authority and does not imply automatic active-state writeback.
execution_obligation,
heartbeat_recommendation, work_lane_contract,
external_evidence_observation, goal_boundary, and
protocol_action_packet remain compatibility and drill-down fields under that
contract, not competing sources of truth.
The same payload includes scheduler_hint.schema_version=scheduler_hint_v0.
This is the scheduling contract for host runtimes, not a delivery permission:
Codex App can back off its automation cadence for long waits, while Codex CLI
TUI and Claude Code loops can run one final quota/replan check after repeated
unchanged polls, then exit/stop only if the guard is still unchanged. Cadence
changes, final checks, and loop self-stop never spend quota. Host schedulers
apply recommended_interval_minutes as the next target interval and multiply
subsequent unchanged intervals by unchanged_poll_backoff_multiplier until
max_interval_minutes; example_progression_minutes exposes the compact
human-readable sequence. The hint also includes a compact reset_policy:
hosts compare reset_token between polls and clear the unchanged/backoff
streak when that token changes, or when a user reply, new/reassigned todo,
resolved gate, or material transition makes the goal actionable again. The
token is derived from scheduler action plus identity/profile inputs, while the
hot path carries only action fields plus a short identity_signature; the
profile signature, reset-condition summary, and full stateful-backoff policy are
available from scheduler_hint.cold_path_detail when callers request
loopx quota should-run --include-detail scheduler. The reset moves Codex
App/local cadence back to the current profile's initial interval before
unchanged backoff resumes, and does not spend quota.
Codex App heartbeats should use automation_update only when
codex_app.stateful_backoff.apply_needed=true and
codex_app.recommended_rrule is present. If that update succeeds, the agent
must run codex_app.ack_hint.cli_args;
current payloads use quota scheduler-ack-current so LoopX re-reads the latest
hint, then persists reset_token, identity_signature, progression_index,
and last_applied_rrule under the runtime root. When the same identity repeats,
LoopX advances the progression after the applied interval has elapsed, until
the max interval. An immediate post-ACK readback remains on the acknowledged
RRULE so repeated reconciliation converges rather than oscillates. When the reset token
changes, the next projected RRULE returns to
reset_policy.codex_app_initial_rrule. If the current desired RRULE is already
applied, recommended_rrule is omitted and the host update should be skipped.
When that matching readback still needs a reset-token/identity binding,
ack_needed=true; run the bound ack directly. Otherwise no scheduler action
is needed.
For CLI payloads, ack_hint.cli_args begins with the registry and effective
runtime-root binding used by the originating should-run call. Consumers must
preserve that prefix so the ACK cannot split scheduler state between project
and shared registries.
scheduler-ack only records the applied host cadence; the next RRULE, if any,
is projected by a future quota should-run, not by the ack response.
The payload also includes execution_obligation, which is the compatibility
entry point for older workers deciding whether a quiet no-op is allowed.
heartbeat_recommendation.notify is only a user-facing notification policy. It
must not be interpreted as an execution gate. If
execution_obligation.kind=external_evidence_observation_required, ordinary
delivery is still blocked, but the worker must perform one read-only
observation or write a compact missing-handle blocker before it may stop. If
execution_obligation.must_attempt_work=true, the worker should choose one
bounded segment under work_lane_contract when present, otherwise under
effective_action / goal_boundary, validate it, write durable state/events,
and spend once after delivery even when notify=DONT_NOTIFY. A quiet no-op
requires execution_obligation.must_attempt_work=false and no blocker-push
notification such as notify_user_on_open_todo=true; when both are present,
notify the user and do not spend. Verified mapped_noop_if_unchanged remains a
quiet no-op case.
The guard also emits protocol_action_packet.schema_version = protocol_action_packet_v0, a compact rule-only packet for executor and future
LLM-router experiments. It distills the same quota guard into one primary actor,
user/agent action requirement, quiet-noop allowance, execution lane, and a short
llm=no_api marker inside a single summary string so the hot path stays
within interface budget. The detailed spend policy remains in
heartbeat_recommendation.spend_policy. This packet is not a new source of
authority and does not authorize model/API use; it is the deterministic baseline
that an optional Codex/LLM summarizer must beat on payload shrinkage and
user/agent action clarity before direct LLM API wiring is added. When an open
todo uses the common [P*] short title: details shape, the packet uses the
short title as the action label so long progress notes do not re-enter the hot
path.
If open user todos coexist with executable agent work, the packet keeps the
primary actor as agent but adds user_action_pending=true plus a compact
user_action label. This preserves the owner-visible blocker without
mislabeling that owner todo as agent_action.
When a registry-enabled goal has control_plane.self_repair.enabled=true,
quota should-run may return decision=self_repair,
self_repair_allowed=true, stall_self_repair, and an effective_action such
as control_plane_health_repair or control_plane_projection_repair. This is
the machine-readable stall-repair contract for short heartbeats: repair the
control-plane projection or write back the concrete blocker, validate, record a
durable event, then spend once. Goals without that registry policy must not get
this lane by default.
When the payload includes decision_freshness_warning, the goal may still be
eligible, but sampled reward/gate state for that same goal is stale or has newer
events after it. Executors should not reuse that old decision as authority until
they re-read the current registry, ACTIVE_GOAL_STATE, quota, policy, and run
status at the decision point. This warning is a guardrail for decision reuse,
not a repository rewind or a replacement for should_run.
If the payload's handoff_readiness.post_handoff_outcome_gap_streak has reached
the project_asset.execution_profile.outcome_floor.surface_streak_threshold,
quota should-run should also enforce the handoff contract by returning
should_run=true, state=focus_wait, blocked_action_scope=delivery_outcome_floor,
safe_bypass_allowed=true, safe_bypass_kind=outcome_floor_recovery,
recovery_delivery_allowed=true, effective_action=outcome_floor_recovery,
decision=safe_bypass_recovery, and
heartbeat_recommendation.recommended_mode=outcome_floor_recovery when the
floor declares a concrete must_advance target. In this shape should_run
means there is a Codex-actionable turn, while normal_delivery_allowed=false
explains that ordinary delivery is blocked. Executors should treat
effective_action=outcome_floor_recovery as recovery permission, spend only
after validated ranker/cross-domain evidence or concrete blocker writeback, and
avoid continuing a surface-only loop or waiting passively.
The status export should apply the same quota guard to attention_queue.items[]
and project_asset.quota, while preserving handoff_readiness run evidence:
codex_ready may become false, but post_handoff_latest_run,
post_handoff_recent_runs, and post_handoff_outcome_gap_streak should remain
visible for dashboards and handoff packets.
Review Packet source-of-truth rule:
- the dashboard/operator view owns the human decision;
- the copied Review Packet is a bridge from that decision surface to a local operator preview and a target project-agent instruction;
loopx review-packet --goal-id <goal-id>may generate the same packet from the status contract for CLI-facing agents, but it is still a read-only packaging command;- when status includes same-goal
decision_freshness_summaryitems that require rebase, the full Review Packet should render a compact human-visible freshness warning before the operator approves or relays work; this warning stays out of the minimized handoff-only text so the project agent still receives a small current instruction; loopx review-packet --goal-id <goal-id> --handoff-onlyis the copy-minimal form for an already selected or approved target-agent relay: it prints only theproject_agent_handofftext in markdown output, while JSON output returns a minimized handoff payload instead of the full operator packet. When a latest post-handoff run carriesbenchmark_experiment_report_replay_decision_v0, JSON handoff-only output may also includebenchmark_report_chain_handoffso agents can readchain_map,replay_decision,next_run_mode,readiness, andauthorizationwithout parsing the handoff sentence. To keep the hot path compact, handoff-only JSON does not expose a separatehandoff_followthrough_summaryprose field; that prose remains available in the full Review Packet and embedded handoff text;- project-agent handoff commands redact local absolute registry/runtime paths
before they enter
project_agent_command,project_agent_handoff, orhandoff_text; - project-agent handoff text is an interface-budgeted hot-path artifact: it should stay within 16 lines and 1800 characters, include at most one command block, and carry only the target goal guard, minimal-context rule, source label, optional compact post-handoff delivery scale, optional delivery contract, forwarding/execution boundary, command, and stop condition;
handoff_delivery_contractis optional structured guidance derived from the currenthandoff_readinessplusproject_asset.execution_profile, not a target-specific hack. When repeated small-scale follow-through reaches the profile'sdegradation_policy.small_scale_streak_threshold, packets may setmode=expand_after_repeated_small_deliveryand ask the target agent to run one coherent batch at the profile'sminimum_scalewith the declaredmust_includesurfaces, or report a blocker without spending quota. When implementation-shaped runs are still only forecast/runbook/queue/field propagation andpost_handoff_outcome_gap_streakreaches the profile'soutcome_floor.surface_streak_threshold, packets may instead setmode=expand_after_surface_progress_loopand require the next delivery to advance the declared outcome floor, or report a blocker without spend;- handoff-only output must not carry the full Review Packet, human decision
section, local operator-gate preview, operator decision payload fields, raw
run_history, orlatest_runscold-path evidence; - the local
operator_gate_dry_runpreview belongs to the user or controller, not the target project agent; - the project-agent command is the after-approval dry-run path for controller
gates, or the quota guard for connected-delivery Codex goals. Connected
delivery handoffs may authorize bounded write-scope delivery after
should_run=true; they must still stop for unapproved scopes, production actions, destructive git, private material, or surface-only loops.
For controller opt-in packets, the operator question must appear before any
local gate preview, and the local gate preview must appear before any
project-agent command. A dashboard, script, or agent must not infer approval,
reward, write-control, or a real map run from the presence of a copied packet,
review URL, selected goal_id, or agent_command.
The project-agent section of a Review Packet should be short and operational: name the current context source, the forwarding condition, the execution boundary, and the stop condition before showing any command. The context source rule keeps agent handoffs from bloating: the packet carries only the minimal current instruction; if the target agent needs more context, it reads the current active state, status, history, and command output instead of rebuilding truth from old chats or old packets. For controller opt-in, that means the section is only forwarded after an explicit human/controller agreement, the agent only runs the read-only or dry-run project path, and it must stop if it needs a real approval, write-control, run-history append, production action, or if the command fails. This keeps the packet easy for target agents to follow while preserving the dashboard as the human decision surface and the archival evidence trail as the cold path.
For focus-wait packets, the Review Packet should surface the first open
owner/user todo as the unlock condition, not as ordinary delivery work. The
human section should explain why the project is quiet, who can unblock it, and
which evidence is needed before delivery resumes. The project-agent section
must not present a safe-local delivery path; it should only point to status or
history inspection and tell the target agent to keep focus_wait until new
owner evidence, a clean baseline, or external eval changes the state.
Dashboard action packets and first-screen cards should follow the same rule:
label the item as Focus wait / owner blocker, show the first open owner/user
todo as the unlock condition, and make the copy affordance status/history-only
rather than an approved handoff or read-only map delivery path.
status=read_only_project_map is emitted when the latest compact run came from
loopx read-only-map. Dashboard consumers should show it as Codex-ready
work with a map-specific badge or drill-down: the project is connected and has
a read-only map run, but the next useful action still needs a controller or
agent to use that map. Compact run records may include a public-safe
project_map object:
{
"adapter_kind": "read_only_project_map_v0",
"adapter_status": "connected-read-only",
"authority_source_count": 1,
"authority_registry_declared": true,
"authority_registry_path_exists": true,
"authority_registry_default_entry_count": 2,
"authority_registry_default_entries_present": 2,
"topic_authority_count": 8,
"authority_registry_conflict_risk": "low",
"guard_count": 3,
"sections_found": 4,
"sections_checked": 7,
"project_registry_exists": true,
"goal_state_dir_exists": true,
"active_state_file_exists": true,
"files_present": 4,
"files_checked": 9,
"residual_risk_count": 1
}
The full run payload may also include residual_risks, a compact public-safe
list such as planned_adapter_requires_controller_opt_in or
project_local_goal_state_not_detected. If an optional authority registry is
declared, missing registry files, missing default entries, deprecated sources,
or medium/high conflict risk are reported with stable authority_registry_*
labels. Project agents should relay that list directly rather than inventing a
free-form risk summary.
For same-repo multi-goal projects, project_registry_exists,
goal_state_dir_exists, and active_state_file_exists are goal-scoped health
signals. A project can have both main-control and side-bypass in the same
repo, but each selected goal_id should have its own
.codex/goals/<goal-id>/ directory. If that directory is missing, the map
reports project_goal_state_dir_not_detected:<goal-id> and the legacy
project_local_goal_state_not_detected risk even when another goal in the same
repo is healthy.
The CLI cleanup path is loopx archive-runtime --goal-id <goal-id>. It
defaults to dry-run and requires --execute before moving the runtime directory
under <runtime-root>/archived-goals/.
Run History
run_history is a compact, public-safe drill-down surface for the dashboard.
It mirrors the compact run index, but strips local artifact paths. UIs should
show artifact availability with json_exists and markdown_exists instead of
linking directly to local files.
On the status, quota should-run, and history read paths, relative
common_runtime_root values, relative --runtime-root overrides, and relative
run-index artifact paths are resolved against the project root that owns the
selected registry, not the caller's current working directory. This keeps
those read surfaces stable when they are invoked from an independent worktree.
Goal shape:
{
"id": "complex-project-main-control",
"domain": "complex-project-control",
"status": "active-read-only",
"lifecycle_phase": "controller_gated",
"lifecycle_flags": [
"controller_gated",
"adapter_inspected"
],
"registry_member": true,
"legacy_runtime_goal": false,
"adapter_kind": "complex_project_read_only_map_v0",
"adapter_status": "connected-read-only",
"authority_registry": {
"declared": true,
"path": "docs/meta/DOC_REGISTRY.yaml",
"path_exists": true,
"default_entry_count": 3,
"default_entries_checked": 3,
"default_entries_present": 3,
"topic_authority_count": 8,
"project_material_count": 6,
"project_material_repository_count": 2,
"project_material_owner_review_required_count": 1,
"project_material_stale_count": 1,
"project_material_current_authority_count": 1,
"deprecated_source_count": 0,
"conflict_risk": "low"
},
"quota": {
"compute": 0.5,
"window_hours": 24,
"slot_minutes": 1,
"allowed_slots": 720,
"spent_slots": 0,
"state": "operator_gate",
"reason": "operator gate blocks gated delivery; safe non-gated steering may continue",
"blocked_action_scope": "gated_delivery",
"safe_bypass_allowed": true
},
"index_exists": true,
"raw_index_records": 2,
"unique_runs": 2,
"subagent_activity": {
"source": "run_history",
"parent_goal_id": "complex-project-main-control",
"child_count": 2,
"visible_child_count": 2,
"completed_count": 1,
"active_count": 1,
"quota_spend_slots": 2,
"items": [
{
"run_id": "docs-map-001",
"goal_id": "docs-map-subagent",
"parent_run_id": "controller-run-001",
"spawned_by_goal_id": "complex-project-main-control",
"agent_role": "explorer",
"state": "completed",
"work_scope": [
"docs/**"
],
"touched_paths": [],
"touched_path_count": 0,
"handoff_summary": "Mapped task clusters without editing files.",
"quota_spend_slots": 1
}
],
"proxy_note": "compact child-run projection only; parent controller remains the authority for locks, writes, and merge decisions"
},
"latest_runs": []
}
authority_registry on the goal comes from the registry and stays visible even
when the latest run is an operator gate or reward overlay rather than a fresh
project map. Dashboard consumers should translate it into one human-facing line
such as "default entries 3/3, topic 8, materials 6, owner review 1, risk low"
before asking for operator decisions. Material details stay project-local:
public status exposes compact counts for material roles, repository links,
owner-review gaps, stale sources, and current authorities instead of URLs,
repository roots, product configs, or raw review notes.
The Markdown status renderer should expose the same compact context as an
authority_material line on attention-queue items, so agent-facing handoffs
see freshness and owner-review pressure without needing internal material
links or source text.
quota on the goal comes from the registry and defaults to compute=1.0 when
not declared. In v0.1, status derives only a compact product state from hard
gates and attention ownership: eligible, focus_wait, throttled,
waiting, operator_gate, paused, or blocked_health. It is not a
permission signal and does not replace human reward, operator gates, write
approval, or production-action authorization.
Run shape:
{
"generated_at": "2026-05-31T21:15:00+00:00",
"goal_id": "complex-project-main-control",
"classification": "ready_for_controller_opt_in",
"lifecycle_phase": "controller_gated",
"lifecycle_flags": [
"controller_gated",
"adapter_inspected"
],
"recommended_action": "ask the target controller to opt into a read-only map before any mutation",
"health_check": "8/8",
"run_id": "controller-run-001",
"subagents": [
{
"run_id": "docs-map-001",
"goal_id": "docs-map-subagent",
"parent_run_id": "controller-run-001",
"spawned_by_goal_id": "complex-project-main-control",
"agent_role": "explorer",
"state": "completed",
"work_scope": [
"docs/**"
],
"touched_path_count": 0,
"handoff_summary": "Mapped task clusters without editing files.",
"quota_spend_slots": 1
}
],
"subagent_count": 1,
"controller_readiness": {
"classification": "ready_for_read_only_not_decision",
"read_only_observer_ready": true,
"decision_advisor_ready": false,
"write_controller_ready": false,
"missing_gates": [
"human_reward_capture",
"aligned_eval_decision_evidence"
],
"review_judgment": "safe to connect read-only observation, but not decision advice",
"next_handoff_condition": "record aligned eval evidence and one human reward event",
"gates": [
{
"id": "durable_goal_context",
"ok": true,
"review": "goal state and run history are available"
},
{
"id": "human_reward_capture",
"ok": false,
"review": "no operator reward has been recorded yet"
}
]
},
"human_reward": {
"recorded_at": "2026-06-01T00:05:00+00:00",
"decision": "continue_route",
"reward": "positive",
"reason_summary": "operator accepted the route because the comparable metric improved and validation was aligned",
"follow_up": "promote the route to a longer-window check"
},
"json_exists": true,
"markdown_exists": true
}
Optional compact fields such as active_task_count, active_priorities, and
cache_check may appear when an adapter records them. Experiment-controller
adapters may also include compact controller_readiness and human_reward
summaries.
lifecycle_phase is derived by the status layer so the dashboard can separate
state interaction stages from adapter-specific classifications:
connected: the goal is registered with a connected adapter but has no run.mapped: the latest run is a genericread_only_project_map.refreshed: the latest run is a state-onlystate_refreshedupdate.adapter_inspected: a project adapter produced a compact run.reward_judged: a human reward overlay is attached to the run.operator_approved: an operator gate was approved and the approvedagent_commandmay be handed to the target project agent.operator_gated: an operator gate was rejected or deferred, so the goal stays gated.controller_gated: controller readiness evidence is present, but the goal is still missing a gate such as human reward or comparable evidence.controller_ready: decision-advisor or write-controller readiness is present.planned,registered, andrun_recorded: fallback phases for goals that are not yet connected or have an unclassified run.
lifecycle_flags may contain more than one phase. For example, a run can be
both adapter_inspected and reward_judged, both adapter_inspected and
operator_approved, or both adapter_inspected and controller_gated. UIs
should show the primary phase first and use flags as secondary badges.
When a Codex-owned goal carries lifecycle_phase=focus_wait or a
continuation_boundary flag, quota should surface state=focus_wait instead
of eligible. This keeps compute quota separate from delivery focus: the goal
can remain healthy and visible while automatic turns wait for new evidence,
owner input, external eval, or a clean baseline.
Quota may also use state=focus_wait when post-handoff delivery has repeatedly
missed the declared outcome floor. In that case blocked_action_scope should
identify delivery_outcome_floor, and the target agent should either return
with outcome-scale evidence or report a blocker without spending another slot.
When the floor declares must_advance, the quota payload should split ordinary
delivery from recovery delivery with normal_delivery_allowed=false,
recovery_delivery_allowed=true, should_run=true, and
effective_action=outcome_floor_recovery
so dashboard and heartbeat consumers do not mistake the recovery lane for a
quiet skip.
For controller_readiness, the status export keeps only controller-stage
booleans, missing gate names, operator-facing review text, next handoff
condition, and compact gate rows with id, ok, and review. For
human_reward, the status export keeps only recorded_at, decision,
reward, reason_summary, and follow_up. For operator_gate, the status
export keeps only recorded_at, gate, decision, operator_question,
reason_summary, follow_up, and agent_command. Operator-gate runs may also
include a compact operator_gate_resume_contract with
version=operator_gate_resume_contract_v0, gate_id, created_state_ref,
latest_state_ref, operator_decision, freshness/precondition checks, rebase
result, resulting action, and validation-after-resume text. This contract is
the public checkpointed-decision surface. Its rebase is scoped to the approval /
resume decision point only; it is not a repo/worktree rollback, restore, or
time-travel mechanism. Richer evidence belongs in private run payloads.
Operator gate decisions answer "may the project agent cross this gate?" and are separate from reward signals. Use them for approvals such as read-only map opt-in:
loopx operator-gate \
--goal-id complex-project-main-control \
--decision approve \
--reason-summary "同意先执行 read-only map opt-in"
The dry-run form appends nothing. A real append writes an
operator_gate_approved, operator_gate_rejected, or
operator_gate_deferred compact run. Approved gates are surfaced as
Codex-ready with the approved agent_command; rejected/deferred gates stay in
the user/controller lane with the recorded reason. The approved command is not a
time-travel replay of the old checkpoint: at the approval/resume decision point,
the target turn must re-read current registry, ACTIVE_GOAL_STATE, quota, repo
dirty/ref snapshot, policy, and run status. That check decides whether the
approved action is still valid now; it must not carry the whole repository state
back to the old gate. Quota spend, eval/experiment launches, production writes,
or external messages belong after the fresh approved resume.
Operators can append human_reward with the CLI:
loopx reward \
--goal-id example-experiment-goal \
--decision continue_route \
--reward positive \
--reason-summary "comparable validation improved and the route is worth extending"
The command appends a compact overlay row to the goal's index.jsonl. History
loading merges later rows with the same run key, so feedback can be added
without rewriting the original run JSON or Markdown payload.
When the operator feedback is a route, priority, benchmark-protocol, safety, or operating-rule correction, the overlay may also include a compact lesson:
loopx reward \
--goal-id example-experiment-goal \
--decision route_correction \
--reward mixed \
--reason-summary "run the driver repair before expanding cases" \
--lesson-kind route \
--lesson-summary "Do not expand cases before driver repair is validated" \
--lesson-avoid "expand cases before driver repair" \
--lesson-prefer "validate driver repair first"
human_reward.lesson is a warning/rebase signal, not write-control. Status
exports the compact lesson, and quota should-run may emit
reward_lesson_projection_warning when the current recommended_action
overlaps a recent lesson's avoid phrase. Agents should then update the
affected todo or Next Action before continuing.
Both dry-run and append responses include:
{
"active_state_summary": "dry-run:将记录目标 `example-experiment-goal` ...",
"project_agent_visibility": {
"source_of_truth": "run_bound_human_reward_overlay",
"history_command": "loopx history --goal-id example-experiment-goal --limit 3",
"active_state_role": "summary_only",
"review_packet_role": "optional_handoff_only"
}
}
Agents should treat history_command as the standard visibility path. Active
state can repeat the summary and next action for context, but it is not the
durable reward store.
When loopx status renders Markdown, a latest run with human_reward
should expand the compact reward fields under Run History and repeat the same
project-agent history lookup. This keeps the dashboard as the operator surface
while making CLI status sufficient for project agents that only need to notice
and inspect a recorded reward.
The Markdown response should also show a short Write Effect section near the
top so the operator can see the selected run, whether the overlay was actually
appended or only previewed, whether active-state writeback would happen, and
the one project-agent history lookup.
The CLI can also preview or perform the active-state summary write when the operator explicitly asks for it:
loopx reward \
--goal-id example-experiment-goal \
--decision continue_route \
--reward positive \
--reason-summary "comparable validation improved and the route is worth extending" \
--write-active-state-summary
That response includes active_state_update, for example:
{
"active_state_update": {
"requested": true,
"section": "Progress Ledger",
"would_write": false,
"written": true,
"already_present": false
}
}
The loopback dashboard write path is opt-in. By default serve-status exposes
only POST /reward/dry-run; when started with --enable-reward-write-api on a
loopback host, it also exposes POST /reward/append. The append request must
reuse the preview_id returned by the dry-run response, so a changed payload,
changed selected run, or changed raw index count forces the operator to preview
again. The compact browser response does not expose index paths, state file
paths, or raw private evidence.
Event Ledger Summary
event_ledger_summary is an optional dashboard-friendly projection over the
compact run index. It makes the durable-execution contract visible without
requiring a dashboard or heartbeat prompt to read the full run history.
The summary classifies sampled run records into:
accounting: quota and spend rows such asquota_slot_spent;decision: operator gates, resume contracts, deferrals, approvals, andhuman_rewardoverlays;evidence: eval, metric, CI, deploy, artifact, blocker, failure/done, or read-only evidence-poll observations;state: state refresh and other compact state-projection rows;work: remaining bounded delivery or implementation progress rows.
The summary reports 24h/7d totals and per-goal counts by event class. It also
reports optional benchmark_runs_24h and benchmark_runs_7d counts when
sampled run-index records carry a compact benchmark_run_v0 object. These
benchmark counts are evidence projections, not official score claims.
Consumers should use them to notice that benchmark evidence exists, then drill
into run_history or the project-local history command for exact evidence. It
must not replace append-only run, reward, quota, validation, artifact, blocker,
or evidence events.
Each per-goal row may also include latest_event_class and latest_event_at,
which are compact routing hints for the dashboard, not replacements for the
latest run record.
When a compact run record includes benchmark_run_summary, it is a redacted
projection of benchmark_run_v0: runner, benchmark id, job name, mode, agent
summary, progress counts, token/cost metrics, validation state, up to three
trial summaries, relative evidence categories, resume/inspect command
templates, and stop conditions. For long-horizon benchmark evidence it may also
carry compact worker_bridge_outcome.wall_time_policy fields: timeout tier,
whether official timeout/resources changed, comparability, observed wall time,
effective wall-time limit, and whether the observed or expected run meets the
true long-task bar (>=1800s). These fields are claim guards, not scoring
changes. It may also carry overhead_attribution_counters, a compact
runner-side summary of wall time, usage metrics, worker bridge event counts,
LoopX CLI call totals, and Codex runtime goal-tool counts. That summary
is for private paired-run diagnosis only; it is not a raw phase trace and must
not be used as a score uplift claim. These fields must not include raw Codex
sessions, host absolute paths, credentials, private benchmark material, or
leaderboard upload claims.
Benchmark adapters that write worker-side or bridge-side compact runs should reuse the generic validation/claim fields below instead of inventing benchmark-specific synonyms:
validation_scope: the layer the worker validated. Recommended values areworker_bridge_connectivityfor control-plane/bridge reachability,environment_readyfor environment-only readiness,worker_case_successfor an explicit worker-side case-success claim, andofficial_verifier_resultwhen an official verifier result is present.validation.bridge_connected: whether the LoopX-enhanced worker control path is connected. This supports a connectivity claim only; it is not case success.validation.case_success_claimed: whether the worker explicitly claims the benchmark case is solved. A missing scope or a legacystatus=passedmust be treated as ambiguous when the official score is zero.validation.official_verifier_validation_present,validation.official_verifier_status, andofficial_task_score: whether the benchmark-owned verifier has spoken, and what it reported.claim_boundary.bridge_connectivity_claim_allowed,claim_boundary.case_success_claim_allowed,claim_boundary.official_score_claim_allowed, andclaim_boundary.forbidden_claims: the reusable boundary that keeps connectivity evidence, worker claims, official score claims, and leaderboard claims separate.
Consumers must not promote bridge_connected=true, worker CLI-call evidence,
environment readiness, or unscoped validation.status=passed into official case
success. Official case success requires an official verifier result or a
benchmark-specific adapter contract that is explicitly mapped into
official_task_score.
When a compact run record includes benchmark_result_summary, it is a redacted
projection of benchmark_result_v0, not a raw benchmark log reader. The summary
keeps official_task_score separate from control_plane_score; for
control_plane_score_core_v0 it preserves the fixed component order
(restartability, stale_state_avoidance, evidence_discipline,
boundary_safety, writeback_quality, gate_compliance,
failure_attribution, overhead) plus compact counts such as validation,
writeback, spend, and forbidden-access totals. It must not include changed file
paths, raw trajectories, local artifact paths, credentials, private traces, or
leaderboard claims.
loopx history append-benchmark-result --benchmark-result-json <path>
is the matching append path for this projection. It is dry-run by default and
accepts only a compact benchmark_result_v0 JSON object; it does not discover
or parse runner directories, task artifacts, Codex sessions, private traces, or
leaderboard outputs.
When a compact run record includes benchmark_comparison_summary, it is a
redacted projection of benchmark_comparison_v0. The summary links paired
benchmark_result_v0 scenarios and exposes only compact comparison fields such
as task/comparison id, mode pair, baseline/treatment scenario ids,
official-task score delta, control-plane score delta, overhead/writeback/spend
deltas, readiness booleans, compared metric names, and stop-condition labels.
It may carry numeric deltas or public-safe symbolic deltas such as
not_applicable_readiness_only. It must not include raw benchmark logs,
changed file paths, absolute runner directories, Codex session transcripts,
private traces, credentials, or leaderboard submission artifacts.
loopx history append-benchmark-comparison --benchmark-comparison-json <path> is the matching append path for this projection. It is dry-run by
default and accepts only a compact benchmark_comparison_v0 JSON object; it
does not discover result pairs from runner directories, parse raw task
artifacts, invoke benchmark runners, or infer leaderboard claims.
When benchmark_comparison_summary is present, status may also include
benchmark_comparison_decision_note. This is a compact consumer-facing note,
not a new benchmark event. It maps the paired deltas into report-ready
claim_boundary and next_decision hints: whether the evidence is
readiness-only, control-plane-only, an official-score candidate, failure
analysis, or still boundary-gated; which claims are allowed; which claims are
forbidden; and the minimum next evidence. The note must preserve official-score
delta versus control-plane delta separation and must not authorize real
benchmark execution, model-backed simulator work, private traces, or
leaderboard claims.
When a compact run record includes benchmark_experiment_report_summary, it is
a redacted projection of benchmark_experiment_report_v0. The summary keeps the
paper/report surface separate from raw benchmark execution: compact experiment
identity, official-score eligibility, passive control-plane score hints,
operator-simulator ablation state, claim boundary, negative-result layers, and
next-decision fields. It must not include raw benchmark logs, local artifact
paths, Codex session transcripts, private traces, credentials, or leaderboard
submission artifacts.
loopx history append-benchmark-report --benchmark-report-json <path> is
the matching append path for this projection. It is dry-run by default and
accepts only a compact benchmark_experiment_report_v0 JSON object; it does
not run a benchmark, invoke a model or simulator, read runner directories, parse
private artifacts, or infer leaderboard claims.
When a compact run record includes active_user_assisted_pilot_summary, it is a
redacted projection of active_user_assisted_pilot_v0. The summary is for
assisted-collaboration research only: compact pilot identity, failure trigger,
active-injection contract flags, frequency budget, visibility policy,
operator-simulator audit counts, claim boundary, and next-run decision. It must
not include raw simulator messages, worker chat transcripts, local artifact
paths, hidden tests, expected solutions, benchmark answer keys, private traces,
credentials, or leaderboard submission artifacts. It must also keep the
assisted-collaboration claim separate from official benchmark score claims.
loopx history append-active-user-assisted-pilot --active-user-pilot-json <path> is the matching append path for this projection. It is dry-run by
default and accepts only a compactable active_user_assisted_pilot_v0 JSON
object; the CLI compacts the input before writing durable history. It does not
run a benchmark, call a model-backed simulator, read private runner artifacts,
interact with a worker, infer hidden test results, or authorize leaderboard
claims.
When benchmark_experiment_report_summary is present, status may also include
benchmark_experiment_report_readiness_note. This is a derived consumer note,
not a new benchmark event or publication approval. It turns the compact report
into a small readiness and next-run authorization hint, such as
negative_or_control_plane_only, fixture_only, review_required, or
assisted_mode_separate. The note must preserve the no-leaderboard and
no-simulator claim boundaries unless explicit evidence and operator approval
exist, and it must keep raw benchmark logs, local artifact paths, private
traces, Codex session transcripts, credentials, and submission artifacts out of
status and review packets.
Status may also derive benchmark_experiment_report_replay_decision from the
readiness note. This is the smallest next-run summary a worker should need
before deciding whether to replay a fixture, ask for operator review, or defer.
It is intentionally a status/review-packet-only consumer of an already durable
run-history report event; it does not create runner authority, execute
benchmarks, call model APIs, enable simulator work, or authorize leaderboard
publication.
docs/research/long-horizon-agent-benchmarks/benchmark-report-chain-map-v0.md
is the reviewer-facing map for this reporting chain. It names the public-safe
order from benchmark_run_v0 through
benchmark_experiment_report_replay_decision_v0 and the handoff fields a
worker may inspect. The map is explanatory only: it does not add a status
field, append a run-history event, or create authority to execute an external
benchmark path. When a latest run has a replay decision, the review-packet
handoff follow-through summary may include
chain_map=benchmark-report-chain-map-v0.md so a worker can jump from the
compact replay decision back to the full reviewer-facing chain contract.
The same information may appear in
loopx review-packet --handoff-only --format json as
benchmark_report_chain_handoff with
schema_version=benchmark_report_chain_handoff_v0. That JSON projection is a
read-only relay helper over existing status/run-history fields; it does not add
a new event type, runner authority, simulator path, raw artifact pointer, or
leaderboard claim.
Promotion Readiness Summary
promotion_readiness_summary is an optional release-control projection over the
runtime release ledger, with legacy Goal run-history events retained as a
read-compatible fallback only when the runtime ledger has no valid readiness
event. It finds the latest
canary_promotion_readiness_smoke_group event and reports whether that evidence
is fresh enough to trust before promoting a live checkout into the default local
release snapshot. New evidence is runtime-scoped because release readiness is
shared by every Goal using that local installation; it does not require or
mutate a project Goal.
The summary reports:
freshness_status:fresh,stale,missing, orunknown.freshness_window_hours: the freshness window, currently 24 hours.is_freshandrequires_readiness_run: compact guards for installers, dashboards, and heartbeat jobs.age_seconds/age_hours: evidence age when the event timestamp is parseable.json_exists/markdown_exists: whether the latest evidence artifacts still exist.dashboard_readiness:passedorskippedfor runtime-level evidence, so a deliberate omission is never indistinguishable from a successful check.
This projection does not promote anything and does not replace the append-only
release artifact under the LoopX runtime root.
scripts/install-local.sh consumes the same readiness fact only to print a
non-blocking warning; operators should still run loopx doctor or the
canary-promotion readiness smoke for exact local release evidence.
Decision Freshness Summary
decision_freshness_summary is an optional checkpointed-decision projection over
the sampled run history. It exists because a chat thread is not the source of
truth for long-running control decisions: the durable source is the append-only
run history and event ledger. A Codex thread may remember an old approval or
reward, but before spending quota, launching work, or mutating external state it
must rebase that decision point against the latest registry, active state,
quota, policy, and run-status facts.
The summary treats compact human_reward, operator_gate, operator-gate resume
contracts, and reward/gate-like classifications as checkpointed decisions. For
each sampled decision it reports:
freshness_state:fresh,rebase_required, orstale_rebase_required.stale_by_age: whether the decision is older than the freshness window.newer_event_count_7dandnewer_event_classes_7d: newer sampled events for the same goal inside the seven-day window.requires_decision_point_rebase: whether the worker should refresh current control-plane state before reusing the old decision.
This is a decision-point rebase helper, not a repository reset or time-travel
mechanism. Newer events mean the worker should reinterpret the old reward or
gate in the current state; they do not roll the project back to the old chat
context. If status --limit omits older runs, the summary may miss a stale
decision, so consumers should treat it as an operational warning surface and
drill into the project history for exact replay when needed.
quota should-run consumes this projection for the selected goal as
decision_freshness_warning whenever a sampled decision has
requires_decision_point_rebase=true. That warning is deliberately additive:
it does not flip should_run, but it tells the worker that any old reward or
gate it plans to reuse must be rebound to the current control-plane state first.
Dashboard project/detail and share surfaces should render non-empty same-goal
items as a compact Chinese operator warning before approval or relay, explicitly
clarifying that decision-point rebase means rereading current control-plane state,
not rolling the repository or project back to the old chat context.
quota should-run also consumes promotion_readiness_summary as
promotion_readiness_warning when the sampled canary promotion-readiness
evidence is missing, stale, or unknown. The warning is a release-readiness guard
surface, not a scheduling decision: it does not flip should_run, but it lets a
heartbeat worker report that the release snapshot should not be promoted until
fresh canary promotion-readiness evidence is written to the shared runtime
release ledger. This keeps release readiness in queryable control-plane
state instead of relying on dashboard prose, doctor output, or a chat thread.
The warning message names the writeback command,
python3 examples/canary/canary-promotion-readiness-smoke.py. A run with
--no-write-evidence validates the canary without refreshing this durable
projection and cannot clear the warning.
Usage Summary
usage_summary is an optional dashboard-friendly proxy derived from the same
compact run history. It is not billing telemetry and intentionally excludes
token counts, raw thread logs, local project paths, private artifact contents,
or anything that would require reading a Codex session transcript.
The summary currently reports:
runs_24h/runs_7d: observed compact run records in the current status sample.quota_spend_slots_24h/quota_spend_slots_7d: slots fromquota_slot_spentevents in that sample.automation_run_count_24h/automation_run_count_7d: quota spend events whose compactquota_event.sourceisheartbeat,automation, orcron. If the compact run index does not retain a source,quota_slot_spentis counted as an automation/spend proxy rather than dropped.progress_signal_run_count_24h/progress_signal_run_count_7d: compact run records that look like actual project or adapter progress rather than accounting/bookkeeping. This proxy excludesquota_slot_spentandstate_refreshed, so dashboards can spot automation loops that keep spending or refreshing state without producing a fresh delivery, validation, mapping, blocker, or gate signal.project_share_24h: per-goal share of observed 24h runs, rounded to three decimals.
Because status --limit can bound the recent run sample, consumers should
display sample_run_count and treat these values as operational signals for
finding busy project lines, not as precise historical accounting.
The markdown status renderer includes the same totals plus the top sampled
goals so heartbeat operators can notice low-progress loops without opening the
full JSON payload.
Display Model
A first useful UI can be built from the export alone:
- Header: operator actions and selected-action sharing should be above auxiliary source controls, metrics, and raw drill-down, because the dashboard is a user decision surface rather than an agent CLI mirror.
- Metrics:
ok,goal_count,run_count, and contract summary. - Canonical home: the default dashboard route should render a Chinese-first control-plane home over the shared global status source when available. It should emphasize project cards, each project's top four todos with per-item status, true user todos, agent-priority todos, quota/guard state, and latest evidence before raw drill-down. This is a browser presentation over the status export, not a new status source.
- Detailed ops view:
?view=opsmay render the older debugging workbench with raw queue filters, selected-goal details, reward drafts, and run-history panels. The legacyview=sharevalue may remain as a compatibility alias for the canonical home, but non-ops views should not be treated as separate durable modes. - Usage snapshot: optional
usage_summaryproxy metrics for observed 24h/7d runs, quota spend slots, automation run count, progress-signal run count, and busiest goals by current sample share. - Promotion readiness ops panel: optional
promotion_readiness_summarystatus showing whether the latest canary promotion-readiness evidence is fresh, stale, missing, or unknown before a release snapshot is promoted. - Promotion gate ops panel: optional
promotion_gatestatus showing the compactcan_promote/should_warnrelease-promotion decision derived from that same readiness event; dashboard code should display it, not recompute it. - Decision freshness ops panel: optional
decision_freshness_summarymetrics for global decision count, stale count, rebase-required count, fresh count, and top affected goals. The panel is a routing warning for old reward/gate reuse; exact replay and event ordering remain in append-only run history. - Compute quota summary: goals eligible for the next agent turn, focus-waiting goals, throttled goals, waiting goals, paused goals, and operator-gated goals should be visible on the first screen once quota fields are present. Automation cadence should be treated as execution detail, not the only priority signal.
- User action summary: first-screen cards should derive from the same selected operator decision and reward-default logic, grouping reward gates, controller opt-ins, evidence watches, Codex handoffs, and blocking health items before raw goal detail. Cards may show the matching safe CLI path label or command plus the reward-draft decision/reward hint, but those are affordances over the agent-facing status export, not browser-side writes. The dashboard can derive local action-kind filters from these cards, such as reward, controller, Codex, evidence, and health, without adding new status fields. Persisting that focus in a URL search parameter is dashboard UI state; it does not change the status contract or durable goal truth.
- Selected goal detail: the dashboard may persist the selected
goal_idin URL search state so a review link can reopen the same run-history detail. This selected-goal state is not part of the status export and must not be treated as an approval, reward, or controller signal. - Review link: the dashboard may copy a browser URL that includes local
actionKind, selectedgoalId, sourcestatusUrl,lane,severity, and optionalview=opssearch state. That link is a user review affordance over this export; it must not add fields to the status contract or mutate goal runtime state. - Review Packet: the dashboard should expose one canonical copy affordance for
the selected action card rather than separate link, reply, handoff, and agent
prompt buttons. The packet may include the review link, Chinese
agree/disagree/reason/next-step prompt, project-agent instructions, safe local
path, reward/default hint, and local dry-run preview. For reward actions, the
project-agent section should point to the run history lookup, not ask the
target project agent to append or dry-run user reward on the user's behalf.
For controller opt-in actions, the packet must keep this order: human
question, user/controller-owned local gate dry-run preview, then
project-agent dry-run instruction. The dashboard/operator view owns the human
decision; the project-agent command is only the after-approval dry-run
execution path. For an approved Codex action carrying
agent_command, the copy affordance should switch to handoff-only content: no human gate wrapper, only the target goal guard, forwarding condition, execution boundary, stop condition, and command. It is still browser UI state and must not be parsed as durable reward, approval, controller opt-in, or write-control. - Goal directory: all
run_history.goals, grouped mentally bydomainand enriched with matching attention items and lifecycle phase badges when a goal needs action. - User review map: counts for connected, mapped, refreshed, adapter-inspected, reward-judged, and controller-ready goals, written as operator-facing states rather than raw adapter statuses. Goals with controller evidence but missing gates should be shown as controller-gated, not controller-ready.
- Primary queue:
attention_queue.items. - First-screen action cards: when a queue item carries
operator_question, show that question as the primary operator prompt beforerecommended_action.recommended_actionremains context;agent_commandis displayed as the safe target-agent command only after the operator question has been answered. When a Codex-owned queue item hasquota.state=focus_wait, show it as a focus-wait owner blocker even ifwaiting_on=codex: the card should say why it is quiet, who or what can unblock it, which evidence is needed, and that the copy packet is only for status/history inspection. - Queue gate hints: show
controller_stage,missing_gates, andnext_handoff_conditiondirectly in queue rows so an operator can see why a watched goal is not ready yet without opening the full run payload. - User lane: items with
waiting_on=user_or_controllerorcontroller. - Codex lane: items with
waiting_on=codex. - Watch lane: items with
waiting_on=external_evidenceorwaiting_on=monitor_signal. - Dreaming lane/badge: items with
project_asset.dreaming_lane_badge.schema_version=dreaming_lane_badge_v0. These items are advisory review surfaces; delivery lanes continue to follow quota and current owner/gate routing. - Health panel: contract
errors,warnings, andchecks. - Run detail panel: selected goal from the attention queue, compact classifications, authority coverage, controller readiness, health checks, reward signals, and artifact availability.
- Reward CLI draft: selected goal plus latest compact run timestamp should be
enough to generate a local
loopx reward --dry-runcommand. Draft fields should default from the selected operator decision and missing gates, while remaining editable before validation. The dashboard should append feedback only when the live loopback status server explicitly exposes the reward write API. - Reward dry-run check: when the dashboard is loaded from a loopback status
server, it may validate the same draft through
POST /reward/dry-runand display the compact result, including the Chinese active-state summary and project-agent history command. The response includespreview_id. - Reward append: when the same loopback server is started with
--enable-reward-write-api, the dashboard may send that exact preview toPOST /reward/append. A successful append writes one run-boundhuman_rewardoverlay, refreshes status, and makes the next project-agent automation able to see the feedback throughloopx statusorloopx history. - Reward source of truth: durable user reward belongs in a run-bound
human_rewardoverlay appended throughloopx reward. Active goal state can summarize that such a reward was recorded, and the Review Packet can be forwarded to another project agent for immediate coordination through the returned history lookup, but neither replaces the compact run overlay as the multi-agent reward signal. - Operator decision: selected goal detail should translate
waiting_on,severity,lifecycle_phase,missing_gates, andrecommended_actioninto a human stance such as review/authorize, let Codex continue, wait for evidence, or fix health first. Raw classifications remain drill-down details. - Safe CLI path: selected goal detail should also show the next safe local command class for that stance: status/history inspection, read-only-map or refresh-state dry-run, or reward dry-run through the Reward CLI Draft. This is a dashboard-to-agent bridge; it must not imply browser-side approval, reward append, or write-controller execution.
Browser-side reward append is outside the default status server behavior. If a local server enables it, it must follow the explicit opt-in boundary in dashboard-reward-write-boundary.md.
Suggested badge mapping:
severity=high: blocking.severity=action: needs a decision or bounded work segment.severity=watch: no immediate action; wait for evidence or a material monitor transition.
Static Dashboard Demo
The repository includes a no-dependency renderer that turns any status JSON export into a static HTML dashboard:
loopx --format json status > /tmp/goal-status.json
python3 examples/render-status-dashboard.py /tmp/goal-status.json /tmp/goal-status.html
The generated page groups queue items into user/controller, Codex-ready, and external-evidence lanes. It is a small demo for local inspection and UI prototyping; it is not the product dashboard.
The official dashboard direction is a React/Vite control-plane app that can render this same JSON contract with typed routes, filters, tables, charts, and drill-down pages. See dashboard-frontend-selection.md.
Adapter Responsibilities
Adapters should write compact run index records that include:
generated_atgoal_idclassificationrecommended_actionjson_pathmarkdown_path
Project adapters may add compact public-safe fields such as health_check,
active_task_count, active_priorities, or a compact human_reward summary.
Raw logs, prompts, private metrics, workspace paths, and internal document
links belong in private run payloads, not in compact index records.
Benchmark status snapshots may include
runs[].observable_handle_policy with
schema_version=benchmark_observable_handle_policy_v0. This is an additive,
public-safe lifecycle projection for one-shot benchmark schedulers. Consumers
may use it to decide whether a run should continue polling, unload/disable a
local launchd label, or write a precise missing-handle blocker before any
rerun. It must be derived from compact artifacts, pid liveness, and run labels
only; it must not expose raw logs, task text, trajectories, scheduler payloads,
or local paths. Snapshots may also include
runs[].process_polling.schema_version=benchmark_process_polling_v0 to make
the polling boundary explicit. That object records that polling used the
private pid file and compact artifacts only; it must keep
process_table_read=false, cmdline_read=false, argv_read=false, and
raw_process_payload_recorded=false so benchmark task prompts embedded in
worker argv cannot leak into status, rollout logs, chat summaries, or
control-plane projections.
Boundary
The JSON export is safe to feed to a local dashboard only if the registry ids, adapter classifications, and recommended actions are sanitized. Before sharing an export publicly, verify that it contains no:
- local absolute user paths,
- private document links,
- credentials,
- raw production logs,
- internal task ids,
- private metric values.
The public examples under examples/ are sanitized and can be used for demos.
Compatibility Rules
- Additive fields are allowed.
- Existing field meanings should remain stable across minor versions.
- Consumers should ignore unknown fields.
- Consumers should handle missing
attention_queue.itemsas an empty queue. - Consumers should handle missing
run_historyas unavailable. - Consumers should treat
contract.ok=falseas a stronger signal than an empty attention queue.