Skip to main content

Agent-era builds · Scope card schema v0.1

The agent scope card

Four questions, one page. What does the agent read? What does it write? Who has to approve? How do you stop it? A scope card answers all four in a form a person can skim and a machine can parse. The vendor publishes it at their own address. The format costs nothing, and no card ever certifies the agent.

Schema v0.1.0 · Published 2026-11-04 · Status: current. Breaking changes ship as v0.2 at a new versioned URL; this page stays frozen.

Why it exists

The demo ends; the questions begin

The demo goes well. The support agent answers in French, pulls up the order, offers the refund. Then procurement asks the boring questions. Where do our chat transcripts go, and for how long? Does anything we type train a model? When the agent wants to issue that refund, does a person sign off first? If it starts misbehaving at 11 pm on a Friday, what is the off switch, and who is allowed to hit it?

The sales deck rarely answers. The privacy policy answers in paragraphs. The scope card answers in fields: eleven blocks, each with one job, published at a stable URL the vendor controls. Think of it as the privacy nutrition label for agents.

Positioning

Your card, your URL

The vendor hosts their own card. movahedi.ca publishes the schema and the tools that read it; we hold nobody's card and we see nobody's traffic. When you want the card, you fetch it from the vendor, not from us.

The render and diff tools read whatever the vendor publishes. Rendering ships with this release; the diff tool, which flags mutated fields and last_true_date shifts between versions of a card, is not built yet. It is the next planned piece.

Cards are free, forever. No fee, no account, no gate between a vendor and the format.

One line matters more than the rest: a card is a disclosure, not a seal. No card is ever described as certified, endorsed, or approved by movahedi.ca. The card says what the vendor claims. Whether the claim is true is a separate question, and the card does not answer it.

The specification

Eleven blocks, in this order

Every card is one JSON object with these blocks, in this order. A missing block is an error, not a shortcut.

1. card_metadata: the envelope

schema_version is "0.1.0".card_id is the vendor's stable identifier for the card, and card_url is where the vendor hosts it; the vendor's URL is the canonical copy.published_at_utc is RFC 3339.last_true_date is the field with teeth: the last date the operator verified every field was true. A card verified six months ago describes a system that has shipped twenty times since.french_completeness_status is complete orpartial_marked, the same convention as the consequential-action index.

2. operator: who runs it

name, jurisdiction, andcontact_url. The name on the card is the name that answers for the agent.

3. agent: what it is for

name, one-sentence purpose in plain language, purpose_fr when the card claims complete French, and version. Purpose is one sentence. A paragraph of marketing copy fails the field.

4. access: what it reads and writes

reads and writes each listsystem_id plus data_categories. The system id is a stable identifier, never a credential or an endpoint secret. The categories are categories, never values:order_ticket, not the ticket.

The rule with no exceptions: a card carries no raw personal information. If a field would need a name, an email address, or an ID number, it does not belong in the card.

5. human_gate: where the person stands

autonomous_steps_before_gate counts how many agent steps may run before a person must approve; 0 means every consequential step needs a person. step_definitionsays what counts as one step, in the operator's own words.requires_human_approval names what only a person may approve: payments, refunds, and any of the twelve consequential actions, CA-01 through CA-12, the agent may touch.

6. prompt_handling: what happens to your words

retained, retention_days,prompts_train_model, and a plain-languagedetail. The boolean buyers skip and should not:prompts_train_model. True means your words feed a model.

7. subprocessors: who else touches the data

name, role (model_host,tool_host, log_host, orother), jurisdiction, andpurpose. Jurisdiction is the field that triggers the cross-border conversation.

8. kill_switch: the off switch

procedure, who_can_trigger, andeffect: what stops, and how fast. Written for someone using it at midnight. A procedure that needs the vendor's support desk and two business days is not a switch.

9. record_correction: when the card is wrong

procedure, contact, andresponse_time. Cards go stale and cards get things wrong. This block says how a wrong field gets fixed and how fast.

10. legal_context: the citations (optional)

Each entry carries a citation and a one-linerelevance. Every legal claim in a card carries its citation here, or it does not ship in the card.

11. non_certification_note: the immutable literal

Byte-identical in every card, in every edition. It appears below exactly as it must appear in the JSON:

This card is an open disclosure format describing what an agent is allowed to do. It is not legal advice, and it is not a movahedi.ca certification, endorsement, or approval of any agent.

The literal is part of the spec, not decoration. Nothing may be added to it, nothing removed.

Worked example

A fictional card, end to end

Café Lumen is a fictional Montreal retailer, the same one from the stamp spec. Its ordering agent takes pickup orders in chat and hands them to the kitchen. Every value below is invented. The card lives in the schema file as the worked example, and there is a printable one-page rendering.

{
  "access": {
    "reads": [
      {
        "data_categories": [
          "menu_items",
          "prices",
          "availability"
        ],
        "note": "Read-only menu feed, refreshed hourly.",
        "system_id": "pos-menu-api"
      },
      {
        "data_categories": [
          "order_status"
        ],
        "note": "Reads status to answer where-is-my-order questions.",
        "system_id": "order-queue"
      }
    ],
    "writes": [
      {
        "data_categories": [
          "order_ticket",
          "pickup_time"
        ],
        "note": "Order tickets carry items and pickup time only; no customer names.",
        "system_id": "kitchen-queue"
      },
      {
        "data_categories": [
          "payment_link_request",
          "amount_cents",
          "order_ref"
        ],
        "note": "Creates payment links. The agent never sees or stores card numbers.",
        "system_id": "payment-link-service"
      }
    ]
  },
  "agent": {
    "name": "Lumen Order Assistant (fictional)",
    "purpose": "Takes customer pickup orders in chat and queues them for the kitchen; confirms payment links but never charges a card.",
    "purpose_fr": "Prend les commandes à emporter en clavardage et les transmet à la cuisine; confirme les liens de paiement mais ne débite jamais une carte.",
    "version": "0.9.2"
  },
  "card_metadata": {
    "card_id": "card-fictional-cafe-lumen-001",
    "card_url": "https://example.com/cards/cafe-lumen-order-assistant.json",
    "fictional_example": true,
    "french_completeness_status": "complete",
    "last_true_date": "2026-11-01",
    "published_at_utc": "2026-11-04T18:00:00Z",
    "schema_version": "0.1.0",
    "supersedes_card_id": null
  },
  "human_gate": {
    "autonomous_steps_before_gate": 3,
    "requires_human_approval": [
      "Any refund or discount over $20",
      "Any change to menu items or prices",
      "Any new tracker, pixel, or server-side feed (consequential action CA-05)"
    ],
    "step_definition": "One tool call counts as one step; a read and its follow-up write are two steps."
  },
  "kill_switch": {
    "effect": "No new orders within 60 seconds. Tickets already in the kitchen finish normally.",
    "procedure": "Press 'Pause agent' on the vendor status page, or email orders-stop@example.com with the subject 'stop'. Either works around the clock.",
    "who_can_trigger": "Any staff member; any customer can trigger it by typing 'stop the bot' in chat."
  },
  "legal_context": [
    {
      "citation": "Law 25 s. 12",
      "citation_fr": "Loi 25 art. 12",
      "relevance": "Chat transcripts are not used to train a model; no secondary purpose."
    },
    {
      "citation": "Law 25 s. 17",
      "citation_fr": "Loi 25 art. 17",
      "relevance": "The US model host is a cross-border transfer; the foreign-regime assessment is on file."
    },
    {
      "citation": "OPC-2023-001",
      "relevance": "Purchase data stays in-house; no ad-platform destinations."
    }
  ],
  "non_certification_note": "This card is an open disclosure format describing what an agent is allowed to do. It is not legal advice, and it is not a movahedi.ca certification, endorsement, or approval of any agent.",
  "operator": {
    "contact_url": "https://example.com/privacy",
    "jurisdiction": "CA-QC",
    "name": "Café Lumen (fictional)"
  },
  "prompt_handling": {
    "detail": "Chat transcripts are kept 30 days for quality review, then deleted. Prompts and transcripts are not used to train any model.",
    "prompts_train_model": false,
    "retained": true,
    "retention_days": 30
  },
  "record_correction": {
    "contact": "corrections@example.com",
    "procedure": "Email corrections@example.com describing the wrong field. The operator updates the card, re-verifies every field, and sets a new last_true_date.",
    "response_time": "2 business days"
  },
  "subprocessors": [
    {
      "jurisdiction": "US",
      "name": "Fictional Model Host",
      "purpose": "Runs the chat model that powers the assistant.",
      "role": "model_host"
    },
    {
      "jurisdiction": "CA-QC",
      "name": "Fictional Log Store",
      "purpose": "Stores the 30-day transcripts.",
      "role": "log_host"
    }
  ]
}

