# Cops Npc To Notion

> Use when inserting or updating a finished COPS NPC inside the Notion casting database, preserving the exact markdown NPC sheet and mapping properties only when the schema really supports them.

- Skill: `ludofleury/cops-npc-to-notion` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add ludofleury/cops-npc-to-notion`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ludofleury/cops-npc-to-notion/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: ludofleury (https://skillmd.com/u/ludofleury)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/ludofleury/cops-npc-to-notion

---


# COPS NPC To Notion

This skill writes a finalized COPS NPC into Notion without `Make`.

Use the Notion app tools directly.

Known target database:

- Database URL: `https://www.notion.so/221333cad96d40618adcc5b76cdbdd3a`
- Data source URL: `collection://33bd73cc-a14d-4fe0-bce6-cb5ea57bfb0c`
- Database title: `Cast`

Use this skill when the user wants to:

- insert a new NPC into the casting database
- send a generated NPC sheet to Notion
- update an existing Notion NPC page from a finalized markdown sheet
- publish an approved NPC portrait alongside the NPC data
- publish first, then continue directly into a portrait proposal flow

## Preconditions

The NPC must already exist in a near-final or final markdown form.

If the user still needs the NPC generated or rewritten, use `$cops-npc-generator`
first, then come back to this skill.

If the user wants an approved portrait attached in Notion, it must already have gone
through `$cops-npc-photo` and been explicitly approved.

Before writing anything, read
[references/notion-insert-playbook.md](references/notion-insert-playbook.md).

## Hard rules

- Do not insert partial NPC data.
- Do not duplicate structured NPC data inside the page body.
- Preserve `Quote`, `Items`, `Cool`, `Uncool`, `Affiliation`, and `Photo`.
- Preserve the validated status of the approved portrait; do not swap images during publish.
- Do not guess Notion property names.
- Do not change the database schema unless the user explicitly asks for it.
- If the database search is ambiguous, stop and ask for the database URL.
- If an exact NPC page already exists and the user did not say whether this is an
  update or a duplicate, pause and ask before overwriting.

## Workflow

1. Validate that the NPC sheet is complete.
2. Determine whether this is:
   - publish only
   - publish with already approved portrait
   - publish then launch a first portrait proposal
3. Use the known `Cast` destination in Notion.
4. Fetch the destination and inspect the real schema and `data_source_id`.
5. Prepare properties using only exact schema matches.
6. Create or update the page with structured properties only.
7. If there is an already approved portrait and the current tool path can truly write it into `Photo`, do it.
8. If this is a newly created NPC and the user did not explicitly skip portraits, hand off immediately to `$cops-npc-photo` for a first proposal.
9. Return the created or updated Notion URL and summarize what was mapped to properties.

## Database lookup policy

Prefer the known database URL:

- `https://www.notion.so/221333cad96d40618adcc5b76cdbdd3a`
- data source: `collection://33bd73cc-a14d-4fe0-bce6-cb5ea57bfb0c`

If that target fails or has changed:

1. search Notion for `Cast`
2. if needed, try nearby variants such as `casting`
3. inspect the most plausible result with `fetch`
4. confirm the correct data source if the database has more than one

If you cannot uniquely identify the database, ask the user for the URL instead of guessing.

## Property mapping policy

Always set the title property using the exact NPC display name.

Use the real `Cast` schema directly.

Write these mappings by default:

- `Nom complet` (`title`): full NPC display name from the markdown header
- `Prénom` (`text`): `first`
- `Nom` (`text`): `last`
- `Alias` (`text`): `alias`
- `Genre` (`select`): exact value from `Gender`
- `Ethnie` (`multi_select`): exact value from `Ethnicity`
- `Age` (`number`): numeric `Age`
- `Niveau de vie` (`select`): exact value from `Social`
- `Education` (`select`): normalized `Education`
- `Occupation` (`text`): `Occupation`
- `Background` (`text`): the full `Background` block as plain text
- `Citation` (`text`): both quotes joined with line breaks
- `Inventaire` (`text`): both `Items` joined with line breaks
- `Cool` (`text`): both `Cool` entries joined with line breaks
- `Uncool` (`text`): both `Uncool` entries joined with line breaks
- `Leitmotiv` (`text`): track label, plus URL when one exists
- `Résidence` (`text`): address plus district note in one text value
- `Caractéristiques` (`text`): full characteristics block plus total points
- `Compétences` (`text`): full skills block as plain text lines

Handle these special cases explicitly:

- `Education`: map any higher-education variant from the NPC sheet to the real
  existing option `Études supérieures`
- `Ethnie`: the generator produces one ethnicity, but the property is
  `multi_select`; with the current connector, send it as a single exact string
  value such as `Arabic`, and Notion will store it correctly
- `Alias`: if the sheet says no alias, set the property to `null`
- `Leitmotiv`: if the markdown contains a link, keep the human-readable track in
  the property only
- if the leitmotiv URL is missing or unverified, store only `Track by Artist`
- never store placeholder or guessed URLs in `Leitmotiv`
- when a verified URL exists, prefer `YouTube Music`, then `YouTube`, then `Spotify`
- `Résidence`: there is no dedicated `District` property, so keep district
  inside `Résidence`

Do not write these properties from the NPC generator output unless the user gives
extra data that truly supports them:

- `Photo`: writable file field, but the generator only produces a photo prompt,
  not an uploaded file
- `Affiliation`: relation field; resolve only exact existing Notion entities
- `Matricule`
- `Permis`
- `Référence`
- `Signes distrinctifs`
- `Statut matrimonial`
- family and timeline relations such as `Parents`, `Enfants`, `Conjoint`,
  `Contacts`, `Timeline`, `Naissance`, `Décès`, `Casier judiciaire`, `Evidences`,
  `Spots`

Never try to write formula, rollup, or other derived fields such as:

- `Année de naissance`
- `Sécurité Sociale`
- `Dossiers`
- `Implications`
- `Stories`
- `Né le`
- `Né à`
- `Mort le`

If a field has no safe writable target, keep it in the page body only.

## Photo policy

If a portrait is part of the request:

- require one approved final image, not just a prompt
- prefer writing that image into the `Photo` property only if the current tool
  path supports a real upload or supported file reference
- if the current tool path does not support that upload, stop and tell the user
  exactly that the portrait is approved but not yet attached in `Photo`
- do not silently downgrade the portrait into body text
- do not silently use a different image than the approved one

If the request is `publish then propose portrait` rather than `publish approved portrait`:

- do not block the Notion insert on image approval
- create or update the Cast page first
- then invoke `$cops-npc-photo` immediately with the finalized sheet and the fresh page context
- default to one first proposal image after publish unless the user asked for prompt-first review
- make clear that the proposed image is not yet attached in Notion until the user validates it

## Relation handling

`Affiliation` points to the data source `collection://e1137024-a8aa-497d-9eb8-3fd4a1a4a0d1`.

When the NPC sheet includes affiliations:

1. extract each named organization from the `Affiliation` block
2. search the affiliation data source for an exact title match
3. write the relation only for exact unambiguous matches
4. if a match is missing or ambiguous, leave the relation empty

## Content policy

The page body must stay free for future notes.

When creating the Notion page:

- default to an empty page body
- do not paste the NPC sheet into the content
- do not copy structured property values into the content
- only write page content if the user explicitly asks for free-form notes or bio text
- if the page already contains free-form notes, preserve them unless the user asks otherwise

## Output

After the write succeeds, tell the user:

- whether the page was created or updated
- the Notion page URL
- which properties were mapped
- which details were kept only in the body

