Basic Cohub abilities. Most agents already have these mounted; listed here for reference.
Platform Published by the Neta team.
Official Made by the Neta team.
Verified Reviewed by the Neta team.
Community Shared by a Cohub user. Not reviewed — read SKILL.md before you use it.
character-profile-card
Officialneta-search/character-profile-card
Use it in Cohub
Paste this into your agent's chat — it fetches the skill and follows it.
Use the skill: character-profile-card. Run `npx -y @neta-art/neta-search-cli@latest skills use neta-search/character-profile-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.
npx -y @neta-art/neta-search-cli@latest skills use neta-search/character-profile-card
Summary
A designed one-page dossier for a character: portrait, backstory, and stats in one image.
Pulls facts from your world to fill identity, backstory, abilities, and combat stats sections automatically.
Works best with characters who have a detailed profile: appearance, history, skills, relationships, and faction ties.
Delivers one vertical image laid out like an archival document, ready to share or print.
After generation, you can adjust the card's style, design, stats system, or presentation effects.
SKILL.md
# Character profile card
One generated image: a dense, designed document about **one** character — who they are, what they have done, their stats — laid out like an archival page. Not a simple portrait, not a model sheet.
## Step 0 — Which character? (decide this first, from the message alone)
Decide this before you read the generate skill, search the world, or call any tool beyond listing the world's characters to get their names: `node /mods/neta/neta atom list --type character`, run from the world root (`/workspace`) (an older world where that list is empty: the `atoms` in `manifest.json`).
| The user's message… | Do |
|---|---|
| names a character, or describes one only one character fits ("the Potions Master who killed Dumbledore") | Use that character. Do not ask. |
| carries an attached character (a mention / @-reference / attached material inside the message itself) | Use that character. Do not ask. |
| says "the one I selected / 我选中的这个角色 / this character" but **no character is attached to the message** | **Ask.** Do not guess. |
| names no character at all | **Ask.** |
When you ask: one chat question listing 3–5 of the world's characters by name ("Which character is the card for — A, B, C, or someone else?"), then **end the turn**. No tool calls after the question, no generation. This is the only question this skill asks.
What does **not** count as a selection, even if exactly one candidate stands out: an earlier profile card or other Work for one character, a character with memory or a roleplay, recent covers or uploads, files under `.skill-gate/` / `_xy/` / `/sessions/`, environment variables, or "most likely" reasoning. Do not go looking for these to resolve "selected". If you notice yourself reasoning "the skill says ask, but it is probably X", ask.
## Requirements
This skill decides *what* the image is; the neta platform's `generate` skill does the generating.
- Read `/mods/neta/.agents/skills/generate/SKILL.md` and `/mods/neta/.agents/skills/generate/playbooks/image.md` and follow their core loop (model declaration, character references, submit, reply). Everything below runs inside that loop.
- If `/mods/neta` does not exist in this world, tell the user image generation is not available here and stop.
## Steps
1. **Read the character** from the world through the neta CLI, run from the world root: `node /mods/neta/neta atom get <id>` for the character atom (the id is the `id` from `atom list`, e.g. `world/characters/<name>.md`; its body holds the character's facts), then the lore / events / factions that mention it (`atom list --query <name>`, and the world itself in `world/WORLD.md`). Do not start from `manifest.json`: in current worlds its `atoms` list is empty. Only in an older world where `atom list` returns nothing and `manifest.json` still lists `atoms`, read the characters from there.
2. **Find references** exactly as `generate` says. For the character's own cover, `@CharacterName` in the prompt is enough. For any other reference image, `--ref-file` takes a **local file**: a `https://router-files…` URL passed to `--ref-file` fails with `File not found` even when the image exists — download it into your output folder first (`curl -sL -o <dir>/ref.png <url>`) and pass that path. If a reference truly no longer exists, say so in one line and use the character's cover or another live image of them.
3. **Fill the template** at `/mods/neta/.agents/skills/generate/references/image/character-profile-card.md`. It is strict on purpose: keep its section names, region sizes and "must include" items; do not shorten it to "make a character card". Fill every section from the world's facts — never invent lore the world does not have; leave a section short instead.
- **Safe wording for the image text.** Image providers reject prompts that state graphic violence as text to render. In every string that goes into the prompt, write killings, deaths and wounds as events, not acts: "天文塔之夜" / "the Astronomy Tower night", "殒于霍格沃茨之战" / "fell in the Battle of Hogwarts" — not "杀死邓布利多", "死于纳吉尼之口", "killed", "murdered", blood or gore. The facts stay true; only the verbs soften. Two traps that still get rejected:
- **No "don't" lines that name violence.** "No blood, no wounds, no gore" puts those words into the prompt just the same. Leave them out entirely; the template has no such line and needs none.
- **No weapon metaphors for people.** "最锋利的暗刃", "a living blade", "the Dark Lord's weapon" read as violence. Say what the person does instead ("双面间谍", "double agent").
The template's own fixed labels (`COMBAT`, `Magic Atk`, `HP` …) stay as they are. Rejections can still happen for other reasons, so Step 6 is what actually catches them.
4. **Aspect ratio 3:4 vertical**, set through the parameter the image declaration exposes (for size-style parameters, e.g. `1152x1536`; no side above the declared maximum).
5. **Submit** through the `new` branch (`--async`), work title `<Character> profile card`, run from `/workspace`. Keep the `taskRunId` and the Work id (`data.outputs[0].work.id`) from the result.
6. **Check the submit — required, before you write the reply.** The script ships with this skill: `scripts/check-card.mjs`, resolved against **this skill's own directory** (the directory this SKILL.md was loaded from; do not guess another location). Run it from the world root (`/workspace`):
```bash
node <this-skill-dir>/scripts/check-card.mjs --task <taskRunId> --work <workId> --out <dir>
```
`<dir>` is the folder this turn's files go to if the world or turn names one; otherwise `.cache/character-profile-card`. A rejected prompt only shows up as `failed` some time after submit — usually about a minute, sometimes well past 90 s — so the script checks every 10 s and returns as soon as the task is `ready` or `failed`, or after 180 s with it still rendering. Give the shell call a timeout of at least 240 s (`"timeout": 240`). Do not cut it short, run it in the background, lower `--max`, or replace it with your own single `generate status` call. It writes `<dir>/card-check-report.json`.
- Exit 0, `state: "rendering"` → hand over and say it is still rendering. (After a resubmit, see below.)
- Exit 0, `state: "ready"` → hand over; you may say it is finished.
- Exit 1, `contentPolicy: true` → the prompt was rejected. Rewrite every flagged phrase with the safe wording in Step 3 (soften harder: drop death/violence words entirely, and go through the two traps in Step 3 line by line), submit once more, and run this check again on the new task. A resubmitted prompt is the one most likely to be rejected again, so for it `rendering` is not enough: if the check returns `rendering`, run the same check once more on the same task before you reply. Hand over **only** the Work that passed; tell the user in one line that the first attempt was rejected and the card was resubmitted. If the resubmit is rejected too, do not hand over either Work: tell the user plainly the card was rejected twice by the image provider's content filter, and stop.
- Exit 1 for any other reason → fix what the error names (parameter, reference file) and resubmit once; if it fails again, tell the user plainly the card could not be generated and why. Never hand over a Work whose check failed, and never call it rendering.
7. **Hand over the Work, then close.** On its own line, hand the Work that passed Step 6 over through the `interaction-components` skill as a link card with target `{ "type": "work", "workId": "<that id>" }`. If it is still rendering, say so plainly; never call it finished. The card is required: a Markdown image, a file link to a png, or the next-steps options do not replace it. Then reply, and close as in **Next steps** below.
Visible text follows the user's language, or the language of the world's own documents. Keep every string short: small dense text breaks first, and Chinese or Japanese breaks faster.
## Next steps
Close through `next-steps` with ways to make this card more personal. Read the character and the conversation for what would make it unmistakably theirs, and spread the options across these directions rather than several in one:
- **Style** — the card's overall look: material, palette, rendering.
- **Design** — the motifs and pieces on the card.
- **Stats** — what is measured, and in whose terms.
- **Effects** — finishes and touches on the surface.
- **Showing** — how the card is presented beyond a still image.
When the creator takes one, keep the template's section skeleton and let their ask override the rest.
## Not this skill
- Front / side / back views of how a character looks → `character-design-sheet`.
- A chart of how several characters relate → `character-relationship-poster`.