Skip to content

Tools cannot read the memory during a run (STO-E001) — so trigger-started runs cannot carry assembled context #85

Description

@sathish-mg

Summary

A --tool-cmd subprocess cannot read the memory while its own run is executing — not even a pure RECALL. The embedded backend's file lock is exclusive, so any read opens read-write and is refused:

areev: STO-E001: storage error: Locking error: Failed locking file
'data/accounting-dev.db'. File is locked by another process

On its own that is awkward. Combined with the trigger seam shipped in 1.3.0/1.4.0 it becomes structural: a trigger-started run cannot carry any context from the memory it lives in.

Repro (1.4.0)

A workflow node bound to a host tool whose command is:

#!/bin/sh
cat > /dev/null
areev cal 'RECALL facts WHERE namespace = "accounting.dev.vendors" LIMIT 3' \
  --db accounting.db --ns accounting.dev     # -> STO-E001, exit 1
echo '{"ok":true}'

areev run start --workflow <WF> --run-id probe --tool-cmd ./probe.sh → the tool runs, the CAL read is refused.

Why the trigger seam turns this into a blocker

Before triggers, the host started the run, so it could assemble context first and pass it in --input. That is exactly what our accounting agent does today: recall the Skill instructions, the Goal targets, the learned vendor-alias facts and the thread history, then run start --input '{…, "context": …}'.

With areev trigger run, Areev starts the run, and every path to the memory is closed at once:

  1. The host no longer starts the run, so it cannot pre-inject.
  2. The connector cannot read — the evaluator holds the memory while it spawns the connector.
  3. The tools cannot read — the driver holds it for the duration of the run.

So a trigger-started agent run is blind to its own memory: no instructions, no goals, no learned facts, no thread history. For a memory engine, an agent that cannot read the memory at the moment it acts is a sharp edge.

This is not hypothetical — it is why our first-party agent (mindgryd/mg#6) has not migrated its launchd job to areev trigger, despite #36 having shipped exactly the seam it asked for.

Precedent: this was already solved once, for blobs

1.2.1 (#27) added blob get with a deliberately lock-free path, and the reasoning in the changelog applies verbatim here:

blob get deliberately does not open the memory: the embedded backend's file lock is exclusive, so while a run holds a memory even a reader is refused, which put an attachment out of reach of the very --tool-cmd subprocess the run spawned to process it.

Attachments got a door. Grains did not.

Proposals (either alone helps; together they close it)

A. A lock-free / read-only open for reads. SQLite WAL already permits concurrent readers; the refusal comes from opening read-write. A --read-only open (or an automatic downgrade when the statement is provably a read, which CAL already classifies by tier) would let a tool run RECALL/ASSEMBLE/RUN "saved_query" mid-run. Consistency is not a concern a reader here needs — it wants the state as of now, and the run's own writes are journaled anyway.

B. Declared context on the Trigger grain. Let a Trigger name a saved query whose result the evaluator assembles (it already holds the memory) and places into the run input:

areev trigger add --type polling --connector gmail \
  --workflow <WF> --context-query triage_ctx --because ""

The run then starts with {trigger, connector, scope, item, context}. This keeps the "tools never touch the store" property intact and makes the context part of the declaration — auditable and replicated, which is the whole point of the trigger grain.

C. Note the backend divergence. The Postgres backend "admits MULTIPLE CONCURRENT WRITERS per memory" (crates/areev-store/src/pg.rs), so this constraint largely disappears at the medium tier. That means the same plan behaves differently on two supported backends — a tool that reads its memory works on Postgres and fails on Turso. Whatever the fix, the divergence deserves to be stated in docs/run.md, because it silently decides whether an agent design is portable across the tiers.

Impact

Any agent whose tools need to consult the memory they are governed by: retrieval-augmented extraction, alias/rule lookups, thread history, policy checks. Today all of it must be hoisted into the host before run start, which the trigger seam removes as an option.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions