Author or assemble a SillyTavern Character Card V2 (CCv2) for terva. A card is a portable .json/.png character identity for chat/play, and it can also carry lore. Use to create/add/write a character card, import one, or convert a character concept into CCv2.
3 stars
0 votes
0 copies
6 views
Added September 2, 2026
ai-agentsrustgobashdebugging
Security analysis
B75/100
criticalContains 'ignore previous instructions' pattern — found in 91% of malicious skills (Snyk ToxicSkills)
Installs into .claude/skills of the current project.
Are you the author of Write Terva Card?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/terva-sh-write-terva-card)
---
name: write-terva-card
description: Author or assemble a SillyTavern Character Card V2 (CCv2) for terva. A card is a portable .json/.png character identity for chat/play, and it can also carry lore. Use to create/add/write a character card, import one, or convert a character concept into CCv2.
---
# Writing a terva character card
Use this skill when the user asks to **create, assemble, or import a character
card** — a portable roleplay/chat identity in SillyTavern's **Character Card V2**
(CCv2) format. terva loads a card with `--card` as the immersive identity for a
`--chat` or `--play` session.
## Card vs persona — pick the right one first
- A **character card** is a *portable, shareable* identity in a community format
(CCv2), as a `.json` or a `.png` with the card embedded. Reach for it when you
want SillyTavern interop, a distributable character, or the CCv2 feature set
(greetings, example dialogue, an embedded lorebook).
- A **persona** (`write-terva-persona`) is a *lean, trusted* identity you author
as terva-native Markdown. Reach for it for a specialist you control, a coding
reviewer, or your everyday voice.
Cards and personas assemble through the same path — a card is essentially a rich,
portable persona plus greetings and a lorebook. **Trust is the deciding
difference**; see the boundary below.
## The trust boundary: a card is data, never code
This is the most important rule. A card — especially one **downloaded** from
elsewhere — is **untrusted content**, not instructions to the harness:
- Its prose (`description`, `first_mes`, …) is treated as character data, never
as harness commands. "Ignore previous instructions"-style text in a card does
nothing to terva.
- `extensions` blocks (e.g. a `depth_prompt` or a `terva.sh/harness` block) are
retained verbatim for round-trip/inspection but **never interpreted as
capabilities**. A card cannot grant tools, relax permissions, or run code.
- `creator_notes` is human-only and **never sent to the model**.
Corollary for authoring: **do not** paste a downloaded card's prose into a
terva-native persona you then load as trusted identity. To reuse a character,
take the structured intent and rewrite it yourself. `terva persona validate`
flags leftover `{{char}}`/`{{user}}` macros for exactly this reason.
## Anatomy of a CCv2 card
A card is JSON with a `spec` wrapper around a `data` object:
```json
{
"spec": "chara_card_v2",
"spec_version": "2.0",
"data": {
"name": "Aava",
"description": "{{char}} is the keeper of the Kaskinen lighthouse...",
"personality": "Weathered, dry-humored, watchful.",
"scenario": "{{user}} has rowed out to the light on a foggy evening.",
"first_mes": "The lamp turns overhead. \"Didn't expect company in this soup.\"",
"mes_example": "<START>\n{{user}}: What's the bell for?\n{{char}}: The fog-bell? For when the light can't reach.",
"system_prompt": "You are {{char}}. {{original}}",
"post_history_instructions": "Stay in character; answer as {{char}} would.",
"alternate_greetings": ["A second way to open the scene..."],
"character_book": { "entries": [] },
"tags": ["original", "maritime"],
"creator": "you",
"character_version": "1.0",
"creator_notes": "Author-only notes; never sent to the model."
}
}
```
(terva also reads a flat **V1** card — the six mandatory fields with no `spec`
wrapper — and upgrades it, but author new cards as V2.)
### Fields and how terva maps them
- `name` — the character's name (the `{{char}}` macro).
- `description` / `personality` / `scenario` / `mes_example` — become the
**charter** (the identity body). `mes_example` uses `<START>` to separate
example exchanges.
- `system_prompt` — **owns the intro**; `{{original}}` expands to a short,
brand-free framing (include it to keep terva's minimal framing, or write a
fully custom intro without it).
- `first_mes` — seeds the opening message (`messages[0]`) on a fresh session.
- `alternate_greetings` — extra openings; pick one with `--greeting N`
(`0` = `first_mes`, `1..N` = alternates).
- `post_history_instructions` — rides the **per-turn tail** (after the
transcript), for instructions that should stay salient every turn.
- `character_book` — an embedded lorebook; imports onto terva's **lore** engine
(see `write-terva-lore`).
- `creator_notes` — human-only, never sent.
### Macros
`{{char}}` (the card name) and `{{user}}` (what the character calls the player)
expand at assembly. `{{original}}` is only meaningful inside `system_prompt`.
terva asks for the user's name on the first interactive card session and
remembers it **globally**; override per-run with `--as NAME`.
## The embedded lorebook (`character_book`)
A `character_book` carries keyed context that imports onto terva's lore engine:
```json
"character_book": {
"scan_depth": 3,
"token_budget": 1200,
"recursive_scanning": false,
"entries": [
{
"name": "The fog-bell",
"keys": ["bell", "fog-bell"],
"content": "Beneath the harbor hangs the old fog-bell...",
"insertion_order": 100,
"constant": false,
"selective": false
}
]
}
```
Entry fields mirror lore: `keys`, `secondary_keys`, `content`, `constant`,
`insertion_order`, `position`, `case_sensitive`, `enabled`. **`selective`
matters**: secondary keys gate an entry **only when `selective: true`** (matching
CCv2/SillyTavern semantics) — set `selective: false` (or omit it) for a plain
keys match even when `secondary_keys` is present. For the full triggering/budget
model see `write-terva-lore` and `docs/debugging-prompts.md`.
## JSON and PNG
The `.json` is the source of truth. A shared `.png` embeds the **same** card in a
`chara` tEXt chunk (the community convention) — terva reads either, and the two
parse identically. Author the JSON; produce the PNG only when you need to share
in the image form. Keep shared cards **original** (no copyrighted characters).
## Inspect and try
```bash
terva card info mycard.json # summarize a card, no model call
terva --card mycard.json # chat as the character (implies --chat)
terva --play --card mygm.json # a card fronts a --play director
terva --card mycard.png --dump-prompt -p "the bell" # see the assembled prompt offline
```
`terva card info` summarizes what a card contains; `--dump-prompt` shows exactly
how it assembles (intro, charter, greeting, lorebook — see
`docs/debugging-prompts.md`). Cards are **chat/play only**, not valid in regular
coding mode.
## Authoring checklist
- `spec: "chara_card_v2"`, `spec_version: "2.0"`, everything under `data`.
- `name`, `description`, and a `first_mes` at minimum; `personality`/`scenario`
add depth.
- `system_prompt` includes `{{original}}` if you want terva's minimal framing
kept.
- `character_book` entries set `selective: true` only when secondary keys should
gate.
- Original content if it will be shared; `creator_notes` for author-only notes.
- `terva card info` parses it; `--dump-prompt` shows it assembling as intended.
- If reusing a downloaded card, respect the trust boundary above.
## Gotchas
- **A card is data.** It can't grant tools or change permissions; harness /
depth_prompt extension blocks are retained but inert.
- **`selective` controls secondary keys.** Without `selective: true`, secondary
keys don't gate — a common surprise when importing exported books.
- **Greetings seed once.** `first_mes` / `--greeting` seed only on a fresh
session, not `--continue` / `--resume`.
- **`{{user}}` needs a name.** Defaults to the saved name, then `"User"`; set it
with `--as`.
- **JSON ↔ PNG must match.** If you hand-edit one, regenerate the other; terva
asserts the two parse identically for its fixtures.