Skip to content

Return a prompt's output and give every run a private store - #15

Merged
vinniefalco merged 4 commits into
cppalliance:masterfrom
vinniefalco:master
Nov 14, 2026
Merged

vinniefalco merged 4 commits into
cppalliance:masterfrom
vinniefalco:master

Conversation

@vinniefalco

@vinniefalco vinniefalco commented Nov 14, 2026 •

Copy link
Copy Markdown
Member

A prompt now returns its output as its return value, and every run has one private store that no caller can seed or read.

What changes

  • A prompt has no output: frontmatter key, and RunReport has no output field. The result is report.result. ErrorCode::NoOutput is gone.
  • Every run has one empty in-memory Store outside the VfsRef, with its own claims ledger. Clones are the same store. Nothing outside the run can put files in it or read them back.
  • Store operations are still Effect::Vfs effects, so a run's records can rebuild its store. No Host policy or observer applies to the store, and tools and the store are disjoint.
  • A prelude's install makes no store call. A store call at a prelude's top level fails the load, and a captured store function works when a block calls it later. ErrorCode::NoStore is gone.
  • answer_vfs in the runner calls perform_vfs_op directly.

Commits

  • Remove the output file from the frontmatter and Harness
  • Fail a prelude that calls the store while it installs
  • Give every run a store of its own outside the filesystem

Plan and findings: plan/2026-11-14-1-private-store.plan.md (see "What the build found").

Checks

fmt, clippy (warnings denied), nextest (3784 passed, 24 skipped), both doc builds, xtask api --check, dylint, cargo test -p build-xtask, node --test tools/docs-claims.mjs, the run-prompt example, and cargo deny check all pass.

Companion changes (not pushed yet)

  • runvil-design: describe the run's own store and the return value as output
  • runvil-docs: teach that a run returns its output and has its own store
  • runvil: name a store operation in the Engine's list of effects

Summary by CodeRabbit

  • New Features
    • Each run has its own initially empty in-memory store, separate from mounted filesystems and tool-call file access.
    • Store operations are recorded as run events and can be replayed to reconstruct stored files.
  • Behavior Changes
    • Prompts return results directly; declared output-file results are no longer included in run reports.
    • Store calls during prelude loading fail without performing the operation. Captured store functions can be used later in a prompt block.
    • Run reports expose the prompt result instead of an output-file result.

A prompt declared a file under `output:`, and the Harness read that path from the store after the run into `RunReport::output`. The key, `FileDecl`, the report field, and `files.rs` are deleted, so the text that a prompt returns is the one result of a run.

- `RunReport` has three fields: `run_id`, `result`, and `unread`. `Harness::run` does not read the store after the run.
- `ErrorCode::NoOutput` had `files.rs` as its one producer. It is deleted with its tag `no_output`, and `ALL` in `error-tests.rs` has 68 codes.
- An `output:` key now fails the parse as an unknown key.
- Both `public-api.txt` listings lose `FileDecl`, `Frontmatter::output`, and `ErrorCode::NoOutput`, and the `runvil` listing loses `RunReport::output`.
- The fixtures that declared `output:` return their text: `SHOUTS`, `REVIEW`, `FILES`, and `GREET` in the `run-prompt` example. Their tests read `report.result`, and `SHOUTS` does not write the store.
- `prepare-files.rs` keeps the two tests of a file that the Host seeds in the store.
- `assert_not_completed`, the five tests of `report_output`, the two frontmatter tests of the key, and `MISSING_OUTPUT` with `extract_declared_output` are removed. No test covers a frontmatter that has an `output:` key.

Plan: /plan/2026-11-14-1-private-store.plan.md
A `store` function ran a direct closure while the Pack preludes installed and yielded only after, so the install of a prelude could change the store with no effect issued. `install_shims` now installs the `store` table of the shim chunk as the global before the preludes. A store call outside a block fails where it yields, as `tools.call` does, so the prelude fails to load and the store is not touched.

