/authoring-service-schema
Author or edit a Dogwood SERVICE schema — the event schema (.dwschema: event kinds, decision vs history points, renamed/reserved fields, nested records, correlation pins) and/or information providers (providers.json + the Rhai `evaluate` implementation behind a computed
$ npx -y skills add dogwood-policy/dogwood --skill authoring-service-schema --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/authoring-service-schema
Context preview
The summary Claude sees to decide when to auto-load this skill.
Author or edit a Dogwood SERVICE schema — the event schema (.dwschema: event kinds, decision vs history points, renamed/reserved fields, nested records, correlation pins) and/or information providers (providers.json + the Rhai `evaluate` implementation behind a computed
SKILL.md
authoring-service-schema.SKILL.mdname: authoring-service-schema
description: "Author or edit a Dogwood SERVICE schema — the event schema (.dwschema: event kinds, decision vs history points, renamed/reserved fields, nested records, correlation pins) and/or information providers (providers.json + the Rhai `evaluate` implementation behind a computed guardrail fact). Use when a policy needs a non-default event model (a history-only event kind, a renamed principal field, a pin/correlation invariant) or a computed fact from a provider/guardrail. The service schema is OPTIONAL and defaults sensibly (default = request/response/error kinds with only `request` deciding, a universal principal pin giving key-local semantics, a 24h `max_window` cap, no providers, and a small standard macro library), so this also covers deciding whether one is even needed. Requires a Cedar action schema first — that is authoring-action-schema. NOT for the Cedar action schema itself (entities/actions/context) — that is authoring-action-schema. NOT for writing `.dw` policies — that is autoformalize-policies."
Authoring a Dogwood service schema (events + providers)
Your job: produce the **service-schema half** of a Dogwood schema — an **event schema** (`.dwschema`) and/or an **information-provider declarations** file (`providers.json` plus its Rhai implementation) — that parses, is well-formed, and lets the policies you care about validate against a concrete action schema.
The service schema is **entirely optional and defaults sensibly**. The default event schema declares three kinds — `request` (the only decision kind), `response`, and `error` (both history-only) — each carrying the action's inputs (`response` also its outputs) plus the reserved leaves `callerPrincipal` / `callerResource` / `requestId` / `sessionId`. Crucially, `callerPrincipal` is a **universal symmetric pin** (`pin callerPrincipal: principalType(A) = principal` on every kind), so the default runs under **key-local semantics**: every temporal predicate is silently correlated to the current request's principal, and other principals' events are invisible to it. The default look-back cap is `max_window = 24h`, the default provider set is **empty**, and the default macro library is the small standard one (`count_within`, `sum_within`, `count_distinct_within`, `bind`). So the most important decision is Step 0: *do you even need one?* If not, the best service schema is no service schema — omit it and Dogwood uses the default.
This skill has two cores — **events** and **providers** — plus **macros** as a related seam (Step 3, briefly; the guide owns it). Do **not** invent DSL or JSON from memory: the guide is exhaustive and every construct is corpus-verified. Follow the steps in order.
Step 0 — Decide whether you need a service schema at all (do this first)
Write a custom **event schema** only if the application's event model diverges from the default request/response/error model in one of these ways:
- **A history-only event kind the default lacks** — an `audit`/`outcome` kind, or
renaming the set (`attempt`/`outcome` instead of `request`/`response`). The default already gives `request` (decision) + `response` + `error` (history); customize only to go *beyond* that.
- **A different decision point** — some kind other than `request` must run
authorization (mark it `decision`).
- **A renamed or extra reserved/principal field** — the injected principal is
`actor` not `callerPrincipal`, or an extra `__session_id`.
- **Nested record fields** — hierarchical fields like `__platform.session.id`.
- **A different pin / correlation invariant** — the default already pins
`callerPrincipal` on every kind (key-local, per-principal semantics). Write a custom schema to pin a *different* key (a session id), to add an extra pin, or — going the other way — to get **global-trace semantics** (a policy about *any* principal's events, e.g. "N logins by any user"), which requires a schema *without* the universal principal pin (the shipped `configuration/event-schemas/unpinned.dwschema` is exactly that).
- **A longer look-back than 24h** — every temporal window is capped by the
event schema's `max_window` directive, **24h when absent**, so a policy with `within 7d` is a validation error under the default. Raising the cap is an event-schema change: copy the default schema and add `max_window = <interval>` (e.g. `max_window = 30d`) at the top of the file. **A `.dwschema` containing only the directive declares zero events** — it passes the isolated `schema event` check but every policy predicate then fails the composite `validate` (`does not name a declared event`) — so always carry the event declarations along with the directive.
Write **providers** (`providers.json`) only if a policy needs a **computed fact** not in the request — a regex match, denylist check, risk/content score, allowlist lookup — i.e. the `Provider::Name(args)` / `guardrails { }` path. Write a **macro library** only for a genuinely reusable policy fragment (Step 3).
If **none** of these apply, **skip the service schema entirely** — do not write an empty `.dwschema` (an explicitly-supplied blank event schema declares zero events and is *rejected* at build time; only *omitting* it falls back to the default). Say so and stop.
The ground truth (read before authoring)
The event-schema DSL and the provider declaration format are precisely documented, including their legality rules. Treat these as authoritative. Paths are relative to this skill directory (`.claude/skills/authoring-service-schema/`); the guide lives in the `dogwood-docs` crate:
- `../../../dogwood-docs/guide/03-event-schema.md` — the **event-schema DSL**:
the `[decision] event <A>::kind { … }` shape, the four selectors (`inputs`, `outputs`, `principalType`, `resourceType`), spreads vs field-types, nested records, **pins** (`pin name: type = <request-reference>`), decision vs history kinds, the **`max_window` directive
Read more
name: authoring-service-schema description: "Author or edit a Dogwood SERVICE schema — the event schema (.dwschema: event kinds, decision vs history points, renamed/reserved fields, nested records, correlation pins) and/or information providers (providers.json + the Rhai `evaluate` implementation behind a computed guardrail fact). Use when a policy needs a non-default event model (a history-only event kind, a renamed principal field, a pin/correlation invariant) or a computed fact from a provider/guardrail. The service schema is OPTIONAL and defaults sensibly (default = request/response/error kinds with only `request` deciding, a universal principal pin giving key-local semantics, a 24h `max_window` cap, no providers, and a small standard macro library), so this also covers deciding whether one is even needed. Requires a Cedar action schema first — that is authoring-action-schema. NOT for the Cedar action schema itself (entities/actions/context) — that is authoring-action-schema. NOT for writing `.dw` policies — that is autoformalize-policies."
Authoring a Dogwood service schema (events + providers)
Your job: produce the **service-schema half** of a Dogwood schema — an **event schema** (`.dwschema`) and/or an **information-provider declarations** file (`providers.json` plus its Rhai implementation) — that parses, is well-formed, and lets the policies you care about validate against a concrete action schema.
The service schema is **entirely optional and defaults sensibly**. The default event schema declares three kinds — `request` (the only decision kind), `response`, and `error` (both history-only) — each carrying the action's inputs (`response` also its outputs) plus the reserved leaves `callerPrincipal` / `callerResource` / `requestId` / `sessionId`. Crucially, `callerPrincipal` is a **universal symmetric pin** (`pin callerPrincipal: principalType(A) = principal` on every kind), so the default runs under **key-local semantics**: every temporal predicate is silently correlated to the current request's principal, and other principals' events are invisible to it. The default look-back cap is `max_window = 24h`, the default provider set is **empty**, and the default macro library is the small standard one (`count_within`, `sum_within`, `count_distinct_within`, `bind`). So the most important decision is Step 0: *do you even need one?* If not, the best service schema is no service schema — omit it and Dogwood uses the default.
This skill has two cores — **events** and **providers** — plus **macros** as a related seam (Step 3, briefly; the guide owns it). Do **not** invent DSL or JSON from memory: the guide is exhaustive and every construct is corpus-verified. Follow the steps in order.
Step 0 — Decide whether you need a service schema at all (do this first)
Write a custom **event schema** only if the application's event model diverges from the default request/response/error model in one of these ways:
- **A history-only event kind the default lacks** — an `audit`/`outcome` kind, or
renaming the set (`attempt`/`outcome` instead of `request`/`response`). The default already gives `request` (decision) + `response` + `error` (history); customize only to go *beyond* that.
- **A different decision point** — some kind other than `request` must run
authorization (mark it `decision`).
- **A renamed or extra reserved/principal field** — the injected principal is
`actor` not `callerPrincipal`, or an extra `__session_id`.
- **Nested record fields** — hierarchical fields like `__platform.session.id`.
- **A different pin / correlation invariant** — the default already pins
`callerPrincipal` on every kind (key-local, per-principal semantics). Write a custom schema to pin a *different* key (a session id), to add an extra pin, or — going the other way — to get **global-trace semantics** (a policy about *any* principal's events, e.g. "N logins by any user"), which requires a schema *without* the universal principal pin (the shipped `configuration/event-schemas/unpinned.dwschema` is exactly that).
- **A longer look-back than 24h** — every temporal window is capped by the
event schema's `max_window` directive, **24h when absent**, so a policy with `within 7d` is a validation error under the default. Raising the cap is an event-schema change: copy the default schema and add `max_window = <interval>` (e.g. `max_window = 30d`) at the top of the file. **A `.dwschema` containing only the directive declares zero events** — it passes the isolated `schema event` check but every policy predicate then fails the composite `validate` (`does not name a declared event`) — so always carry the event declarations along with the directive.
Write **providers** (`providers.json`) only if a policy needs a **computed fact** not in the request — a regex match, denylist check, risk/content score, allowlist lookup — i.e. the `Provider::Name(args)` / `guardrails { }` path. Write a **macro library** only for a genuinely reusable policy fragment (Step 3).
If **none** of these apply, **skip the service schema entirely** — do not write an empty `.dwschema` (an explicitly-supplied blank event schema declares zero events and is *rejected* at build time; only *omitting* it falls back to the default). Say so and stop.
The ground truth (read before authoring)
The event-schema DSL and the provider declaration format are precisely documented, including their legality rules. Treat these as authoritative. Paths are relative to this skill directory (`.claude/skills/authoring-service-schema/`); the guide lives in the `dogwood-docs` crate:
- `../../../dogwood-docs/guide/03-event-schema.md` — the **event-schema DSL**:
the `[decision] event <A>::kind { … }` shape, the four selectors (`inputs`, `outputs`, `principalType`, `resourceType`), spreads vs field-types, nested records, **pins** (`pin name: type = <request-reference>`), decision vs history kinds, the **`max_window` directive
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.
Other skills on dogwood.
- /authoring-action-schema
Stand up the Cedar ACTION schema (.cedarschema) a Dogwood deployment governs — its entity types (principals/resources), one action per tool/operation, and each action's context.input/output/system layout — either hand-written or generated from an MCP tools/list manifest. Use
Open skill - /autoformalize-policies
Autoformalize a natural-language authorization requirement into a validated Dogwood (.dw) policy. Use when a user describes access rules in prose (\"only allow X if Y\", \"deny after Z\", \"no more than N per hour\") and wants a compilable Dogwood policy. Disambiguates intent
Open skill - /dogwood
Orientation and router for authoring Dogwood authorization policies end to end. Run /dogwood when you are starting from scratch and are not sure which step you are on — it maps the lifecycle (action schema -> service schema, if needed -> policies -> validate/replay) and points
Open skill

