Repository navigation
feat(kernelforge): plans open with a Summary line; implementers keep <plan>.reasoning.md - #1949
amd-ama10002-2 wants to merge 3 commits into
Conversation
Code metrics gate: PASSEDJudged: the 22 files this change touches. Files it does not touch never fail it; anything found there is listed under Outside this change for information.
Module length warning: over 800 lines, within the 1200-line failure limit (not failing): 1
Already over at the base (backlog, not this change's): 8
97 findings in files this change does not touchOutside this change (informational): 97
...and 72 more; the job log lists every row.
Thresholds and sources: |
There was a problem hiding this comment.
🟡 Changes recommended
Writing a reasoning log in a non-ignored workspace can trigger rejection and rollback of valid kernel edits.
1 open issue
What changed in this PR
This PR prepares KernelForge artifacts for later Experience KB export by adding plan summaries and persistent implementer work logs.
Changes:
- Requests
Summary:lines in plans and implementer logs. - Routes logs beside their plans and preserves them during replanning.
- Extracts prompt definitions and consolidates optional callback arguments and gate scoring.
| File | Description |
|---|---|
| src/kernelforge/tests/test_summary_line.py | Tests summary parsing and log contracts. |
| src/kernelforge/tests/test_loop_runner.py | Tests log paths and scoring delivery. |
| src/kernelforge/tests/test_lane_session_guarantees.py | Tests lane permissions and gate scoring. |
| src/kernelforge/tests/test_lane_plan_persistence.py | Tests log preservation during replanning. |
| src/kernelforge/tests/test_lane_aiter_cache.py | Updates callback signature. |
| src/kernelforge/tests/test_forge_orchestration.py | Tests planner summary instructions. |
| src/kernelforge/tests/test_fanout.py | Updates callback signature. |
| src/kernelforge/tests/test_codex_backend.py | Tests implementer log configuration. |
| src/kernelforge/orchestrator/summary_line.py | Defines summary and log contracts. |
| src/kernelforge/orchestrator/plan_prompts.py | Houses summary-aware planner prompts. |
| src/kernelforge/orchestrator/orchestration.py | Uses extracted planner prompts. |
| src/kernelforge/orchestrator/agent.py | Configures logs and consolidated scoring. |
| src/kernelforge/loop/scoring.py | Introduces GateScoring. |
| src/kernelforge/loop/runner.py | Supplies log paths and preserves logs. |
| src/kernelforge/loop/agent_extras.py | Filters declared callback arguments. |
| src/kernelforge/cli/lanes.py | Forwards lane log paths. |
| scripts/code_metrics_baseline.txt | Updates reduced code metrics. |
| docs/kernelforge/how-to/autonomous-loop.md | Documents summaries and persistent logs. |
Review effort: Balanced
|
/review (Oh, I guess this doesn't do anything? 😅) |
|
Automated review started for head 9c0569e. Progress: https://github.com/AMD-AGI/Hyperloom/actions/runs/38980746400 |
|
Automated review: no verdict applied -- the review job ended with result 'failure'. Comment |
|
This is the result of running the agent review-pr skill locally (the /review skill I think) PR #1949 -- feat(kernelforge): plans open with a Summary line; implementers keep
|
|
This is the result of running the agent review-pr skill locally (the /review skill I think) PR #1949 -- feat(kernelforge): plans open with a Summary line; implementers keep
|
os.walk without onerror, and Path.rglob, return nothing for a directory the user cannot list. A run copied out of a container, where Claude Code keeps each project's transcripts in a directory only root can list and KernelForge creates its best bundles with mkdtemp, therefore lost those files while the export still exited 0. inventory now raises the listing error, which export-runs reports with its fix-ownership hint, and _files_in lists through inventory instead of a second walker. The declaration and both reference pages also said that a plain run made before #1949 falls back to its Implementer's transcript. A plain session's transcript is linked only by the reasoning log its first prompt names, so such a run gives the rationale KernelForge recorded and its lanes give no reasoning; the text now says so. The reasoning_file description changes, and with it the declaration's schema_ref. Co-authored-by: Cursor <cursoragent@cursor.com>
…soning The mapping's no-reasoning skip reason said the logs hold no Claude Code transcript of the agent and asked for logs that record its reasoning. A lane of a plain run made before #1949 can have its transcript in the logs, but nothing links it, so every such lane got a wrong diagnosis and a remedy that cannot help, contradicting the collection reference. The reason now says no transcript is linked, and that such a lane has no reasoning, like a merge. Co-authored-by: Cursor <cursoragent@cursor.com>
Hyperloom Forge E2E — ✅ Succeeded
|
….reasoning.md
An Experience built from a KernelForge run needs a short statement of the
plan a candidate was built from and the implementer's own account of its
change. The logs held neither: the nearest text was the first sentences of
a long plan and the session's opening messages, which are tool narration
("I'll start by reading the required optimization plan...").
The planner's synthesis, lane-synthesis and revision prompts now ask for a
first line, before any heading, of `Summary:` and one to three plain
sentences: the problem the plan addresses and its goal. The implementer's
system prompts ask it to keep a work record at the path its invocation
names, opening with its own `Summary:` line (the problem and the change it
makes), brought up to date before the session ends.
The runner names that path for every session that executes a plan:
<plan>.reasoning.md beside the plan in forge_experiments/orchestration/
iter_NNN/, which the workspace guard ignores, the candidate archive does
not replace, and a lane's temporary workspace copy does not hold. A lane
session gets the plan's directory as an additional directory, so its log
outlives the copy. The stale-lane-plan cleanup now matches only
lane_NNN.md: re-planning an iteration still removes the lane plans the new
round no longer has, and no longer deletes the reasoning logs lanes wrote.
kernelforge.orchestrator.summary_line owns the format: both prompt rules,
the invocation section that names the log, the parsers that read the
summary and that section back, and where the log lives. The reasoning-log
rule is worded as an engineering record of what was examined, changed and
measured; a wording that asked for the reasoning itself and the model's
hypotheses tripped Claude-Opus-5.5's [reasoning_extraction] safeguard on
every writable implementer session.
Refactors with nothing observable: the planner system prompts move to
plan_prompts.py, the two hygiene rules and the session deadline section
become module-level names in agent.py, and the runner's signature check
for optional agent_fn arguments becomes loop.agent_extras.declared_extras.
The code-metrics baseline is tightened for the three units that shrank.
Observable effect: planner plans in forge_experiments/orchestration/
iter_NNN/ open with `Summary:` and one to three sentences, and every
implementer session that executes a plan leaves <plan>.reasoning.md beside
it, opening with its own `Summary:` line. Nothing in KernelForge parses a
plan's first line, so plans are otherwise used as before.
Co-authored-by: Cursor <cursoragent@cursor.com>
…s one GateScoring The runner handed an injected Implementer callback the pristine per-case times and the current best mean case speedup as two optional arguments. They travel together, into the in-session gate and into the scoring section of its system prompt, and with the reasoning log they made make_agent_fn's agent_fn a six-parameter function, one over the code-metrics limit. kernelforge.loop.scoring.GateScoring carries both as one frozen dataclass. The runner passes it as the optional gate_scoring argument through declared_extras, and agent_fn hands it to the gate builder and to the scoring section. agent_fn is back to five parameters and _build_insession_gate takes fifteen; the code-metrics baseline is tightened for both. Refactor with nothing observable: the gate scores against the same values and the session is told the same scoring state. Two tests pin the handoff: the runner hands a session its gate's scoring, and the canonical session's gate and prompt carry what it was handed. Co-authored-by: Cursor <cursoragent@cursor.com>
…orkspace
An implementer session now keeps its reasoning log under
forge_experiments/orchestration/iter_NNN/. In a workspace whose ignore
rules do not cover forge_experiments/, that log is a new untracked file,
so WorkspaceGuard.verify() rejected the session ("new non-ignored files
are unsupported") and rolled back its kernel edits along with the log.
The example script's .gitignore and the Hyperloom controller both hide
the folder, which is why no run under them showed it.
forge-loop now hides its own output folder the way the controller
already did: IterationLoop._run_impl writes forge_experiments/.gitignore
holding `*` before any session runs, so git never lists anything the
loop or a session writes there. The controller's private helper moves to
llm.workspace_policy.hide_forge_loop_output and both callers share it.
The guard is unchanged: a new file anywhere else in the workspace is
still rejected and rolled back.
Observable effect: every forge-loop workspace gets
forge_experiments/.gitignore (`*`), and a workspace that did not ignore
that folder no longer has an implementer session rejected, and its
kernel edits rolled back, when the session writes its reasoning log.
Co-authored-by: Cursor <cursoragent@cursor.com>
d32992a to
76236b0
Compare
PR #1949 -- feat(kernelforge): plans open with a Summary line; implementers keep
|
|
Superseded by #2037: the four stacked PRs were combined into one PR at the reviewer's request. |

Motivation
We are building knowledge-base support for KernelForge runs (kernel writing): turning KernelForge's raw logs into structured Experiences in Hyperloom's Experience KB. We are also changing the logs KernelForge writes so they carry what the KB extracts: planner plans open with a
Summary:line, and implementers keep a<plan>.reasoning.mdwork log that opens the same way. This PR is that change to the logs. Later the KB service will extract these logs and their summaries into a structured "Experience" dataclass (Please see the follow-up PRs)Stack: merge in this order, one at a time. Each PR targets the branch of the PR above it in this list.
export-runsand thekernelforge-v1mapping, for plain forge-loop runsexport-runsreads AgentKernelArena driver.log sessionsexport-runsreads AgentKernelArena campaign logsWhat changes
forge_experiments/orchestration/iter_NNN/(synthesis, lane synthesis, revision) open withSummary:and one to three sentences: the problem the plan addresses and its goal. Nothing in KernelForge reads that line, so plans are otherwise used as before.<plan>.reasoning.mdbeside it (optimization_plan.reasoning.md,lane_002.reasoning.md, ...): a record of what it examined, changed and measured, opening with its ownSummary:line. A lane is given the plan's directory, so its log outlives the lane's workspace copy.lane_NNN.md.forge_experiments/.gitignoreholding*when it starts. A workspace that did not ignoreforge_experiments/no longer has an implementer session rejected, and its kernel edits rolled back, when the session writes its reasoning log there; a new file anywhere else in the workspace is still rejected.plan_prompts.py; the two hygiene rules and the session-deadline section become module-level names inagent.py; the runner's optional-argument check becomesloop.agent_extras.declared_extras; the in-session gate's pristine per-case times and current best reachagent_fnas oneGateScoring; the controller's private output-folder helper becomesllm.workspace_policy.hide_forge_loop_output, shared with the loop.Known limitations
AgentRunSpec.additional_directories.test_summary_line.py; the planner, runner, lane, Codex backend, workspace-guard and workspace-policy tests are extended.agent.pygrows from 965 to 981 lines (under the 1200-line limit) for the reasoning-log wiring,orchestration.pyshrinks from 1831 to 1771, andrunner.pystays at 6448; no edited function grew past a trigger.