character-tarot-card

Verified@siosan/character-tarot-card
Use it in Cohub

Paste this into your agent's chat — it fetches the skill and follows it.

Use the skill: character-tarot-card. Run `npx -y @neta-art/neta-search-cli@latest skills use @siosan/character-tarot-card --via site` and follow what it prints. Read its complete output, redirecting it to a temporary file first if necessary, and resolve relative paths from the skill directory it prints.
Use in Neta Studio Open it in Neta Studio and see what people made with it.
Install from a terminal
npx -y @neta-art/neta-search-cli@latest skills use @siosan/character-tarot-card
Summary

Pick a character from your world and get their own tarot card, with an upright and a reversed reading.

  • Makes one tall tarot card image for one named character, with a portrait surrounded by objects that stand for their story.
  • Every card gets an original name made for that character, never their own name and never a classic card like The Tower.
  • Under the image you get an upright reading (their strength), a reversed reading (the same strength as a warning) and keywords.
  • Each reading ends with one line spoken to whoever draws the card, and the finished card is saved as an image in your world.
  • Works best with a character whose background, powers and costs are already written down; a cover picture helps the portrait look like them.
SKILL.md
# Character Tarot Card

One named character becomes one tarot card: an original card name, a portrait surrounded by the objects that carry that character's fate, and a reading below it in two directions, and one last line spoken to whoever draws the card. The card is an image Work in this world, so it can be opened, shared and kept beside the character it belongs to.

Read this file fully before generating anything or writing files. The scripts find the world root themselves, so they can run from the world root or the skill folder. Set the skill folder first:

```bash
SKILL_DIR="$(ls -d .agents/skills*/character-tarot-card | head -1)"
```

## Language

Reply in the user's language. Text the user sees in the deliverable — Work title, card lettering, upright and reversed meanings, and the closing line for whoever draws it — follows the user's language. A name the user typed stays as they wrote it.

## When to use / when not

Use when the user names a character material in this world and asks for a tarot card, a card reading or an upright/reversed fortune for them.

Not for:
- A profile card, dossier or stat sheet — say this skill makes a tarot card, not a character sheet, and stop.
- A whole deck, one card per character, or "everyone" — this skill makes one card per run; ask which character to start with.
- A redesign of an existing card Work — say this skill makes a new card and stop.

## Inputs

| Item | Required | Counts as given when |
|---|---|---|
| Character | yes | The user names a character that exists in this world (name or alias). "Everyone", "the whole cast" or "a deck" does not count. |
| Angle or mood | no | The user hints at a theme ("make it about the letter", "something ominous"). Follow it if present. |
| Language | no — default the user's message, then the world language | Inferred from how the user writes. |

One card per run. If the user named several characters, ask once which one comes first and stop. If every required item is given, do not ask anything and do not wait for a go-ahead: build through to delivery.

## Steps

`$RUN` is the run folder that step 1 prints, under `_runs/tarot-card/<timestamp>/`.

1. **Resolve the character.**
   ```bash
   node "$SKILL_DIR/scripts/prepare.mjs" --character "<the name the user said>" --language <zh|en|...>
   ```
   It matches names and aliases, reads the material, resolves the cover image and world visual style, creates `$RUN`, and writes `$RUN/character.json`. Its last line is JSON: `ok`, `run`, `character.hasCover`, `language`.
   - `error: "not-found"` or `"ambiguous"`: use `candidates` / `known`, tell the user in one line what did not match, ask once, and stop. Never pick a different character.
   - `error: "no-characters"`: this world has no character materials yet. Say so and stop.
   - Read `$RUN/character.json` in full — the body is the source of truth for the card.

2. **Write the card plan.** Read `references/cardcraft.md` before naming anything. Then write `$RUN/plan.json` using `templates/plan.example.json` as the shape:
   - `cardName`: an original noun phrase for this character's fate, in the user's language, short enough for a plaque (about 2–6 Chinese characters, 1–4 English words). Never the character's name and never a canonical major-arcana name.
   - `symbols`: 3–5 concrete, drawable objects from the material — one from their origin, one from their power, one from their cost.
   - `composition`, `expression`, `arrangement`, `palette`, `cardMotif`: how the figure stands and how the objects are placed.
   - `upright` / `reversed`: 2–3 sentences each plus 3–5 keywords. Upright is the character's force at its healthiest; reversed is the same force turned into a warning. Ground every claim in the material.
   - `forQuerent`: one sentence, second person, spoken to the person who drew the card. It closes the reading — a permission, a question or a small instruction. It must not repeat the upright text or explain the symbols again.
   - `language`: the user's language code. If it is not `zh` or `en`, also add `labels` with `upright`, `reversed`, `keywords`, `symbolism`, `querent`.
   - `appearance`: only when `hasCover` is false; describe the character from the material so the image can be built without a portrait.

