I also checked how ace works, and it looks good for the purpose it is aimed. However, I couldn’t find any tests where setContext is used, especially considering that it is a shared context for every policy attached to the engine
It seems that if 3 or more policies share the same context, decoding it can become a mess (due to the lack of structure) because the context has to contain the payload for each of them. Also this would require the developer to create ad hoc methods such as setContextA, setContextB, setContextC, …, setContextX in the contract that inherits from PolicyProtected. I even ended up creating an issue in the Chainlink repository: https://github.com/smartcontractkit/chainlink-ace/issues/20
ERC-8006 doesn’t directly solve this problem because, as I mentioned, it focuses on the artifact interface rather than the Policy Handler interface.
However, the reference implementation of the Policy Handler uses a very similar approach. In this case, the runtime-supplied variables, and the way they are packed, are the closest equivalent to what setContext does. The number of artifacts that require the context doesn’t matter because each artifact has its own isolated context. I would probably highlight this in the Policy Handler ERC. This is a
That distinction is a clean one, and you’re right, that’s a genuinely different mechanism, not a stricter policy variant. I hadn’t separated those two clearly until you named it that way.
I’d be glad to prototype this. Before I dive in - is /review something with an existing API or SDK I could actually call, or is this still conceptual on your side too?
If it’s live, I could wire a call to it in front of my policy_engine.py fairly quickly and see what a combined Intent → your verdict → my policy check → Proof flow actually looks like end to end, using the same testnet setup I’ve already got running. One thing I’d want to understand first: what makes the verdict independent in practice - different model, different data access, a separate team or system running it? That seems like the part that decides whether this catches something a policy check structurally can’t see, versus a second opinion from a similar vantage point.
If it’s not live yet, happy to sketch the schema for the verdict object first (approve/deny/concerns + confidence + signature, sitting alongside my existing proof.schema.json) so we’re both working from the same shape before either of us builds against it.
@Anandi It’s live, not conceptual. POST /review at api.babyblueviper.com, takes {"artifact": "<your proposed action/diff/plan>"}, returns a signed verdict — approve / reject / approve_with_concerns, a confidence score, and a list of any issues found — sealed with a schnorr signature you (or anyone) can check independently via /verify-proof without trusting our word for it. Three payment rails (Lightning, x402/USDC, API-key Bearer), so wiring it in front of policy_engine.py would be a real call, not a mockup.
On independence — the honest answer, since that’s the part that actually decides whether this is worth building against: it’s a completely separate system that never sees your policy.json or its pass/fail signal. It evaluates the proposed artifact fresh, on its own, with no access to your reasoning trace or your engine’s internal state. That’s what makes it different from a second policy check, even a stricter one — two policy engines reasoning over the same declared intent the same way can still share the exact same blind spot. Ours doesn’t share that vantage point at all: different code path, no dependency on whether your own check already said yes, nothing inherited from how the intent was originally framed.
Genuinely curious to see the combined Intent → verdict → policy check → Proof flow if you build it against your existing testnet setup — happy to help debug the wiring if anything’s unclear once you’re actually calling it.
Circling back after a few days – did you get a chance to try wiring /review into policy.json, or has something else come up? No pressure either way, just wanted to make sure the debug-help offer above didn’t get buried. If you’re mid-build and hit friction, happy to jump on whatever’s blocking.
No rush at all – real integration work takes real time, and “working on it” after a week is exactly what I’d expect for wiring a live external call into an existing engine, not a red flag. Ping any time you hit friction or want a second pair of eyes on the wiring (auth, response shape, whatever) – happy to jump on it live rather than over a thread. Looking forward to seeing what the combined Intent → verdict → policy check → Proof flow actually looks like once it’s running end to end.
My thoughts were actually similar, but with a slightly different goal. The artifactMetadata method could serve as a source of metadata (including the URI), providing a way to inspect and verify that the artifact being used is actually what it is, and is exactly what it claims to be. No successful verification no usage.
This is important because artifacts are the building blocks of a policy, and a policy is only as reliable as the artifacts it’s built from.
The goal is to help developers ideally build a runtime onchain verification flow (e.g., validating that artifacts are pulled from a registry of trusted, public, audited artifacts).
“No successful verification, no usage” for the artifact itself is the right gate, and it’s a different question from the one we build for — worth naming explicitly since the two compose cleanly rather than overlap.
artifactMetadata/artifactURI answers: is this artifact actually what it claims to be, sourced from where it claims (a registry check on the building block). What it can’t answer: given a genuinely verified, trusted artifact, is this specific use of it, right now, in this context still sound? A correctly-verified, unmodified artifact can still be invoked with the wrong parameters, at the wrong time, against the wrong target — the artifact passing provenance doesn’t mean the action built from it should proceed.
That’s the seam a signed pre-action verdict sits in: artifact integrity gates whether the building block is trustworthy at all; a verdict over the actual composed action gates whether this specific use is. Neither substitutes for the other — a policy built from verified-but-misused artifacts fails just as hard as one built from unverified ones.
Your assumption is correct – the gas usage is higher.
Each transaction becomes more expensive. Based on my measurements, a simple policy consisting of three artifacts implementing an authorization check adds roughly **150k gas** of overhead for the policy evaluation compared to implementing the same authorization as require(someFunctionCheckAuthorization(params), “not authorized”);
This is the cost exchange for the flexibility, upgradability, and composability that this standard provides.
With the current gas price of 0.167 gwei and the ETH price as of 2026-08-06, that translates to an additional cost of approximately $0.07 per transaction.
However, as authorization logic becomes more complex and requires more artifacts, someFunctionCheckAuthorization will also consume more gas. I can imagine cases where a bloated authorization function ends up consuming a similar amount of gas as graph-based policy split into artifacts.
Also, these measurements were taken using the reference, non-optimized implementation, where everything is written for clarity and to demonstrate the standard rather than maximize efficiency. A significantly more gas-efficient implementation is definitely possible.
So my recommendation would be:
Use a simple require(…) check when the contract is upgradeable and the authorization logic is simple enough to fit in a single function
Use ERC-8006 when the contract itself is not upgradeable, or when the authorization policy is complex and composed of many independent artifacts, or gas difference is an acceptable cost for the qualities this standard provides
I’m currently working on a gas-optimized implementation (will share it with you via DM)