- `install_store_table`, its closures, `route_store_to_shims`, `install_store_shims`, the `store_conflict` slot with `take_store_conflict`, and `__impl_store.lua` are deleted. `engine_globals_store.rs` keeps `run_store_op`, the line bounds of the two reads, and the failure messages.
- The section VM holds no access and makes no store view. `inject_values` and `inject_test_values` take no access, `install_engine_globals` takes no `ScopeHandle`, and `SectionVmSetup`, `vm_setup`, and `SectionContext::new` lose `access` and `scope`.
- `SectionContext::new` loses its `too_many_arguments` expectation, and `type_size.rs` loses its entry for `SectionVmSetup`.
- The load failure of a prelude ends with `it must not call tools or the store while loading.`
- A prelude that catches the failure with `pcall` installs. A store function that a prelude captured as it installed runs when a block calls it. `preludes.rs` has a test of each rule, and the test of a conflict from the write of a prelude is removed with the slot.
- A VM without the coroutine shims has no `store` global.
- `drive_block` in the lua test hub runs a block as a coroutine and answers each store request with `run_store_op`. `run_chunk` goes through it, so the tests in `tests/store.rs` take the yield path and assert the code of the store failure itself.
- The lua crate reports no store event. The store event tests move from `store_reports.rs` to `observations-store.rs`, which asserts those events on a run.
- `FailingBackend` is removed from the lua tests, so no lua test covers a store call that its backend fails. `engine_misuse.rs` is removed with its one test, and `a_store_install_without_a_store_names_why_in_its_message` is removed.

Plan: /plan/2026-11-14-1-private-store.plan.md
A run's store was one mount of the `VfsRef` that the caller gave the run, so the caller could fill it, read it, and put a policy on it, and a tool call could reach its files. A store is now a value of its own, `Store` in `runvil-vfs`: an empty set of files in memory under its own claims ledger, which the Engine makes for each run and reaches only through `Store::view`. The `VfsRef` holds the files that the run's tool calls work in, and each store operation stays an `Effect::Vfs`, so the records of a run hold every one.

- `Store::view` joins the scope of the access it gets and records its claims in the ledger of the store. The forks and joins of a run order store operations as they order file operations, and two stores share no path and no claim. Neither `public-api.txt` listing has `Store`.
- `SharedState` holds the `Store` of the run, made with `Store::new()` when the run is built. `dispatch_vfs` is the one place that makes a view, through `ChainState::store()`, so a chain that gets another store needs no other change.
- `VfsRefBuilder::store`, `StoreDecl`, `acquire_store`, `probe_store`, the `store_view` methods of `ScopeHandle` and `Access`, `VfsError::NoStore`, `ErrorCode::NoStore`, and the store probe of `check_start` are deleted. `VfsRef::default()` is one memory mount at `/`.
- Every access is rooted at `/`, so the root of an access and the root parameter of `canonicalize`, `strip_root`, and `relativize_error` are deleted. A boolean `store_view` marks a view.
- The policy and the operation observer of a handle see the file operations of tool calls and never a store operation. `a_handles_policy_and_observer_never_see_a_store_operation` and `a_hosts_policy_and_watcher_never_see_a_store_operation` hold the rule.
- A run sees no file of its handle through `store`, a tool call sees no file of the store, and two runs over one handle each start with an empty store.
- The first step checks the version gate, the arguments, and the requirements. A handle that refuses the root access of the run ends the run after those checks.
- `make_files_error` gives a refusal by the files of the caller the message `file access failed: {cause}`: the root access of the run, the fork for a task, and the fork for a tool call. A store view that the scope refuses keeps `store operation failed: {cause}` from `make_store_error`, which has the text of `store_probe_message`.
- `answer_vfs` calls `perform_vfs_op` with no `catch_unwind`, because the store is memory and no backend of the caller runs there.
- `SharedState` has 15 fields, and its entry in `type_size.rs` records 15.
- `handle/tests/store.rs` has the tests of a store, and `scope_handle-tests.rs` keeps the tests of `spawn`, `join`, `end_access`, and `end`. `a_runs_vfs_records_rebuild_its_store` and `a_runs_store_effect_records_rebuild_its_store` apply the `Vfs` records of a run to an empty memory handle and read back the files of the run.
- The runtime's `TestStore` reads the store of the run through `store_for_test`. In the runner, `stopping_store`, `sending_store`, and `HookedBackend` are deleted, and their tests hook the recorder with `HookedRecorder`, as `stopping_at_each_store_write` does.
- `tool_call_access.rs` and the tests of modes, the watcher, and a caller's edit work on a file that a tool call touches through its access.
- The tests of a store that the caller fills, reads, fails, or mounts at a path are deleted, and so are the tests of a `Vfs` operation's thread and of a backend that panics. `prepare-files.rs` and `temp_root.rs` are removed.
- `store_error_message` keeps its text for failures such as `PermissionDenied`, which a `Store` does not give. No test covers a store view that fails for a cause other than the end of its scope.

