# Policy As Config

> Encode policy — consent mechanisms, data flow, allowlists, retention, feature gates — as config/data rather than hardcoded, so it's auditable, grep-able, and changeable without a code edit. Use when adding a consent flow, a data-sharing path, a feature allowlist, a retention rule, or any policy that compliance/product may need to inspect or change.

- Skill: `jcdavis131/policy-as-config` (Agent Skill)
- Install (CLI): `npx skillmds@latest add jcdavis131/policy-as-config`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jcdavis131/policy-as-config/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: jcdavis131 (https://skillmd.com/u/jcdavis131)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/jcdavis131/policy-as-config

---


# Policy As Config

Policy hardcoded in code is invisible (you can't grep a behavior) and expensive to change (a code edit + deploy). Policy as config is auditable (a data field), grep-able, and changeable without touching code. This is the compliance counterpart to infrastructure-as-code.

## What counts as policy

- **Consent** — the mechanism (opt-in checkbox on `/check`) and what consented data is used for.
- **Data flow** — where consented samples go (`data/data-ingest/inbox`), what source they're tagged as (`data-ingest source: model-gateway-health-checks`).
- **Allowlists / denylists** — which sites, which providers, which endpoints.
- **Retention** — how long data is kept.
- **Feature gates** — which features are on for which sites/tenants.

## The shape

Encode policy in the fleet/service registry config, alongside the entity it governs:

```json
{
  "id": "model-gateway",
  "domain": "model-gateway.example.com",
  "dataConsent": "Opt-in checkbox on /check; consented samples → data/data-ingest/inbox (data-ingest source: model-gateway-health-checks)"
}
```

One field encodes: the mechanism (opt-in checkbox), the location (`/check`), the flow (→ `data/data-ingest/inbox`), and the source tag. A compliance reviewer reads one field and knows the whole consent story for that site.

## Why config, not code

- **Auditable.** A reviewer greps `dataConsent` across the registry and sees every site's consent model in one pass. A code-based consent model requires reading every route handler.
- **Changeable without a code edit.** Tightening consent from "opt-in" to "opt-in + explicit confirmation" is a config change, not a code change + deploy.
- **Visible to automation.** The fleet SDK reads the config; a drift detector can flag sites missing a `dataConsent` field.
- **Stable surface.** Code changes; policy fields stay named and grep-able across versions.

## When to keep policy in code

- The policy is enforced by code semantics that can't be expressed as data (a complex multi-step auth flow).
- The policy is truly one-off for a single code path.
- The policy changes so often that config would lag code anyway.

Most policy is none of these — it's a rule that belongs in config.

## Anti-patterns

- **Consent buried in a route handler.** "We do consent in the /check page" — invisible to anyone not reading that handler.
- **Data flow implied by code.** Samples land in `data/data-ingest/inbox` because a script writes there, but nothing says that's the intended flow. A config field makes intent explicit.
- **Policy fields without the flow.** `"dataConsent": "opt-in"` — opt-in *for what*? The field must encode the mechanism AND the flow.
- **Config that duplicates code instead of governing it.** Policy in config that the code ignores is worse than no config — it lies.

## Pair with

- `metadata-align` — the fleet/service registry is the surface where policy-as-config lives; keep it aligned.
- `agent-guardrails` — allowlists are policy-as-config applied to agents.
- `readiness-report` — a missing `dataConsent` field on a new site is a "needs your input" item (compliance sign-off).