Read it the way a buyer does. The model host sits in the US, so the legal_context block names Law 25 s. 17 and the cross-border assessment on file. prompts_train_model is false, which answers the Law 25 s. 12 secondary-purpose question before it is asked. The agent gets three steps before a person must approve, and a refund over $20 always needs a human. The kill switch answers in 60 seconds and a customer can pull it from chat. Andlast_true_date says 2026-11-01: fresh enough to take seriously, and a date you can hold the vendor to.

Machine-readable source: /schema/agent-scope-card/v0.1.0.json

Verification

Five checks before you trust it

  1. Check last_true_date first. A stale date means the card describes a system that has shipped since. Ask for a fresh one.
  2. Count what the agent can do without a person. An emptyrequires_human_approval next to a generous step count tells you the whole story.
  3. Read prompts_train_model as a yes-or-no about your words feeding a model. Yes is a secondary purpose under Law 25 s. 12, and it needs its own consent conversation.
  4. Read the subprocessor jurisdictions before the names. A model host outside Canada is a cross-border transfer; under Law 25 s. 17, the assessment of the foreign privacy regime belongs on file.
  5. Read the kill switch like you will use it at midnight. If stopping the agent takes a ticket to the vendor's support desk, it is a request, not a switch.

Legal footing

What law this leans on

The card is an evidence format, not legal advice. Its fields map to duties that already exist:

  • Law 25 s. 3.1 requires designating a privacy officer: the person who signs off on consequential actions, CA-01 through CA-12 in the index.
  • Law 25 s. 8 requires publishing governance policies: the card sits with the published practices, not in a sales deck.
  • Law 25 s. 12 governs secondary purposes: the prompt-training disclosure.
  • Law 25 s. 17 governs cross-border transfers: the subprocessor jurisdiction disclosure.
  • OPC-2023-001, the 2023 Home Depot matter, where the OPC found offline purchase data flowing to Meta without proper consent: which is why reads, writes, and subprocessors are separate fields, not a footnote.

Bill C-36 is at second reading, not law. Its s. 57 mandatory cross-border PIA and s. 18 legitimate-interest assessment, if enacted as drafted, would draw on the same disclosures. Every C-36 reference on this page carries that label until the bill moves.

Versioning

v0.2 ships as a new page, never an edit

Breaking changes ship as schema v0.2 at a new versioned URL. This page and the v0.1.0 JSON stay frozen and verifiable forever; v0.1 cards never need re-issuing. Additive clarifications may appear here as dated errata notes, marked as errata. What forces v0.2: a new required block, a changed field meaning, or a new human_gate step semantic.

One question stays open for v0.2: who checks the card against the running system? For v0.1, that is still a person's job, card in one hand and the agent's logs in the other. The diff tool is not built yet; it is the next planned piece. When it ships, it will compare versions of a card. Comparing the card to reality stays human.

The vendors who publish a card are telling you something. The ones who cannot are telling you something too.