ACF
acfstandard.io
Developer docs
FR
REASON

acf.assign-ddao-controls

ACF® control set scoped to an agent’s autonomy level and risk class — dual vocabulary (plain-English recommended_controls + canonical ddao_controls), estimated effort in days, and identified owners.

Tip
The output deliberately splits recommended_controls (business language for sponsor and audit) from ddao_controls (canonical ACF® vocabulary for the DDAO). This duality is what makes the assignment legible internally AND defensible externally. requires_human_review stays constant — the DDAO validates the actual cadence before any commit.

When to use

Use this tool when an agent already has an ACF® qualification (acf_level) and a criticality score (risk_level), and you now need the exact list of controls to enforce — what kill switches, what escalation thresholds, what logs, who owns each control, at what cadence it runs. This is the step that turns a qualification into an operational plan.

The board-level question the output answers: “How many DDAO-days does it cost, and who does what?” The estimated_total_effort_days gives a defensible order of magnitude for a financial sponsor; the recommended/ddao duality avoids vocabulary confusion between the business team and the DDAO.

Input parameters

Five fields, three required. The acf_level and risk_level must already be settled upstream (typically by acf.classify-agent or acf.assess-autonomy).

agent_descriptionstring (10-500)required
Short agent description. Used in the DDAO summary and rationale; does not drive the control selection (that is driven by level × risk).
acf_level"N0" | "N1" | "N2" | "N3"required
ACF® autonomy level. N0 = pure observation, N1 = assisted, N2 = bounded delegation, N3 = autonomous. Drives the severity of the control set.
risk_level"low" | "medium" | "high" | "critical"required
Risk class from the ACF-02 matrix. Combined with acf_level, it determines the mapping cell.
budget_constraint"minimal" | "standard" | "comprehensive"
Budget constraint. minimal = keep the first two controls (kill switch + log); standard = full canonical set; comprehensive = full canonical set, no trim.
locale"en" | "fr"default: "en"
Language of the textual output (control titles, summary).

Output schema

The output is a structured object containing two parallel control lists, the total estimated effort, and a summary ready to paste into an ACF-12 card.

recommended_controlsRecommendedControl[]
Controls in business language — id, title, description, owner, frequency (one_time / monthly / quarterly / annual / on_event), evidence_storage. Trimmed to 2 if budget_constraint = minimal.
ddao_controlsstring[]
Same controls in canonical ACF® vocabulary — codes C-AUTONOMY-XX, C-LOG-XX, C-KILL-XX, C-DRIFT-XX, C-ESC-XX. Ready to paste into the DDAO card.
total_countnumber
Total controls across both lists (recommended + ddao).
estimated_total_effort_daysnumber
Cumulative person-days based on each control’s frequency (one_time=5, monthly=1, quarterly=2, annual=4, on_event=1).
ddao_summarystring
Summary sentence ready to paste into the DDAO’s ACF-12 card.
confidence"low" | "medium" | "high"
Global confidence level. High whenever (level, risk) is in the canonical matrix with no contradiction.
assumptionsstring[]
Explicit assumptions — V1.0 does not yet apply sector-specific overrides (a banking agent inherits the same controls as a SaaS agent for the same level/risk pair).
gaps_to_validatestring[]
Gaps for the DDAO to validate — actual availability for the proposed cadence, evidence-storage location.
requires_human_reviewtrue
Constant. No call returns false.

Example call

An autonomous N2 procurement agent capped at 50k EUR, high criticality:

assign-controls.tstypescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

const transport = new StdioClientTransport({
  command: "npx",
  args: ["-y", "acf-mcp"],
});
const client = new Client({ name: "demo", version: "1.0" }, {});
await client.connect(transport);

const result = await client.callTool({
  name: "acf.assign-ddao-controls",
  arguments: {
    agent_description:
      "Autonomous procurement agent that places purchase orders up to 50k EUR against pre-approved suppliers and writes the result to SAP.",
    acf_level: "N2",
    risk_level: "high",
    budget_constraint: "standard",
    locale: "en",
  },
});

console.log(JSON.stringify(result.content, null, 2));

Response

