When a tool returns more than 4 KB, the CLI stores the payload locally and hands back a handle plus a shape preview, rather than printing everything. For an agent this is the difference between spending a few hundred tokens and blowing the context window on one call.
You now know the response is 2,841 items and what one looks like - without having read any of it.
Pull only what you need
--select applied to a list maps over it, so items.email returns every email rather than erroring. A path that doesn’t exist yields null instead of throwing - safe to probe.
Manage the sandbox
Stored results live under $XDG_CACHE_HOME/engini/results/ (%APPDATA% on Windows), auto-pruned to the 20 most recent and anything older than 24h.
Handles are short-lived and local. They don’t survive a pruning, another machine, or a CI runner that gets torn down. Drill in during the same session; if you need the data later, write it to a file with --full.
Bypassing it
Use these in CI, where you want the whole thing in a file. Keep the default when an agent is driving.
Why this matters for agents
The wrong pattern is a tool call returning 2,841 contacts straight into the model’s context. The right one is three cheap steps:
The model sees a summary, then requests precisely the slice it needs. Pair it with --llm openai|anthropic, which formats a result as that vendor’s tool-result message so it can be handed straight back into the conversation:
In the SDKs
There’s no handle mechanism in the SDKs - you already hold the object in memory, so slice it in your own language. Handles exist because the CLI’s boundary is a pipe, where “hold it and slice it later” isn’t otherwise possible.