Diagnose probes each of 8 tracker tables and 4 world-sim tables with a synthetic write/read/cleanup using a sentinel chat_type — free, ~1s. Pipeline test enqueues a real tracker job, waits for the worker to extract via Haiku, then exercises continuity + consequences + NPC sim. Costs roughly $0.001 per run.
Voice (Piper + Whisper via VOICE_API_URL), tracker job queue, scheduler overdue reminders, Billing SQL. Deploy latest Forge for /api/repair/system/*; older builds fall back to voice proxy only.
Observability for the Director-pipeline retrieval path (plan.txt §10): pre-retrieval pool size + embed latency, rerank fallback rate + latency p50/p95, World State budget-pass drops. Read-only — no fix counterpart. Only meaningful when forgeDirectorEnabled is on for at least one session.
hexgrad/Kokoro-82M (StyleTTS2) on HAL at BOT_KOKORO_URL (default :8092,
GPU 2). Deterministic — only voice + speed tune it. Long text is auto-split into chunks,
synthesized, then stitched into one continuous file. Ctrl+Enter to synthesize.
Drop or pick multiple .txt files. Each becomes its own audio file — same name,
new extension — all bundled into one kokoro-batch.zip.
Resemble AI's open-source TTS. Voice clone from a short reference clip, with expressive
emotion control. Expected on HAL at BOT_CHATTERBOX_URL
(default :8093). Backend proxy:
packages/forge/src/chat/voice-routes.ts.
A character card is everything an AI roleplay model needs to play a character convincingly — who they are, how they speak, where the story begins, what to remember, and what rules to follow. The Card Editor stores all of it in the Character Card V3 (CCv3) format so it round-trips with other tools.
The Editor's tabs map to roughly the same groups you'll see in this handbook:
When the AI generates a reply, all these fields are concatenated into one prompt. The model weighs things at the bottom more heavily than things at the top. Instructions near the very end essentially override instructions near the beginning.
systemPrompt (top of context — weakest)descriptionpersonalityscenariomesExamplepostHistoryInstructions (bottom — STRONGEST)Practical consequence: if a tone or pacing rule keeps drifting after long conversations, move it to postHistoryInstructions. If you put it in systemPrompt it will get steamrolled by everything below it.
A quick decision table for "I want to capture X — which field?"
| You want to capture… | Put it in… |
|---|---|
| A trait that's always true about the character | description (or split out to personality) |
| What the opening scene looks like — where, when, mood | scenario |
| The character's actual opening line / action | firstMes |
| A demo of how they speak under different moods | mesExample |
| Writing rules for the AI (POV, prose style, content limits) | systemPrompt |
| The 3–5 most critical reminders that must not drift | postHistoryInstructions |
| World details that only matter when a topic comes up | Lorebook entry |
| Information that should be true every turn forever | Lorebook entry with constant: true |
| An automatic reaction to a keyword the user types | Trigger (on_user_send + inject_system) |
| A note to yourself about the card | creatorNotes (never sent to the model) |
Short factual fields — don't put personality or instructions here.
{{char}} macro. Keep it short. A long full name like "Sir Reginald Ashworth III, Knight-Captain of the Western Reach" will appear in every dialogue tag.characterVersion when you revise the card lets users know.These three are in context every turn, so they have to earn their keep. Total budget across all three: about 2000 tokens. Less is better.
The single most important field. Cover five categories, in roughly this order:
mesExample)Use prose for large models (Claude) or PList style for tight contexts. Do not put AI writing instructions here — those belong in systemPrompt.
Brief trait summary or PList. You can fold this into description if you prefer — splitting it out is mainly useful when you want to swap personalities without touching the rest of the card.
The stage setting for the first interaction. Where are we, what's happening, what is the character's relationship to {{user}} right now? NOT backstory. NOT world lore. Just the opening situation.
Writing instructions for the AI — not character facts.
POV, prose style, content rules, genre conventions. Sits at the top of context, so it's the weakest position. Use {{original}} as a placeholder to supplement (rather than fully replace) the platform's default system prompt.
The most powerful field in the whole card. Injected right before the model generates, so nothing follows it. Use it for the 3–5 behavioral anchors most likely to drift over a long conversation: voice consistency, pacing, prose-quality reminders.
Keep it lean — 50–150 tokens. Bigger isn't better here; the strength comes from its position, not its length, and verbosity dilutes the signal.
The AI mimics the length, tone, prose quality, and pacing of the first message throughout the session. So write it at full quality. A short, dry first message will produce short, dry replies for the rest of the chat.
A good first message includes:
Variations on the opening — different scenes, emotional states, entry points. The user can swipe between them when starting a chat. Two or three good alternates beat ten okay ones.
mesExample)2–3 demonstration exchanges using <START> as a separator. Each block is independent — not a continuing conversation. Show different facets of the character, not the same beat three times:
Format:
<START>
{{user}}: Where were you yesterday?
{{char}}: *doesn't look up from the map* Out.
<START>
{{user}}: I made you tea.
{{char}}: *softly* You didn't have to.
The model uses these as voice samples. If you fake a character voice here, the AI will fake it everywhere.
Dynamic world knowledge — only injected into context when keywords match recent messages. This is how you keep the base context lean while still having access to deep lore on demand.
If a fact is always true about the character → put it in description. If it only matters sometimes → put it in the lorebook.
One location. One NPC. One event. One world system. Don't bundle.
The content can start with @@ lines that get stripped before injection:
@@depth:N — inject at depth N in history (0 = right before generation, strongest)@@activate_after_turn:N — only activate after N user messages@@keep_activate — once triggered, stays active for the rest of the session@@constant — always active (equivalent to constant: true)@@exclude_keys:[k1,k2] — suppress if these keywords also appearconstant: true; content: facts that should color every interactionDynamic story responses fired by pattern matching against messages. Each trigger has an event (when), a condition (what pattern), and an action (what happens).
| Event | Fires when… |
|---|---|
on_user_send | The user's message matches the condition pattern |
on_ai_response | The AI's reply matches the condition pattern |
on_chat_start | A new conversation begins (no condition needed) |
| Action | What it does |
|---|---|
inject_system | Inserts actionData as a system message into context |
toast | Shows actionData as a UI notification |
auto_reply | Auto-sends actionData as if from the user |
set_pref | Changes a user preference key (advanced) |
swap_persona | Switches to a different alternate persona |
/\bhello\b/i is an explicit regex; hello on its own is a substring match.on_user_send + pattern /(?:leave|head out|go outside)/i + inject_system with "The scene moves outdoors. Describe what {{char}} notices first."on_ai_response + pattern matching an NPC's name + inject_system reminding the model of the NPC's current mood.on_chat_start + pattern .* + inject_system "Open on a small action that establishes {{char}}'s tells before the first line of dialogue."Triggers create story momentum: scene transitions, NPC reactions, world events, atmosphere shifts. They aren't replacements for character traits.
Use these placeholders everywhere instead of hardcoding names. The platform substitutes the right values at runtime, so the same card works for any user / persona / pairing.
{{user}} — the human's persona name{{char}} — the character's name{{original}} — the platform's default system prompt (use this in your systemPrompt to append to it rather than replace it)description. Description is character facts. Writing rules go in systemPrompt or postHistoryInstructions."he", "the", "city" match on every turn and burn the lorebook budget. Use specific names.postHistoryInstructions. Its strength comes from position, not length. Past ~150 tokens the model starts ignoring half of it.firstMes. The model copies its style for the whole session. Invest here.{{user}} / {{char}}. Breaks personas and gender swaps.scenario. Scenario is the opening situation; backstory belongs in description or in a lorebook entry triggered by relevant names.Ask the assistant in to draft any section for you, or to critique what you've written — it has the same reference material you just read.
Ask Forge to help draft, rewrite, or critique the card on the left.
| ☐ | Name ▲ | Visibility ▲ | Rating | ★ ▲ | Source ▲ | Creator ▲ | Tags | Updated ▼ |
|---|
Click to load reports...
Click to load moderation queue...
Click to load world moderation queue...
Each role tries models top-to-bottom. Drag to reorder. First available provider with a key is used. OpenRouter, Together, Groq, Fireworks, DeepInfra API keys are set here only — they are not duplicated under System Settings.
Live remaining credit per provider. Cached for 5 minutes — click Refresh to bypass cache. Only OpenRouter exposes a balance API; other providers show their dashboard link.
| Role | Models (priority order) | Actions |
|---|---|---|
| Loading... | ||
Each Kokoro voice has its own saved chunk size and max parallel /api/chat/voice/kokoro requests (audio still plays in order). Choose a voice from the list — sliders jump to that voice’s saved values, or to Default until you save a profile for it.
Subscribers’ effective max parallel is also capped by subscription tier (maxTtsParallelRequests in src/config/tiers.ts: free 2, pro 8, premium unlimited).
Legacy preset + word-count rules from older configs are preserved server-side but not edited here.
Open this section to load voices…
No saved profile for this voice yet — sliders match Default until you Save.
Anthropic, OpenAI (images/TTS), search, email, Twilio account credentials, and performance. Multi-provider LLM keys (OpenRouter, Groq, …) live under AI Models & Providers above; all Stripe keys & products live under Payments below — not here.
Messages pop up centered on screen after login. "Once" messages are tracked per user server-side; "every login" messages repeat until deactivated. Audience: everyone, one tier, or named users.
pg_dump of every cluster DB (VoidIO-PG-Backup, 4am). The list below shows the real backups.Everything Stripe, in one place: account keys & webhook secret, Forge subscription Price IDs, checkout options, and the multi-app system (register apps, mint API keys, usage markup, credit balances, per-app Stripe prices, and per-app revenue & usage).
Sideload on Android: enable “Install from unknown sources” in your device settings, then open the downloaded APK.
Used on usage reports and billing — separate from your public creator display name.
When enabled, anyone can open and see your display name, bio, and characters you have marked public or published to Community.
Controls which characters appear in Community and Online search.
Treats your owner account like a normal user for moderation, so you can test the gated experience: your published characters run the Tier-1/Tier-2 moderation scan, chat messages run the full input gate, adult content requires the 18+ confirmation, and the owner-only “Uncensored” model group is hidden. Untick to restore the full owner bypass — chat input is then screened only for sexualized-minor content, which always applies to every account.
The "Welcome to Forge" window with the demo-chat button shows on every visit unless this is checked.
Ask the AI to wrap actions and narration in *asterisks*, shown as dimmed stage direction so it reads apart from speech. A character card with its own style instructions still wins.
Automatically extends AI responses truncated by the token limit (max 3 times).
Receive a weekly summary of your usage stats, top models, and activity by email (Sundays 6 PM).
Get a notification when someone follows you or comments on one of your characters — even when Forge isn't open. Install Forge to your home screen for the best experience.
If the pause option is off: Edit first never auto-sends; Send when done sends as soon as dictation finishes. If the pause option is on, Forge waits for that much quiet time after you stop typing, then sends (only if the message is not empty).
StyleTTS2-based 82M-param model on HAL (the GPU rig). Deterministic — no sampling. Leave the voice blank to use the character card’s default (falls back to af_heart).
Hide characters from your browse and search results by creator, character, tag, or keyword. Only affects what you see; your own library (My Characters) is never filtered.
Pill buttons above the input. Click to send instantly.
Card details and invoice history are stored by Stripe — never by Forge. Updates and cancellation happen in the portal.
Upload text or markdown documents. Content is chunked and searchable by AI tools during conversations.
Controls what the LLM sees each turn. Older messages stay in the chat for you to read but are not sent to the LLM — a rolling summary stands in for them.