Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions docs/heartbeat-automation-prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ two separate layers:
runtime source of truth. This makes the Codex thread a replaceable worker and
leaves durable task truth in LoopX.

Prompt compression must preserve both conditions and required responses. A
missing concrete user action under `NOTIFY` calls for state-projection repair,
not just a diagnostic label. Under `DONT_NOTIFY`, repair stays internal; it
does not grant notification authority. Keep these semantics in brief and thin
prompts as well as the expanded contract, within their existing size budgets.

Do not paste the full lifecycle protocol into the visible goal text, and do not
use a short goal text such as "advance TODO" as the recurring automation body.
The short text names the goal; the generated task body enforces quota, gates,
Expand Down Expand Up @@ -446,18 +452,19 @@ If the result says should_run=true:
turns, do not append a quota spend for the self-cancel turn, and return
NOTIFY explaining that the automation was cancelled because it was spinning
without progress.
4. Choose one bounded, verifiable progress segment from that audit. It may be a
coherent batch across related implementation, test, doc, and state-writeback
files when the write scope is clear and validation is explicit; it should not
be forced into a tiny single-file step.
5. Do that segment only. Stay inside goal_boundary when present and keep
4. Choose scope-bounded work toward a verifiable result. Size by task, evidence
and risk, not calls, files or wake cadence. Related implementation, research,
tests, docs and writeback may form one coherent effort; a focused correction
can also be sufficient. One operation/writeback is not a stop condition;
obey budgets, explicit stops, settlement and replan requirements.
5. Execute that scoped work. Stay inside goal_boundary when present and keep
public/private boundaries intact. Public-safe repo publication is not an
operator gate by itself: for routine public project work, commit, push, and PR
creation may proceed autonomously after validation and a clean public/private
boundary scan. Stop and surface a user/controller gate only for private or
company-internal material, credentials, destructive git operations,
production actions, or repository rules that explicitly require review.
6. Run the smallest useful validation.
6. Run validation proportionate to the change and risk.
7. Write back changed files, validation, critic, and next action to the active
state. If a user/owner todo appears, do not hide it in prose:
`loopx todo add --goal-id <GOAL_ID> --role user --task-class user_gate --blocks-agent <agent-id>`
Expand Down
20 changes: 16 additions & 4 deletions docs/quota-allocation.md
Original file line number Diff line number Diff line change
Expand Up @@ -992,10 +992,22 @@ common modes are:
- `mapped_noop_if_unchanged`: the latest compact read-only map already exists;
if there is no new user instruction, owner evidence, agent todo, stale source,
or safe handoff, return a quiet no-op without another dry-run or quota spend.
- `steering_audit_then_one_step`: the goal is eligible but needs the normal
steering audit before selecting one bounded progress segment. A coherent
implementation/test/state batch is valid when scope and validation are clear;
the contract is bounded, not tiny.
- `steering_audit_then_one_step`: this compatibility mode name does not impose
a one-operation limit. The eligible goal needs a steering audit before
scope-bounded work toward a verifiable result. Work size follows task,
evidence and risk, not calls, files or wake cadence. Related implementation,
research, tests and writeback may form one coherent effort; a focused
correction can also be sufficient. Explicit stops, budgets, Todo/lease
boundaries, settlement and replan requirements remain authoritative.

All heartbeat prompt sizes, including the default thin prompt, carry this
scope-bounded work guidance. This is a prompt clarification, not a change to
execution-profile thresholds, scheduler cadence, permissions or spend rules.
Fine-grained mode still plans independently verifiable checkpoints and checks
fresh evidence before a successor; checkpoint granularity is not a tool-call
limit. Read-only monitor polls, bounded recovery attempts and explicit
`end_current_heartbeat` transitions retain their existing limits. Do not turn
this guidance into a minimum batch size or a reason to bypass those limits.