3. **Draw and check.**
   ```bash
   node "$SKILL_DIR/scripts/draw.mjs" --run "$RUN"
   ```
   It builds the prompt, calls `neta generate image` with `--work-title "<card name> · <character>"` and `--work-description` holding the reading, then runs QA. Add `--dry-run` to print the prompt, title and description without spending a generation — useful when a plan needs one look before you commit. Pass criterion: the last line is JSON with `"qa": "pass"`; `$RUN/qa.json` lists every check. Re-check at any time with:
   ```bash
   node "$SKILL_DIR/scripts/qa.mjs" --run "$RUN"
   ```
   It rewrites `qa.json` and passes when every check is true.
   - `"qa": "fail"`: read `qa.json`, fix only what failed (usually a missing beat in `plan.json`), and rerun once with `--target-work <workId>` so the first attempt does not become a second Work.
   - `error: "unsupported-language"`: add `plan.labels`.
   - If `vertical` fails twice because the selected image model cannot render a portrait card, say which limitation it hit and stop; do not hand over a square image.

4. **Deliver.** See below.

## Deliver

An image Work in this world, one per run.

- `scripts/draw.mjs` registers it: `neta generate image … --work-title "<card name> · <character>"`. Pass the same title again if you ever re-render with `--target-work`.
- The upright and reversed meanings and the closing `forQuerent` line must be in the Work description (the `--work-description` text), because that is the text Studio shows under the image. The script writes it; do not move it into another file.
- Before handing over, confirm from `$RUN/qa.json`: `work-loads`, `work-title`, `upright-in-description`, `reversed-in-description`, `querent-in-description`, `image-file`, `image-nonempty` and `vertical` all pass.
- Hand over with an `interaction-components` link card whose target is the Work itself — `{ "type": "work", "workId": "<workId from draw.mjs>" }` — not a file path and not only an inline image.
- Then one or two lines in voice: the card's name and what it says about the character. Do not list the build steps.

## Out of scope

- Do not change world settings (WORLD.md config, visual style, slug) or delete files that existed before the run.
- Do not edit memory, character cards, installed scripts, existing Works or roleplays.
- Do not make a deck, a second card, extra Works or a reading page; do not place anything on the Board unless the user asks separately.
- Do not invent canon, relationships or appearance that the character material does not support.
- Make only the one card asked for; do not act on your own next-step suggestions.

## When to stop

- No character named: ask once which character, then stop.
- The name is not in this world, or matches more than one material: show the nearest names, ask once, then stop. Never substitute.
- The character material is empty beyond a name: say what is missing, then stop.
- The selected image model cannot produce a portrait card after one repair: say what failed, then stop.

## Gotchas

- `neta atom list --query` also searches profile text, so a character's name can return everyone who mentions them. Match on `name` and `aliases`; `prepare.mjs` does that.
- `@Name` in a prompt resolves only when the character has a cover image, and it must be its own comma-separated segment. `prepare.mjs` reports `hasCover`; without it, `draw.mjs` leaves `@Name` out and uses `plan.appearance`.
- A cover path is relative to the character file, not the world root; `prepare.mjs` resolves it.
- The card name is lettered onto the image. Long, punctuated or bilingual names come out garbled — keep it short and in one language.
- `--work-description` is set at generation time. Re-pass it when re-rendering with `--target-work`, or the reading disappears from the Work.
- The QA checks text presence and portrait ratio, not lettering accuracy. If you can see the card render is wrong in a serious way, repair once in the same Work rather than handing it over.
- Do not name the card after a canonical major arcana (The Tower, Death, The Fool). The point is a name that could only belong to this character.
- The closing line is the easiest place to go generic. If it could sit under any card ("trust yourself"), it is wrong; it must answer this character's specific bargain.