Plan: /plan/2026-11-14-1-private-store.plan.md
@coderabbitai

coderabbitai Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

Explain Change →

Caution

Review failed

The pull request is closed.

Walkthrough

The change replaces declared output-file reporting with prompt return values. Each run now owns an empty in-memory store, separate from the filesystem used by tool calls. Lua store operations yield to the executor as effects.

Changes: Run-scoped store and prompt results

Layer / File(s) Summary
Return prompt results and remove output-file reporting
crates/runvil-internal/prompt/*, crates/harness-internal/runner/*, crates/runvil-internal/types/src/error.rs, crates/runvil/public-api.txt, crates/runvil/examples/run-prompt.rs
Prompt frontmatter no longer declares an output file. RunReport returns the run result instead of output-file contents. Output-reporting APIs and the NoOutput error code were removed.
Define the independent store and its views
crates/runvil-internal/vfs/src/*, crates/runvil/public-api.txt
The VFS crate adds Store and store views bound to an access identity and scope. Store mounts, store probes, and NoStore are removed. Store path handling now uses the namespace root.
Own the store per run and dispatch effects
crates/runvil-internal/runtime/src/execute/*, crates/runvil-internal/runtime/src/error.rs
The runtime creates an empty store in shared run state and derives a store view when dispatching a VFS effect. Startup no longer probes for a declared store.
Route Lua store calls through coroutine yields
crates/runvil-internal/lua/src/*, crates/runvil-internal/runtime/src/execute/section_vm.rs
Lua installs store yield shims before Pack preludes. Store calls during prelude loading fail at the yield point; block execution handles store requests.
Update run, tool, and effect coverage
crates/harness-internal/runner/tests/it/*, crates/runvil-internal/runtime/src/execute/tests/*, crates/runvil-engine/tests/suite/*, crates/runvil/tests/suite/*
Tests cover run-store isolation, tool-call filesystem separation, effect ordering and replay, and prompt results returned as text.

Estimated code review effort: 5 (Critical) | ~90 minutes

Sequence Diagram(s)

sequenceDiagram
  participant LuaBlock
  participant Scheduler
  participant Store
  participant Harness
  LuaBlock->>Scheduler: yield store request
  Scheduler->>Store: create store view and dispatch operation
  Store-->>Scheduler: operation result
  Scheduler-->>Harness: VFS effect and answer
  Harness-->>LuaBlock: resume block with answer
Loading
Merge Risk: Minimal · up to 1664e

The change makes prompt output the returned result and gives each run its own in-memory store. No concrete merge-blocking issue was found. Public API removals are intentional and documented.

Pre-merge checks: Passed 4

Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title names two changes: returning a prompt's output as the run result, and giving each run a private store. The changeset matches both. It removes the file-based output declaration and `RunReport…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title names two changes: returning a prompt's output as the run result, and giving each run a private store. The changeset matches both. It removes the file-based output declaration and RunReport::output, adds RunReport::result, and adds a per-run empty in-memory Store separate from the caller's VFS. The title is concise, specific, and written as one sentence, so it covers the main change.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@greptile-apps

greptile-apps Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[High impact] The PR appears safe to merge; no blocking issue was found.

Summary

Prompts return their output through RunReport.result. Each run owns an empty memory store, separate from the files its tools use.

  • Prompts return their text as the run result.
  • Each run keeps its store apart from tool files.
  • Store calls run from prompt blocks, not prelude loading.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Prompt["Prompt block"] -->|"store call"| Effect["Recorded Vfs effect"]
  Effect --> Store["Run's private memory store"]
  Prompt -->|"tool call"| Tool["Pack tool"]
  Tool --> Files["Caller-provided filesystem"]
  Prompt -->|"return"| Result["RunReport.result"]
Loading

Reviews (2) · Last reviewed commit: "Return a test chunk's compile failure" · Reviewed by Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Additional comments: 1

crates/runvil-internal/lua/src/test_vm.rs-199-199: 1

199-199: Minor · Functional Correctness · Quick win

Unverified finding
Verification ran but could not confirm this finding. It is shown for review, not as a verified issue.

Return compilation failures from run_chunk.

If source contains malformed Lua, such as local =, block(source) panics at LuaProgram::compile(...).expect(...). The caller cannot inspect the failure through this helper's Result, unlike other block failures.

Compile with LuaProgram::compile(...)? inside run_chunk. Keep block() for fixtures that must compile.

Review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 12cc8b63-f875-4a2b-a4e7-144633d2bcf1
Commits

Reviewing files that changed from the base of the PR and between 0d93888 and ceb5da4.

Files selected for processing: 133

  • AGENTS.md
  • crates/build-xtask/src/type_size.rs
  • crates/harness-internal/plugin-loader/src/file-tests.rs
  • crates/harness-internal/runner/src/effect_loop.rs
  • crates/harness-internal/runner/src/files.rs
  • crates/harness-internal/runner/src/harness.rs
  • crates/harness-internal/runner/src/lib.rs
  • crates/harness-internal/runner/src/performers.rs
  • crates/harness-internal/runner/src/prepare.rs
  • crates/harness-internal/runner/src/setup.rs
  • crates/harness-internal/runner/tests/it/effect_loop-recorder.rs
  • crates/harness-internal/runner/tests/it/effect_loop-vfs.rs
  • crates/harness-internal/runner/tests/it/effect_loop.rs
  • crates/harness-internal/runner/tests/it/harness-errors.rs
  • crates/harness-internal/runner/tests/it/harness-inbox.rs
  • crates/harness-internal/runner/tests/it/harness-stop-timing.rs
  • crates/harness-internal/runner/tests/it/harness.rs
  • crates/harness-internal/runner/tests/it/prepare-args.rs
  • crates/harness-internal/runner/tests/it/prepare-files.rs
  • crates/harness-internal/runner/tests/it/prepare-ready.rs
  • crates/harness-internal/runner/tests/it/prepare.rs
  • crates/harness-internal/runner/tests/it/support.rs
  • crates/harness-internal/runner/tests/it/tool_context.rs
  • crates/harness-internal/test-plugin/tests/it/run.rs
  • crates/runvil-engine/public-api.txt
  • crates/runvil-engine/src/lib.rs
  • crates/runvil-engine/tests/suite/prepare.rs
  • crates/runvil-engine/tests/suite/prompt.rs
  • crates/runvil-engine/tests/suite/vfs.rs
  • crates/runvil-internal/lua/README.md
  • crates/runvil-internal/lua/benches/surface.rs
  • crates/runvil-internal/lua/src/__impl_coro.lua
  • crates/runvil-internal/lua/src/__impl_store.lua
  • crates/runvil-internal/lua/src/coro.rs
  • crates/runvil-internal/lua/src/engine_globals_store.rs
  • crates/runvil-internal/lua/src/error.rs
  • crates/runvil-internal/lua/src/error_value-tests.rs
  • crates/runvil-internal/lua/src/error_value.rs
  • crates/runvil-internal/lua/src/lib.rs
  • crates/runvil-internal/lua/src/prelude-tests.rs
  • crates/runvil-internal/lua/src/prelude.rs
  • crates/runvil-internal/lua/src/protocol/request.rs
  • crates/runvil-internal/lua/src/test_support.rs
  • crates/runvil-internal/lua/src/test_vm.rs
  • crates/runvil-internal/lua/src/tests-recording.rs
  • crates/runvil-internal/lua/src/tests.rs
  • crates/runvil-internal/lua/src/tests/args.rs
  • crates/runvil-internal/lua/src/tests/engine_misuse.rs
  • crates/runvil-internal/lua/src/tests/logging.rs
  • crates/runvil-internal/lua/src/tests/section_vm.rs
  • crates/runvil-internal/lua/src/tests/store.rs
  • crates/runvil-internal/lua/src/tests/store_errors.rs
  • crates/runvil-internal/lua/src/tests/store_reports.rs
  • crates/runvil-internal/lua/src/tests/sys_and_var.rs
  • crates/runvil-internal/lua/src/vm.rs
  • crates/runvil-internal/lua/src/vm/inject.rs
  • crates/runvil-internal/lua/src/vm/install.rs
  • crates/runvil-internal/prompt/src/frontmatter.rs
  • crates/runvil-internal/prompt/src/lib.rs
  • crates/runvil-internal/prompt/src/tests/frontmatter.rs
  • crates/runvil-internal/runtime/AGENTS.md
  • crates/runvil-internal/runtime/README.md
  • crates/runvil-internal/runtime/src/error.rs
  • crates/runvil-internal/runtime/src/error/tests-chain.rs
  • crates/runvil-internal/runtime/src/execute.rs
  • crates/runvil-internal/runtime/src/execute/context.rs
  • crates/runvil-internal/runtime/src/execute/params.rs
  • crates/runvil-internal/runtime/src/execute/run.rs
  • crates/runvil-internal/runtime/src/execute/run/effect.rs
  • crates/runvil-internal/runtime/src/execute/scheduler.rs
  • crates/runvil-internal/runtime/src/execute/scheduler/chain.rs
  • crates/runvil-internal/runtime/src/execute/scheduler/chain_ops.rs
  • crates/runvil-internal/runtime/src/execute/scheduler/chain_record.rs
  • crates/runvil-internal/runtime/src/execute/scheduler/dispatch.rs
  • crates/runvil-internal/runtime/src/execute/scheduler/drive.rs
  • crates/runvil-internal/runtime/src/execute/scheduler/tasks.rs
  • crates/runvil-internal/runtime/src/execute/scheduler/test_hooks.rs
  • crates/runvil-internal/runtime/src/execute/scheduler/tool_call.rs
  • crates/runvil-internal/runtime/src/execute/scheduler/walk.rs
  • crates/runvil-internal/runtime/src/execute/section_context.rs
  • crates/runvil-internal/runtime/src/execute/section_vm.rs
  • crates/runvil-internal/runtime/src/execute/tests.rs
  • crates/runvil-internal/runtime/src/execute/tests/effects.rs
  • crates/runvil-internal/runtime/src/execute/tests/happens_before-concurrency.rs
  • crates/runvil-internal/runtime/src/execute/tests/happens_before.rs
  • crates/runvil-internal/runtime/src/execute/tests/observations-store.rs
  • crates/runvil-internal/runtime/src/execute/tests/observations.rs
  • crates/runvil-internal/runtime/src/execute/tests/preludes.rs
  • crates/runvil-internal/runtime/src/execute/tests/suite/args_surface-refusals.rs
  • crates/runvil-internal/runtime/src/execute/tests/suite/exec_flow/run_setup.rs
  • crates/runvil-internal/runtime/src/execute/tests/suite/exec_flow/store_failures.rs
  • crates/runvil-internal/runtime/src/execute/tests/suite/prepare.rs
  • crates/runvil-internal/runtime/src/execute/tests/suite/vfs.rs
  • crates/runvil-internal/runtime/src/execute/tests/tool_call_access.rs
  • crates/runvil-internal/runtime/src/execute/tests/tool_scoping.rs
  • crates/runvil-internal/runtime/src/lib.rs
  • crates/runvil-internal/runtime/src/lua.rs
  • crates/runvil-internal/runtime/src/lua/tests.rs
  • crates/runvil-internal/runtime/src/model/tests.rs
  • crates/runvil-internal/runtime/src/test_support.rs
  • crates/runvil-internal/runtime/src/test_support/recording/observation.rs
  • crates/runvil-internal/runtime/src/test_support/scenario.rs
  • crates/runvil-internal/runtime/src/test_support/temp_root.rs
  • crates/runvil-internal/types/src/error-tests.rs
  • crates/runvil-internal/types/src/error.rs
  • crates/runvil-internal/vfs/AGENTS.md
  • crates/runvil-internal/vfs/README.md
  • crates/runvil-internal/vfs/src/error.rs
  • crates/runvil-internal/vfs/src/handle.rs
  • crates/runvil-internal/vfs/src/handle/access.rs
  • crates/runvil-internal/vfs/src/handle/case_fold.rs
  • crates/runvil-internal/vfs/src/handle/forward.rs
  • crates/runvil-internal/vfs/src/handle/operations.rs
  • crates/runvil-internal/vfs/src/handle/scope_handle-tests.rs
  • crates/runvil-internal/vfs/src/handle/scope_handle.rs
  • crates/runvil-internal/vfs/src/handle/store_view.rs
  • crates/runvil-internal/vfs/src/handle/tests.rs
  • crates/runvil-internal/vfs/src/handle/tests/refusals.rs
  • crates/runvil-internal/vfs/src/handle/tests/store.rs
  • crates/runvil-internal/vfs/src/lib.rs
  • crates/runvil-internal/vfs/src/observe.rs
  • crates/runvil-internal/vfs/src/path.rs
  • crates/runvil-internal/vfs/src/real/tests/semantics.rs
  • crates/runvil-internal/vfs/src/router-tests.rs
  • crates/runvil-internal/vfs/src/router.rs
  • crates/runvil-internal/vfs/src/test_support.rs
  • crates/runvil-plugin/src/pack.rs
  • crates/runvil/examples/run-prompt.rs
  • crates/runvil/public-api.txt
  • crates/runvil/src/lib.rs
  • crates/runvil/tests/suite/launch.rs
  • crates/runvil/tests/suite/vfs.rs
  • plan/2026-11-14-1-private-store.plan.md
Files with no reviewable changes: 20

  • crates/harness-internal/plugin-loader/src/file-tests.rs
  • crates/harness-internal/runner/src/files.rs
  • crates/harness-internal/runner/tests/it/prepare-args.rs
  • crates/harness-internal/runner/tests/it/prepare-files.rs
  • crates/harness-internal/runner/tests/it/prepare-ready.rs
  • crates/runvil-engine/public-api.txt
  • crates/runvil-engine/tests/suite/prompt.rs
  • crates/runvil-internal/lua/src/__impl_store.lua
  • crates/runvil-internal/lua/src/error_value-tests.rs
  • crates/runvil-internal/lua/src/tests-recording.rs
  • crates/runvil-internal/lua/src/tests/engine_misuse.rs
  • crates/runvil-internal/lua/src/tests/store_reports.rs
  • crates/runvil-internal/prompt/src/frontmatter.rs
  • crates/runvil-internal/runtime/src/test_support.rs
  • crates/runvil-internal/runtime/src/test_support/recording/observation.rs
  • crates/runvil-internal/runtime/src/test_support/temp_root.rs
  • crates/runvil-internal/types/src/error.rs
  • crates/runvil-internal/vfs/src/error.rs
  • crates/runvil-internal/vfs/src/real/tests/semantics.rs
  • crates/runvil/public-api.txt

Included review availability: This review used your included allowance. 4 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 5 reviews per hour.

`run_chunk` in the Lua test VM compiled its source with `block`, which panics on malformed Lua. It now compiles with `LuaProgram::compile` and returns the failure through its `Result`, as every other block failure is returned.

- `block` is unchanged, for fixtures that must compile.
- A new test in `tests/store.rs` pins that `local =` gives an error and not a panic.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant