Key Takeaways
- Dogwood adds temporal logic to Cedar but inherits concurrency correctness traps
- A single word — "request" vs "response" — separates a sound rate limit from a broken one
- AWS admits temporal evaluation needs stateful tracking with unbounded latency
- The real problem isn't language expressiveness; it's that agents execute in parallel
AWS open-sourced Dogwood last week. The headline is that Cedar — the stateless policy language AWS contributed to the CNCF — can now govern sequences. The fine print is that the same concurrency bugs that plague distributed systems just moved into the policy layer.
Cedar was deliberate in its limitation. One request, one decision, no memory. Feed it the same input twice and you get the same output. That determinism made audit trivial and automated reasoning tractable. It also meant Cedar could fence off a single action and nothing more. Approval before action, running totals, stop contacting external parties after touching confidential data — the constraints teams actually care about — live in the sequence, not the snapshot.
Dogwood adds a second clause type. Where a Cedar condition sits in `when`, a temporal condition sits in `when temporal` and reads the agent's event history. Events correspond to tool call requests and their outcomes, carrying input arguments and requesting principal. The action schema comes from the agent's MCP tool manifest, one action per tool, which Dogwood generates directly. Under the hood, a temporal condition translates into a Cedar context field the interpreter fills from event history before Cedar makes the decision.
Four operators cover the common shapes, all defined as standard-library macros over a core Metric First-Order Temporal Logic subset rather than as language primitives: `formerly` for whether something happened in a window, `count_within` for how many times, `count_distinct_within` for how many different values, and `sum_within` for a running total. A `bind` operator names an aggregate so the current request can be compared against it. The macro approach keeps the core small. It also means every temporal query reduces to a Cedar context lookup — stateful by another name.
The most instructive part of the announcement is a correctness trap platform teams will recognize. AWS walks the trace: three concurrent $2,000 transfers arrive before any settles. A policy summing response events sees nothing in flight and allows all three past a $5,000 cap. The same policy summing request events denies the third. One word separates the two policies.
That asynchrony is not incidental. Agents issue parallel tool calls. In multi-agent settings the interleaving compounds. A policy that reads correctly in sequence can fail under concurrency, which is a familiar distributed systems problem arriving somewhere new. The Dogwood documentation treats this as a modeling choice — pick the right event type — but the example reveals something deeper: the policy author must reason about the runtime's concurrency semantics to write a correct rule. The language does not enforce that reasoning.
AWS is direct about the costs. Temporal evaluation requires stateful tracking of events, and evaluation time can depend on the length of the history window. The interpreter must materialize the relevant slice of the log, compute aggregates, then hand the context to Cedar. For a high-throughput agent that means either bounded windows or unbounded latency. The sandbox project status at the CNCF signals this is early. AgentCore Policy supports Dogwood today, but the control plane runs outside the model — the model proposes, the policy engine disposes, the model never touches enforcement. That architecture is sound. It also means the policy engine becomes a stateful hot path.
The macros themselves are sensible. `sum_within` with a `bind` gives you a running budget check. `count_distinct_within` gives you a distinct-counterparty limit. `formerly` gives you a prerequisite gate. But each macro expands to a temporal logic formula that the interpreter must evaluate over the event log. The translation is mechanical. The performance characteristics are not.
What Dogwood does not solve: the fundamental tension between expressive temporal policies and the determinism Cedar was built to guarantee. A temporal condition that reads `count_within` of the last five minutes is deterministic only if the event log is totally ordered and completely visible. In a multi-agent system with partial ordering and network partitions, the same policy can yield different decisions depending on which events have arrived at the evaluator. Cedar's single-request determinism came from statelessness. Dogwood buys expressiveness by surrendering it.
The Apache 2.0 license and CNCF sandbox status suggest AWS wants this to become the common substrate for agent governance. That ambition is plausible. The alternative is every framework inventing its own temporal dialect, each with its own concurrency bugs. A shared language at least concentrates the debugging.
But the debugging is the work. The rate-limit example is not a corner case — it is the canonical case. Any policy that constrains a sequence of value-carrying actions under concurrency faces the same choice: count requests and over-reject, or count responses and under-reject. Dogwood gives you the vocabulary to write either. It does not tell you which is correct for your consistency model. That answer lives in the runtime, not the language.
Teams adopting Dogwood should treat the temporal clause as a distributed systems interface, not a policy convenience. The macros are macros. The state is real. The latency is variable. The correctness depends on event ordering guarantees the language does not provide. Cedar made the easy thing — single-action fences — formally tractable. Dogwood makes the hard thing — sequence governance — expressible. Whether it makes it correct is still on you.