From dtwo
Create, validate, attach, publish, deploy, verify, and roll back DTwo policies and their pipeline attachments. This is the system-of-record skill: it owns the DTwo MCP tools for policy lifecycle (create, update, publish, revert) and pipeline lifecycle (attach, deploy, verify), and is responsible for confirming pipeline attachments before and after deployment. TRIGGER when: user says "create/add a policy", "modify/update a policy", "block/allow/redact something", "attach/detach policy", "set/update pipeline", "publish/pin policy version", "deploy gateway" after a policy change. Always pair with dtwo-policy-rego for the Rego authoring/modification step. SKIP when: task is purely *explaining* existing Rego with no save/attach/deploy intent (use dtwo-policy-rego alone); task is editing gateway YAML or MCP server entries (use dtwo-gateway-config).
How this skill is triggered — by the user, by Claude, or both
Slash command
/dtwo:dtwo-gateway-policyThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
<!-- © 2026 DTwo, Inc. -->
You manage DTwo policies and their attachment to gateway pipelines through the DTwo MCP server. You handle the full policy lifecycle: creating and validating policies, attaching them to gateway ingress/egress pipelines, deploying, and verifying behavior.
This skill is typically used alongside others. Invoke them via the Skill tool when relevant (in other agents, use your host's equivalent skill-loading mechanism):
dtwo-gateway-policy unless the task is pure pipeline attachment of an already-authored policy.This skill requires the DTwo MCP server to be connected (dtwo-* tools must be loaded). If the tools are not available, ask the user to connect the DTwo MCP server first.
The tools listed below reflect the initial set. The DTwo MCP server may add new tools over time — if you discover dtwo-* tools not listed here, use them where appropriate. Prefer newer, more specific tools over workarounds when available.
Tool naming note: This skill refers to the DTwo MCP tools by their short names (e.g., dtwo-list-gateways). In Claude Code, that short name is what you call directly — the mcp__dtwo__ server prefix is stripped automatically. In other MCP clients you may see the fully-qualified name mcp__dtwo__dtwo-list-gateways; both refer to the same tool. This is separate from the per-tool name that appears inside Rego policies (input.payload.name) — see the companion dtwo-policy-rego instructions for that.
sub, email, org_id), pull tenant claims with dtwo-list-claims (see Tool Discovery → Finding Identity Claims). Skip for policies that only gate on tool names, arguments, or other non-identity inputs.Skill("dtwo-policy-rego") (or your host's equivalent) to produce or revise the code before proceeding.revert-policy as deletion; detach first if the user wants removal from runtime behavior.Dtwo entry in mcp_servers), plan a dtwo-* passthrough into the Rego. Without it, the deploy locks management calls out — see Deploying → Self-lock risk.| Tool | Purpose |
|---|---|
dtwo-list-policies | List policies with optional filters (name, direction, uid) |
dtwo-get-policy | Fetch a single policy by UID (includes draft Rego code) |
dtwo-get-policy-versions | List published versions for a policy |
dtwo-validate-policy-rego | Validate Rego code without saving — useful for dry-run checks before committing changes (note: dtwo-add-policy and dtwo-update-policy also validate automatically) |
dtwo-add-policy | Validate and create a new policy (requires name, description, policy, packageName, direction) |
dtwo-update-policy | Update an existing policy's draft — any field (policy, packageName, name, description, direction, tags). Validates Rego when both policy and packageName are provided |
dtwo-publish-policy | Publish the current draft as a new version |
dtwo-revert-policy | Restore a published version back into the draft |
dtwo-list-claims | Return the union of JWT claim names observed across the tenant, plus the issuers seen. Defaults to tenant-wide; pass gatewayUid to scope to a single gateway when the user asks. Call this when authoring or modifying identity-aware policies so rules can reference claims that actually exist; skip for policies that don't read input.subject.claims. |
| Tool | Purpose |
|---|---|
dtwo-list-gateways | List gateways with optional filters (name, status, uid) |
dtwo-get-gateway | Fetch a single gateway by UID |
dtwo-set-gateway-pipelines | Attach policies to ingress/egress pipelines |
dtwo-get-gateway-pipelines | Fetch ingress and egress pipeline steps for a gateway, including policy details |
dtwo-deploy-gateway | Queue a deployment for the gateway |
dtwo-get-gateway-deployments | List deployment tasks for a gateway |
dtwo-get-deployment | Check status of a specific deployment |
The DTwo MCP server does not expose a delete-policy tool. revert-policy restores a prior version — it does not delete.
When the user asks to delete a policy:
dtwo-set-gateway-pipelines (pass [] to clear the relevant direction), then redeploy. A detached policy remains in the policy list but has no runtime effect.If a dtwo-delete-policy tool later appears (see the tool-discovery note under Prerequisites), prefer it over this workaround.
Users typically refer to gateways by name. Use dtwo-list-gateways with the name filter to resolve a name to a UID. If the user hasn't specified a gateway and more than one exists, list the gateways and ask which one to use.
When writing policies, you need exact tool names, argument schemas, and (for identity-aware policies) the shape of input.subject.claims. Use dtwo-get-gateway-config for tool names and dtwo-list-claims for claim names (details in Finding Identity Claims below) — falling back to the dump-input debug technique when you need actual claim values rather than just names — instead of guessing.
dtwo-get-gateway-config to retrieve the gateway's YAML configuration — the mcp_servers[].name values are the server name prefixes used in tool names.input.resource.name (PARC) or input.payload.name (legacy alias) — both carry the same value, constructed as <server-name>-<tool-name>. The names visible when listing tools from the MCP server match what the gateway passes to OPA — no prefix stripping is needed.input.payload.args — no guessing required.Pull claims when the policy will read input.subject.claims — i.e. when gating on identity such as sub, email, org_id, or scope. Skip for policies that only inspect tool names, arguments, or other non-identity inputs (content filters, channel allowlists, simple tool gating). When identity is in scope, knowing what claims the tenant has actually observed often surfaces a cleaner policy shape (for example, gating on org_id instead of a brittle email-substring match). The projected claim set varies by IdP, by the scopes the client requested, and by each gateway's jwt_audience, so don't assume — query.
When to pull (decision triggers). Pull when the user's request mentions any of:
Skip when the request only references:
If ambiguous, ask the user one question rather than guessing — the call is cheap but pulling claims for a content-only policy clutters the agent's context.
Primary path: dtwo-list-claims. Returns the tenant-wide union of JWT claim names and issuers. Call it with no arguments by default. Pass gatewayUid only when the user has explicitly asked to scope the result to a single gateway (e.g., "what claims does the PARC Gateway see"); otherwise tenant-wide is the right default and gives a more complete picture.
Fallback: dump-input policy. Fall back to the dump-input technique (described in dtwo-policy-rego — see Debugging Policies + Identity (Subject and Claims)) when you need actual claim values for a specific caller (e.g. the exact org_id for a particular user), not just claim names — dtwo-list-claims only returns names and issuers. Rare edge case: if dtwo-list-claims returns an empty set the tenant has not yet observed any JWT traffic anywhere; making one real call populates the discovery store.
Detach the dump policy when done — the dtwo-policy-rego Common Pitfalls section warns about leaving an always-deny policy attached.
If dtwo-get-gateway-config shows an MCP server named atlassian-jira-mcp, and that server exposes a tool atlassian-jira-mcp-getjiraissue with parameters {cloudId, issueIdOrKey, ...}:
atlassian-jira-mcp-getjiraissue (matched against input.resource.name or input.payload.name)cloudId, issueIdOrKey, etc.Every policy description is structured markdown with up to three sections. The field is rendered in a markdown editor that supports headings, bold, italic, lists, and code blocks.
## Intent
<One sentence. The policy's durable goal — no tool names, claim names, or argument identifiers.>
## Description
<Optional. Free-form. History, ticket links, owners, expiry plans — anything that doesn't fit the other sections.>
## Implementation
<Optional. Only when there's something the Rego doesn't make obvious on its own.>
Field rules:
Intent (required) — 1 sentence. The policy's durable goal, written so it remains true even if tool names, claim names, or argument schemas change. No tool/claim/argument identifiers. Agents should not edit Intent unless the user's goal has changed.
slack-mcp-slack-send-message when message matches a secret regex." (that's Implementation)Description (optional) — Free-form, user-owned. Any length. Use for context that doesn't fit the other two sections: history, ticket links, owners, expiry plans. Agents should not edit this unless explicitly asked.
Implementation (optional) — Include only when there's something the Rego doesn't make obvious on its own. Most useful for:
slack.ingress.allowlist running first"; "must precede any redaction step that rewrites message")If the Rego is self-explanatory and stands alone, omit the section entirely.
Examples:
Common case — Intent + context notes, no Implementation needed:
## Intent
Prevent secrets and PII from leaking to John via Slack DMs.
## Description
Added 2026-04 after a near-miss where an API key was almost pasted
into John's DM during an oncall handoff. Owner: [email protected].
Revisit once the org-wide secrets-DLP egress policy ships (DTWO-1234)
— this can likely be retired then.
With Implementation — when pipeline ordering matters:
## Intent
Block Jira ticket creation from contractors outside business hours.
## Description
Compliance request from legal (DTWO-2210). Contractors are identified
by the absence of an `employee_id` claim.
## Implementation
Runs **after** `jira.ingress.tenant_isolation` in the pipeline —
relies on that earlier step having already rejected cross-tenant
calls, so this policy only inspects `input.subject.claims` and
business-hours, not `cloudId`. Reordering will produce false
allows.
sub, email, org_id), pull tenant claims with dtwo-list-claims (see Tool Discovery → Finding Identity Claims).dtwo-* passthrough before authoring — see Deploying → Self-lock risk.dtwo-policy-rego instructionsdtwo-validate-policy-regodtwo-add-policy — provide:
name — human-readable policy namedescription — structured markdown using the template in Policy Description Format (Intent required; Description and Implementation optional)policy — the Rego codepackageName — the Rego package name (e.g., jira.ingress.readonly)direction — ingress or egressdtwo-set-gateway-pipelines — omit policyVersion to reference the draftdtwo-deploy-gateway and test the policy behaviordtwo-publish-policydtwo-set-gateway-pipelines and redeploydescription with dtwo-get-policydescription before editing:
dtwo-list-claims (see Tool Discovery → Finding Identity Claims).dtwo-policy-rego instructionsdtwo-update-policy — provide uid, policy, and packageName (Rego is validated automatically when both are provided). Also pass description when Implementation was updated or the description was backfilled; preserve it unchanged otherwise.policyVersion), just deploy to pick up the new draft. If it was pinned to a published version, update the pipeline step by omitting policyVersion with dtwo-set-gateway-pipelines, then deploy.dtwo-publish-policydtwo-get-policy-versionsdtwo-revert-policy (optionally publish immediately with publish: true)Use dtwo-set-gateway-pipelines to attach policies to a gateway's ingress and/or egress pipelines. Each pipeline step requires:
policyUid — the policy's UID (from dtwo-list-policies or dtwo-add-policy)evalNamespace — the Rego package name declared in the policy (e.g., jira.ingress.readonly)policyVersion (optional) — controls which version of the policy to use:
0 — use the latest published version. Requires at least one published version to exist.N (e.g., 1, 2) — pin to a specific published version.Once a draft is working as desired, publish the policy and update the pipeline step to pin the published version number for stability.
Steps are evaluated in array order — place broader policies (e.g., access control) before narrower ones (e.g., argument transforms). If an earlier step denies, later steps are not evaluated.
Ingress and egress steps are independent arrays. Omitting a direction leaves it unchanged; pass [] to clear it.
dtwo-deploy-gateway is the only operation that affects a running gateway — all other changes (policy edits, pipeline attachment, publishing, reverting) modify draft or published state that is not live until a deploy happens. Always confirm with the user before deploying.
After attaching or modifying policies, you must deploy the gateway for changes to take effect on the running instance.
Self-lock risk before deploy. If the policy you're about to deploy will deny calls to the DTwo MCP server itself (e.g., a
default allow := falsepolicy with no management bypass, or a debug policy that denies all requests), and your MCP client routesdtwo-*tools through this gateway, the deploy will lock you out — recovery requires the DTwo web UI. Before deploying, checkdtwo-get-gateway-configfor aDtwoMCP server entry; if present and your client connects through this gateway, either add adtwo-*passthrough rule to the policy or route management traffic through a different gateway. The Common Pitfalls section indtwo-policy-regocovers the guarded-management-tool pattern in detail.
Does the gateway restart on deploy? It depends on what changed:
completed.dtwo-deploy-gateway returns the task UID immediately; poll dtwo-get-deployment with that UID until status: "completed" before testing or further changes.
Client quirks during a configuration restart (Claude Code). These only apply to gateway-config deploys, not policy-only deploys. Claude Code's MCP client surfaces two distinct transient error states; other MCP clients may reconnect transparently or surface different errors.
Streamable HTTP error: 502 Bad Gateway— the gateway is restarting but the MCP client connection is still alive. Keep retrying — this recovers automatically.MCP server "<name>" is not connected— the MCP client has fully disconnected and will not auto-recover. Ask the user to reconnect the MCP server in their client (e.g., via the MCP server panel in VS Code or the CLI reconnect command), then resume polling.Do not ask the user to reconnect unless you see the "is not connected" error. The 502 errors resolve on their own. For policy-only deploys, neither error is expected.
After deploying a gateway:
dtwo-get-deployment until it returns status: "completed". For policy-only deploys, polling is uneventful — the gateway doesn't restart, so no transient errors are expected. For gateway-configuration deploys, the gateway restarts; if a poll call fails with a 502 error, retry — the gateway is still restarting. If you get "MCP server is not connected", ask the user to reconnect, then resume polling. Once status is "completed", the gateway is live and ready to test.dtwo-get-gateway-pipelines. Verify the expected policies are present at the expected step indexes, that evalNamespace matches each policy's package declaration, and that policyVersion pins match your intent (omitted = draft, 0 = latest published, N = pinned version).package declaration and the evalNamespace used when attaching. Verify they match exactly.dtwo-policy-rego instructions (debug policies, blanket deny diagnosis)This section walks through one complete request — from natural-language prompt to a pinned, deployed policy — using a Slack DM content filter as the example. It stitches the abstract sections above (Tool Discovery, Policy Workflow, Pipeline Attachment, Deploying, Verification) into one correct assembly.
User request: "Create a policy that blocks DMs to John in Slack when the message contains sensitive information."
This example gates on tool name + payload content rather than identity, so the workflow's claims-fetch step is skipped (per Tool Discovery → Finding Identity Claims). For an identity-aware request like "block DMs to John from non-admin users", you'd insert a dtwo-list-claims call before step 1.
Call dtwo-list-gateways. If the user hasn't named one and multiple exist, ask. Record the UID.
Call dtwo-get-gateway-pipelines for that UID. This tells you whether new steps append cleanly, or risk colliding with existing transforms / deny policies.
Call dtwo-get-gateway-config. Read mcp_servers[].name — the server name prefixes policy tool names. For Slack, the send tool is typically slack-mcp-slack-send-message with args {channel_id, message, thread_ts, ...}. Do not guess; confirm from the config.
For "DMs to John", you need John's Slack user ID (DMs use user IDs as channel_id). Use slack-search-users or equivalent. Capture the ID, and note the assumption that DM = user ID.
dtwo-policy-regoInvoke Skill("dtwo-policy-rego") (or your host's equivalent) with the exact tool name, channel ID, and the sensitive-content patterns agreed with the user. It returns a fenced Rego block.
Call dtwo-validate-policy-rego with the Rego and its packageName. If validation fails, loop back to step 5 — do not create a broken policy.
Call dtwo-add-policy with name, description, policy, packageName, direction. Capture the returned uid. The draft is stored but not live.
Use the Policy Description Format template for description. For this example (Intent is required; Implementation is omitted because the Rego is self-explanatory):
## Intent
Prevent secrets and PII from leaking to John via Slack DMs.
## Description
Requested by the security team after an oncall near-miss. Revisit
if a tenant-wide egress DLP policy ships — this may be redundant then.
Call dtwo-set-gateway-pipelines with the new step, omitting policyVersion so the draft is used. Preserve existing steps — do not overwrite them.
{
"ingressSteps": [
{ "policyUid": "<existing>", "evalNamespace": "...", "policyVersion": 1 },
{ "policyUid": "<new>", "evalNamespace": "slack.ingress.no_sensitive_to_john" }
]
}
Deployment is the first live-state change. State it plainly and wait for confirmation before calling dtwo-deploy-gateway. Capture the task UID. This example is a policy-only deploy, so no gateway restart and no MCP client disconnect is expected — see the Deploying section for the policy vs configuration distinction.
Loop on dtwo-get-deployment until status: "completed". For this policy-only deploy, polling should be uneventful — no 502s, no reconnect. If you ever do see a 502 Bad Gateway or "MCP server is not connected" during a poll, the deploy probably also pulled in a pending gateway-config change; handle as described in Deploying.
Call dtwo-get-gateway-pipelines again. Confirm the new step is at the expected index with the right evalNamespace and the intended policyVersion (undefined for draft).
Invoke the guarded tool two ways:
If the deny case fails silently (the request goes through), the most common cause is an evalNamespace / package mismatch — verify both match exactly.
Once both tests pass, ask the user whether to publish. They may want to tweak the Rego, add more test cases, or stabilize the draft in a later session before cutting a version — publishing is not reversible without a new version. If confirmed, call dtwo-publish-policy with a clear publish message (what the policy does + what was verified).
After publishing, call dtwo-set-gateway-pipelines again with policyVersion: 1 on the new step. Confirm the redeploy with the user before calling dtwo-deploy-gateway; poll as in step 10.
Do not skip step 14. Leaving the attachment on the draft does not take effect immediately, but the current draft state will be bundled into the next deploy of that gateway, whoever triggers it and whatever the reason. A later dtwo-update-policy edit — even an experimental one — will then go live on a deploy that was meant for an unrelated change. Pinning to a published version freezes runtime behavior against future draft edits.
dtwo-policy-rego instructionsdtwo-gateway-config instructionsdtwo-set-gateway-pipelines, then delete in the DTwo web UIProvides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.
npx claudepluginhub dtwoai/plugins --plugin dtwo