The same response includes `interaction_contract.schema_version =
loopx_interaction_contract_v0`, the top-level user/agent/CLI protocol
Expand Down
46 changes: 25 additions & 21 deletions examples/control_plane/heartbeat-prompt-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ def user_output_policy(task_body: str, *, mode: str) -> dict[str, str]:
else:
assert "`user_channel.notify` controls OUTPUT only" in body
assert "NOTIFY=向用户输出动作; DONT_NOTIFY=安静输出" in body
assert "Due/peer gate != prompt" in body
assert "missing NOTIFY action->" in body
assert "Due/peer非用户动作" in body
assert "NOTIFY缺动作→" in body
assert "具体user todo未投影" in body
assert "需修复LoopX状态投影" in body
assert "静默时内部修复" in body
if mode == "brief":
assert "Return only under `user_channel.notify=NOTIFY`; else quiet." in body
return {
Expand Down Expand Up @@ -455,8 +457,8 @@ def main() -> int:
"else quiet."
) in compact_task
for phrase in (
"compact LoopX heartbeat body",
"Expanded lifecycle contract",
"Compact policy: registry/state/adapter/`goal_boundary`",
"Detail:",
"loopx heartbeat-prompt --full --goal-id public-heartbeat-goal --active-state /tmp/public-heartbeat-goal/ACTIVE_GOAL_STATE.md",
'loopx --format json --registry "$HOME/.codex/loopx/registry.global.json" quota should-run --goal-id public-heartbeat-goal',
"state=operator_gate",
Expand Down Expand Up @@ -585,8 +587,8 @@ def main() -> int:
"--goal-id loopx-meta --agent-id codex-product-capability --available-capability network "
"--available-capability external_evidence_poll",
"`user_channel.notify` controls OUTPUT only: NOTIFY=向用户输出动作; DONT_NOTIFY=安静输出",
"Due/peer gate != prompt",
"missing NOTIFY action->",
"Due/peer非用户动作",
"NOTIFY缺动作→",
"具体user todo未投影",
"Observed capabilities -> `--available-capability`; never user gates",
"host_action=pause_or_delete_current_heartbeat->automation_update stop(no-spend)",
Expand Down Expand Up @@ -629,7 +631,9 @@ def main() -> int:
assert brief_payload["thin"] is False, brief_payload
assert brief_payload["quota_guard_command"] == payload["quota_guard_command"], brief_payload
assert brief_payload["quota_spend_command"] == payload["quota_spend_command"], brief_payload
assert len(str(brief_payload["task_body"])) < len(str(compact_payload["task_body"])) * 0.56, (
# Preserve size ordering and the absolute budgets checked above. Essential
# shared guidance need not shrink by an arbitrary percentage in each mode.
assert len(str(brief_payload["task_body"])) < len(str(compact_payload["task_body"])), (
len(str(brief_payload["task_body"])),
len(str(compact_payload["task_body"])),
)
Expand All @@ -640,9 +644,9 @@ def main() -> int:
"Guard/retry; `LOOPX_TURN=<current_time_iso>`",
'loopx --format json --registry "$HOME/.codex/loopx/registry.global.json" quota should-run --goal-id public-heartbeat-goal',
"`user_channel.notify` controls OUTPUT only: NOTIFY=向用户输出动作; DONT_NOTIFY=安静输出",
"Due/peer gate != prompt",
"Due/peer非用户动作",
"Done->successor first; final->refresh->spend->no-follow-up",
"missing NOTIFY action->",
"NOTIFY缺动作→",
"具体user todo未投影",
"follow user channel",
"monitor_quiet_skip",
Expand All @@ -655,7 +659,7 @@ def main() -> int:
"review-packet --handoff-only",
"heartbeat_recommendation",
"goal_boundary",
"bounded segment/batch",
"scope-bounded work",
"validate/writeback/todos",
"Progress(actual,no upgrade)",
"Spend once; no pipe/retry",
Expand All @@ -671,7 +675,7 @@ def main() -> int:
"loopx heartbeat-prompt --thin --goal-id public-heartbeat-goal "
"--active-state /tmp/public-heartbeat-goal/ACTIVE_GOAL_STATE.md"
), thin_payload
assert len(str(thin_payload["task_body"])) < len(str(brief_payload["task_body"])) * 0.45, (
assert len(str(thin_payload["task_body"])) < len(str(brief_payload["task_body"])), (
len(str(thin_payload["task_body"])),
len(str(brief_payload["task_body"])),
)
Expand All @@ -683,8 +687,8 @@ def main() -> int:
"use selection_command when required",
"`quota should-run`",
"`user_channel.notify` controls OUTPUT only: NOTIFY=向用户输出动作; DONT_NOTIFY=安静输出",
"Due/peer gate != prompt",
"missing NOTIFY action->",
"Due/peer非用户动作",
"NOTIFY缺动作→",
"具体user todo未投影",
"host_action=pause_or_delete_current_heartbeat->automation_update stop(no-spend)",
"else RRULE/fallback_hint/ack/fail",
Expand Down Expand Up @@ -814,15 +818,15 @@ def main() -> int:
"2 consecutive eligible heartbeats are no-progress loops",
"self-cancel turn",
"repair path is",
"Choose one bounded, verifiable progress segment from that audit",
"coherent batch across related implementation, test, doc, and state-writeback",
"not be forced into a tiny single-file step",
"Choose scope-bounded work toward a verifiable result",
"a focused correction can also be sufficient",
"obey budgets, explicit stops, settlement and replan requirements",
"Stay inside goal_boundary when present",
"Public-safe repo publication is not an operator gate by itself",
"commit, push, and PR creation may proceed autonomously after validation",
"clean public/private boundary scan",
"private or company-internal material, credentials, destructive git operations, production actions",
"Run the smallest useful validation",
"Run validation proportionate to the change and risk",
"Write back changed files, validation, critic, and next action",
"Plan/top todo/route changes need todo/Next Action writeback",
"If a user/owner todo appears",
Expand Down Expand Up @@ -927,8 +931,8 @@ def main() -> int:
"2 consecutive eligible heartbeats are no-progress loops",
"self-cancel turn",
"repair path is",
"Choose one bounded, verifiable progress segment from that audit",
"coherent batch across related implementation, test, doc, and state-writeback",
"授权/预算内推进可验证结果",
"a focused correction may suffice",
"Stay inside `goal_boundary` when present",
"Public-safe repo publication is not an operator gate by itself",
"commit, push, and PR creation may proceed autonomously after validation",
Expand Down Expand Up @@ -987,9 +991,9 @@ def main() -> int:
"Run a short steering audit before choosing work",
"Include a product bottleneck lens",
"Run the no-progress self-repair check before choosing delivery work",
"Choose one bounded, verifiable progress segment from that audit",
"Choose scope-bounded work toward a verifiable result",
"Public-safe repo publication is not an operator gate by itself",
"Run the smallest useful validation",
"Run validation proportionate to the change and risk",
"loopx refresh-state --goal-id <GOAL_ID>",
'loopx --format json --registry "$HOME/.codex/loopx/registry.global.json" quota spend-slot --goal-id <GOAL_ID> --todo-id <SELECTED_TODO_ID> --slots 1 --source heartbeat --execute',
"If the dashboard or controller needs a state-only update after spend",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ def assert_default_bounded_delivery_mode() -> None:
lane=work_lane(open_count=1, advancement_count=1, monitor_count=0),
)
assert normal["recommended_mode"] == "steering_audit_then_one_step", normal
assert "bounded progress segment" in normal["spend_policy"], normal
assert "scope-bounded work" in normal["spend_policy"], normal


def main() -> int:
Expand Down
8 changes: 4 additions & 4 deletions loopx/control_plane/goals/start_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def build_goal_start_prompt(
agent_clause = f" Use agent id `{agent_id}` for quota/claim commands." if agent_id else ""
todo_rule = (
"plan the broader direction as evidence-linked notes, but write exactly one "
"current small, verifiable Agent advancement_task Todo; do not write a runnable "
"current independently verifiable Agent advancement_task Todo; do not write a runnable "
"successor ahead. Use `[P0]`/`[P1]`/`[P2]`, no `--priority`; User Todo only "
"for owner/private gates"
if fine_grained
Expand All @@ -182,11 +182,11 @@ def build_goal_start_prompt(
"Todo before work"
)
fine_rule = (
"\n8. Fine-grained mode: the current Todo must be one small verifiable checkpoint. "
"If it is too broad, split it before work. A coherent decision slice may complete "
"\n8. Fine-grained mode: the current Todo must be an independently verifiable checkpoint. "
"Split independent decisions before work. Scope-bounded work may complete "
"one or more causally related Agent advancement Todos in the same turn: after each "
"completion inspect its fresh evidence before creating or claiming the next Todo, "
"and settle only once after the slice. Use the existing replan obligation/ACK path "
"and settle only once after the work. Use the existing replan obligation/ACK path "
"when evidence changes direction or the bounded-chain review becomes due; never "
"prewrite a long runnable chain. Protocol/setup and capability re-entry steps stay "
"inline in the guided transaction, are not Todos, and do not count as advancement "
Expand Down
6 changes: 3 additions & 3 deletions loopx/control_plane/heartbeat/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@
)

FINE_GRAINED_TURN_RULE = (
"Fine-grained planning contract: each Todo must be one small verifiable checkpoint; "
"if broader, split before delivery. The turn budget is one coherent decision slice "
"Fine-grained planning contract: each Todo must be an independently verifiable checkpoint; "
"split independent decisions before delivery. Work follows one coherent direction "
"and may complete one or more causally related Agent advancement Todos. After each "
"completion inspect fresh evidence before creating or claiming a successor; continue "
"only while the direction remains unchanged. Validate and durably complete each Todo, "
"then perform accountable refresh and spend to settle the turn once after the slice. "
"then perform accountable refresh and spend to settle the turn once after the work. "
"A direction change or bounded-chain review must use the existing replan obligation/"
"ACK path before further delivery. Protocol/setup and capability re-entry steps are "
"inline non-advancement work: never create Todos or settle a turn for them alone."
Expand Down
16 changes: 10 additions & 6 deletions loopx/control_plane/heartbeat/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

DEFAULT_MATERIAL_QUEUE_RULE = "Do not consume the learning material queue unless the user explicitly asks."
DEFAULT_PERMISSION_RULE = "Do not ask for permissions when the current Codex session is already trusted."
SCOPE_BOUNDED_WORK_RULE = (
"授权/预算内推进可验证结果;按任务/证据/风险定规模,不按操作/文件数/心跳间隔。"
"操作/写回不自动结束;遵守停止/重规划。"
)
USER_TODO_FINAL_MESSAGE_RULE = (
"`interaction_contract.user_channel.notify` controls output: `NOTIFY` -> concrete "
"action; otherwise quiet. `should_run`/due monitor and other-agent scoped todos "
Expand All @@ -12,16 +16,16 @@
)
HEARTBEAT_NOTIFICATION_RULE_SHORT = (
"`user_channel.notify` controls OUTPUT only: NOTIFY=向用户输出动作; "
"DONT_NOTIFY=安静输出。执行义务看 `heartbeat_recommendation.agent_must_attempt`/"
"`execution_obligation.must_attempt_work`:true 时必须执行 bounded slice 并写回,"
"quiet no-op 仅当 false。"
"Due/peer gate != prompt; missing NOTIFY action->"
"具体user todo未投影,需修复LoopX状态投影."
"DONT_NOTIFY=安静输出。见 `heartbeat_recommendation.agent_must_attempt`/"
"`execution_obligation.must_attempt_work`:true须推进并写回,false才可no-op。"
"Due/peer非用户动作;NOTIFY缺动作→"
"具体user todo未投影,需修复LoopX状态投影;静默时内部修复。"
)
HEARTBEAT_NOTIFICATION_RULE_THIN = (
"`user_channel.notify` controls OUTPUT only: NOTIFY=向用户输出动作; "
"DONT_NOTIFY=安静输出。执行义务看 `agent_must_attempt`/`must_attempt_work`。"
"Due/peer gate != prompt; missing NOTIFY action->具体user todo未投影."
"Due/peer非用户动作;NOTIFY缺动作→"
"具体user todo未投影,需修复LoopX状态投影;静默时内部修复。"
)
HEARTBEAT_VISION_WRITEBACK_RULE_SHORT = (
"writeback: no-change=`surface_only`/no spend; "
Expand Down
Loading