response.jsonjson
{
  "recommended_controls": [
    {
      "id": "REC-KILL-01",
      "title": "Per-supplier kill switch",
      "description": "Operations can suspend orders to any supplier within 5 minutes, no DDAO escalation required.",
      "owner": "Procurement Ops",
      "frequency": "on_event",
      "evidence_storage": "ACF-07 register"
    },
    {
      "id": "REC-CAP-02",
      "title": "Hard per-order cap at 50k EUR",
      "description": "Any order > 50k EUR is rejected at the agent layer; > 25k requires DDAO co-sign.",
      "owner": "Finance + DDAO",
      "frequency": "on_event",
      "evidence_storage": "ACF-09 escalation log"
    },
    {
      "id": "REC-DRIFT-03",
      "title": "Monthly drift review of supplier mix",
      "description": "Alert if any supplier exceeds 30% of monthly volume vs trailing 6-month baseline.",
      "owner": "DDAO",
      "frequency": "monthly",
      "evidence_storage": "Drift dashboard + DDAO minutes"
    },
    {
      "id": "REC-LOG-04",
      "title": "Signed decision register",
      "description": "Every order decision logged with input, supplier choice, rationale, and ed25519 signature.",
      "owner": "Platform team",
      "frequency": "on_event",
      "evidence_storage": "ACF-08 register, 6-month retention"
    },
    {
      "id": "REC-DRILL-05",
      "title": "Quarterly kill-switch drill",
      "description": "Simulate a supplier compromise; verify orders are halted in < 5 minutes.",
      "owner": "Procurement Ops + DDAO",
      "frequency": "quarterly",
      "evidence_storage": "ACF-07 drill report"
    }
  ],
  "ddao_controls": [
    "C-AUTONOMY-02 — N2 gating: orders 25k-50k EUR require DDAO co-sign before SAP write",
    "C-LOG-03 — Signed decision register branched to ACF-08, 6-month retention",
    "C-KILL-01 — Per-supplier kill switch, response time ≤ 5 min, drilled quarterly",
    "C-DRIFT-02 — Monthly drift dashboard for supplier mix",
    "C-ESC-04 — DDAO escalation on any single order > 25k EUR or supplier concentration > 30%"
  ],
  "total_count": 10,
  "estimated_total_effort_days": 9,
  "ddao_summary": "Control set scoped to ACF® N2 / risk=high (5 recommended controls, 5 ACF-canonical controls).",
  "confidence": "high",
  "assumptions": [
    "Controls are derived from the canonical level × risk mapping; sector-specific overrides not applied in V1.0."
  ],
  "gaps_to_validate": [
    "Confirm DDAO availability for the proposed escalation cadence.",
    "Confirm evidence-storage location for each control before go-live."
  ],
  "requires_human_review": true,
  "rationale_per_rule": [
    {
      "rule_id": "ddao-mapping.N2-high",
      "rule_version": "2026-06",
      "fired": true,
      "evidence": "level=N2, risk=high"
    }
  ],
  "doctrine_version": "ACF framework v1.0 / rules 2026-06",
  "doctrine_hash": "sha256:bf0b6d8e4731ebdc58f6d6338702c5b74af47874cf0ad3dc958cde5c5b30b9dc",
  "doctrine_signature": "ed25519:…",
  "doctrine_archive_url": "https://acfstandard.io/doctrine/v1.0/archive.json",
  "regulatory_snapshot": "EU AI Act 2024/1689 · GDPR 2016/679 · ISO 42001:2023 · NIST AI RMF 1.0 · COBIT 2019 — frozen 2026-06",
  "generated_at": "2026-06-14T12:03:47.501Z",
  "disclaimer": "Preliminary qualification only — not legal advice. Human review required."
}

Common errors

  • InvalidEnumValue acf_level receives something other than N0..N3, or risk_level something other than low / medium / high / critical. The tool does not guess — fix to a canonical value.
  • InputTooShort agent_description &lt; 10 chars. The DDAO summary would have no usable context — be specific.
  • MappingNotFound the (level, risk) pair is not in the loaded mapping matrix. Likely a doctrine mismatch — update acf-mcp.