Dogwood is a governance language designed for AI agents and their tools. It supports Cedar policies and adds temporal conditions (since, formerly, once, aggregations) to look back over an agent's recent events.
> /plugin marketplace add dogwood-policy/dogwood> /plugin install dogwood@dogwood
What's inside
Dogwood is a governance language designed for AI agents and their tools. It
supports Cedar policies and adds temporal
conditions (since, formerly, once, aggregations) to look back over an
agent's recent events.
permit(principal, action, resource)
when { context.input.amount < 1000 }
when formerly within 1h {
Action::"Approve"::request{ approver: context.input.approver }
};
This repository contains a reference interpreter for the language for the purpose of understanding the semantics of the language, with simple examples of the kinds of policies Dogwood supports. This reference interpreter is NOT intended for production use. Please see the end of this document for a list of important limitations of the interpreter.
๐ Read the full documentation โ
permit/forbid with when/unlesscontext.* slots filled at runtime| Path | Description |
|---|---|
dogwood-language/ | The core Rust library โ parser, interpreter, lowering, and API |
dogwood-docs/guide/ | The language guide (syntax, schemas, temporal expressions, providers, formal spec) |
dogwood-cli/ | The dogwood CLI (validate, lower, replay) |
dogwood-docs/examples/ | Runnable example policies with traces and expected output |
dogwood-language/configuration/ | Starter action schemas and event schemas |
# Validate a policy against its schemas:
dogwood validate policy.dw --policy-schema schema.cedarschema
# Lower to Cedar and see the output:
dogwood lower policy.dw --policy-schema schema.cedarschema --emit both
# Replay a trace and see verdicts:
dogwood replay policy.dw --policy-schema schema.cedarschema --trace events.log
The read_after_login example
permits a Read only if the same user logged in within the last hour:
// policy.dw
@id("read_after_login")
permit (
principal,
action == Drupe::Action::"Read",
resource
)
when temporal {
formerly within 1h Drupe::Action::"Login"::request{ input.user: context.input.user }
};
Replay it against a trace of three events (login at t=0, read at t=10s, read at t=2h):
$ dogwood replay dogwood-docs/examples/read_after_login/policy.dw \
--policy-schema dogwood-docs/examples/read_after_login/schema.cedarschema \
--trace dogwood-docs/examples/read_after_login/trace.log
@0 (time point 0): DENY
@10 (time point 1): ALLOW [rules: 0]
@7200 (time point 2): DENY
The first event is the login itself (no read requested) โ DENY. Ten seconds later Alice reads โ ALLOW (she logged in recently). Two hours later she tries again โ DENY (the login has expired from the 1-hour window).
You can also validate and lower to Cedar:
$ dogwood validate dogwood-docs/examples/read_after_login/policy.dw \
--policy-schema dogwood-docs/examples/read_after_login/schema.cedarschema
OK: validation passed with no errors or warnings.
$ dogwood lower dogwood-docs/examples/read_after_login/policy.dw \
--policy-schema dogwood-docs/examples/read_after_login/schema.cedarschema \
--emit cedar-policies
@id("read_after_login")
permit(principal, action == Drupe::Action::"Read", resource) when { context.policy_0__temporal_0 };
The lowered Cedar replaces the temporal condition with a context.* slot that
Dogwood fills at runtime from the event history.
See the Getting Started guide for
full setup instructions and more examples in
dogwood-docs/examples/.
Add the crate to your Cargo.toml:
[dependencies]
dogwood-language = { git = "https://github.com/dogwood-policy/dogwood.git" }
See the library README for the API overview and the API and Workflow guide for detailed usage.
This repo ships agent skills that let AI coding assistants author Dogwood policies from natural-language requirements. See AGENTS-README.md for setup across Claude Code, Codex CLI, Cursor, Copilot, and others.
As mentioned above, the reference interpreter provided here is NOT intended to be used directly as an authorization engine for enforcing Dogwood policies. The purpose is to provide a way to test and evaluate the semantics of Dogwood policies.
A production-ready authorization engine needs to deal with several concerns not addressed by the reference interpreter, including but not limited to:
Event timestamp integrity. The interpreter accepts timestamps as provided and does not validate them. Production systems should use timestamps provided by a trusted time source or validate them before ingestion.
Event authentication. The reference interpreter does not provide any kind of authentication on events. A production implementation should bind the authenticated caller identity as the principal before submitting events to an engine.
Event field consistency. Fields needed by both temporal predicates
AND Cedar conditions must be supplied to both the logged bag
(.field()) and the request_context bag (.request_context()).
Supplying only one silently weakens either temporal or Cedar checks.
Action naming consistency. Events must use the same qualified action
format as the policies (e.g., "{ServiceName}::Action::Transfer" not just
"Transfer"). A mismatch causes temporal predicates to silently not
match while Cedar may still authorize the action.
Trace management. The built-in InMemoryTemporalEngine has no eviction or
size cap. Production deployments handling sustained event volume should
consider strategies for bounding and managing store size. Additionally, because
the reference interpreter is purely in memory, its trace is lost after
crash/restart. A production deployment ought to manage traces in a durable or
fault-tolerant way. Keep in mind that depending on the nature of your policies,
requests/events may contain sensitive data, so some method of protecting and
purging that data ought to be used.
The net feature. When enabled, provider scripts can make outbound
HTTP requests via http_get. This function performs NO host or IP
validation โ it will connect to any address the URL specifies, including
internal/private endpoints (169.254.169.254, 127.0.0.1, RFC-1918).
Never construct the URL authority from untrusted event fields. See the
provider guide for the safe pattern.
Policy validation. Always run Validator::validate() on lowered policies
before authorizing. Skipping validation may allow policies with degenerate
windows, unresolved references, type mismatches etc. that behave unexpectedly
at runtime.
Audit logging. Dogwood returns decisions but does not log them. A
production implementation should use some form of logging around
is_authorized() for compliance and forensics.
Multi-tenancy. By default, an authorizer instance monitors one event
history, with no isolation or partitioning between principals. The pin
feature in the interpreter implements a rewriting pass that causes policies to
be interpreted as if they were partitioned along the pinned key fields.
However, this does not mean that an evaluation engine necessarily stores the
event history in a partitioned way. A production deployment must consider and
implement the appropriate level of isolation for their needs, and separate
authorizer instances and event storage mechanisms may be warranted.
Rhai script sandboxing. Provider scripts run in Rhai's embedded
interpreter with no CPU/memory limits configured by default. A malicious or
buggy provider script could infinite-loop or allocate unbounded memory,
starving the authorizer. Production deployments should configure Rhai's
max_operations / max_call_levels limits or run providers with a timeout.
Error message information leakage. Error messages from the compiler/validator include policy content, field names, and type details. In a multi-tenant deployment where policies are authored by different parties, returning raw error details to one tenant could reveal another tenant's policy structure if policies are co-loaded. Production systems should sanitize or gate error output appropriately.
See CONTRIBUTING.md.
See SECURITY.md.
This project is licensed under the Apache-2.0 License. See LICENSE.
.claude/
.claude-plugin/
marketplace.json
plugin.json
skills/
authoring-action-schema/
SKILL.md
authoring-service-schema/
SKILL.md
autoformalize-policies/
SKILL.md
dogwood/
SKILL.md
.gitattributes
.github/
codeql/
codeql-config.yml
workflows/
ci.yml
deploy-docs.yml
.gitignore
AGENTS-README.md
AGENTS.md
book.toml
Cargo.toml
CLAUDE.md
CODE_OF_CONDUCT.md
CONTRIBUTING.md
dogwood-cli/
Cargo.toml
src/
error.rs
main.rs
ops.rs
render.rs
dogwood-docs/
Cargo.toml
examples/
access_not_revoked_since_grant/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
alert_exactly_three_transfers/
events.dwschema
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
alert_heartbeat_and_login_rate/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
alert_login_and_big_transfer/
policy.dw
README.md
schema.cedarschema
alert_login_current_tp/
policy.dw
README.md
schema.cedarschema
alert_login_in_last_hour/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
alert_pending_transfers/
policy.dw
README.md
schema.cedarschema
alert_same_principal_login_transfer/
policy.dw
README.md
schema.cedarschema
alert_same_user_login_and_transfer/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
alert_some_login/
events.dwschema
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
alert_total_transfer_over_200/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
allow_anything/
policy.dw
README.md
schema.cedarschema
approve_has_output_guard/
policy.dw
README.md
schema.cedarschema
call_cedar_macro_as_argument/
macros.dw
policy.dw
README.md
schema.cedarschema
call_cedar_macro_is_small/
macros.dw
policy.dw
README.md
schema.cedarschema
call_cedar_macro_with_temporal_leaf/
expected.out
macros.dw
policy.dw
README.md
schema.cedarschema
trace.log
call_cedar_macros_composed/
macros.dw
policy.dw
README.md
schema.cedarschema
call_temporal_aggregation_macro_count/
expected.out
macros.dw
policy.dw
README.md
schema.cedarschema
trace.log
call_temporal_condition_macro_once/
expected.out
macros.dw
policy.dw
README.md
schema.cedarschema
trace.log
call_temporal_condition_macros_composed/
expected.out
macros.dw
policy.dw
README.md
schema.cedarschema
trace.log
cedar_eligible_not_blocked/
policy.dw
README.md
schema.cedarschema
cedar_is_small_threshold/
policy.dw
README.md
schema.cedarschema
cedar_macro_plus_temporal_leaf/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
cedar_semver_gt/
policy.dw
README.md
schema.cedarschema
cedar_starts_with_f_like/
policy.dw
README.md
schema.cedarschema
cedar_within_cap_if_else/
policy.dw
README.md
schema.cedarschema
cond_is_oauth_in_team/
policy.dw
README.md
schema.cedarschema
deny_overrides_sell_not_amzn/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
forbid_large_except_amzn/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
forbid_read_transfers_over_1000/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
get_amzn_stock_info/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
heartbeat_scope_alias/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
login_attempt_custom_kind/
event.dwschema
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
macro_library_once_is_small/
expected.out
macros.dw
policy.dw
README.md
schema.cedarschema
trace.log
max_window_raised/
event.dwschema
policy.dw
README.md
schema.cedarschema
permit_read_anyone/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
principal_is_oauth/
policy.dw
README.md
schema.cedarschema
provider_allowed_or_short/
allowed.rhai
expected.out
length.rhai
policy.dw
providers.json
README.md
schema.cedarschema
trace.log
provider_digitcount_forbid/
digits.rhai
expected.out
policy.dw
providers.json
README.md
schema.cedarschema
trace.log
provider_digitcount_operator_ge/
digits.rhai
expected.out
policy.dw
providers.json
README.md
schema.cedarschema
trace.log
provider_filter_set_index_decimal/
expected.out
filter.rhai
policy.dw
providers.json
README.md
schema.cedarschema
trace.log
provider_int_arithmetic_trusted/
digits.rhai
expected.out
policy.dw
providers.json
README.md
schema.cedarschema
trace.log
provider_matches_and_not_blocked/
blocked.rhai
expected.out
matches.rhai
policy.dw
providers.json
README.md
schema.cedarschema
trace.log
provider_principal_id_allowlist/
allowed.rhai
expected.out
policy.dw
providers.json
README.md
schema.cedarschema
trace.log
provider_regex_analyze_fields/
analyze.rhai
expected.out
policy.dw
providers.json
README.md
schema.cedarschema
trace.log
provider_regex_matches_uppercase/
expected.out
matches.rhai
policy.dw
providers.json
README.md
schema.cedarschema
trace.log
provider_risk_decimal_method/
expected.out
policy.dw
providers.json
README.md
risk.rhai
schema.cedarschema
trace.log
read_after_login/
read_after_login_success/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
read_heartbeat_since_login_30s/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
read_login_not_logout/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
read_prev_compute_open_session/
policy.dw
README.md
schema.cedarschema
read_prev_login/
read_prev_login_success/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
read_since_login/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
sell_after_2024_datetime/
policy.dw
README.md
schema.cedarschema
sell_after_approval_valid_ticker/
expected.out
matches.rhai
policy.dw
providers.json
README.md
schema.cedarschema
trace.log
sell_comparison_chain/
policy.dw
README.md
schema.cedarschema
sell_datetime_window/
policy.dw
README.md
schema.cedarschema
sell_like_a_prefix/
expected.out
policy.dw
README.md
schema.cedarschema
trace.log
sell_logical_grouping/
policy.dw
README.md
schema.cedarschema
sell_nested_if_threshold/
policy.dw
README.md
schema.cedarschema
... 1600 moreShowing a partial view of a very large repo.
FAQ
dogwood is a Claude Code plugin with 4 hand-picked skills for security work, indexed on Flowy. Install it with the command on its page. It includes authoring-action-schema, authoring-service-schema, autoformalize-policies. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.