Quilltap 4.2.0
The characters have learned to dress themselves. The Dressing Room tore out its own walls and rebuilt them simpler. The Salon acquired a wardrobe — a real one, with drawers and hangers and the kind of quiet authority that comes from knowing exactly what you're wearing and why. And the word "persona," which had been skulking around the codebase since the early days like an uninvited guest who refuses to leave, was finally shown the door.
There is a difference between a costume and a wardrobe. A costume is a decision made once and worn until the curtain falls. A wardrobe is a system — composable, contextual, alive to the scene. A character who owns a costume plays a part. A character who owns a wardrobe inhabits one.
Quilltap 4.2 gives every character a wardrobe.
Not a description field. Not a clothing record pasted into a system prompt like a stage direction no one reads after the first act. A modular, composable, persistent inventory of individual garments — tops, bottoms, footwear, accessories — that characters can browse, change, create, and gift to one another, mid-conversation, with the LLM making the decisions a person would make about what to put on and when.
The wardrobe system is the largest single feature Quilltap has ever shipped. It touched the database, the API, the tools, the system prompt builder, the image generation pipeline, the scene state tracker, the backup system, the import/export format, and every theme. It added three new LLM tools. It introduced outfit presets, an archetype library, per-conversation avatar generation, wardrobe import from photographs, AI-generated wardrobe items during character creation, gifting between characters, and an outfit change notification system that lets you tell the room what just happened with a single button press.
But before we get to the wardrobe — because the wardrobe is large and deserves its own wing of this document — we should talk about the two architectural changes that cleared the ground for it.
The Dressing Room Simplifies Itself
Roleplay Templates: From Plugins to JSON
Aurora's roleplay template system had been built on the plugin architecture. This was, in the way of many early decisions, technically correct and practically burdensome. To create a roleplay template — to define how narration, dialogue, and action text are delimited and styled — you needed to write a plugin. You needed npm. You needed TypeScript, or at least the patience to pretend you did. The ROLEPLAY_TEMPLATE plugin capability existed, the builder utilities existed, the registration pipeline existed, and all of it existed to do something that is, at its heart, a JSON object with a list of delimiters and a name.
Quilltap 4.2 replaces the entire plugin-based template architecture with a native JSON system. Templates now carry a delimiters array — each entry specifying a name, a buttonName for the formatting toolbar, the delimiters themselves (open and close characters), and a style for rendering. The old annotationButtons column has been renamed. The pluginName column has been dropped. The ROLEPLAY_TEMPLATE capability has been removed from the plugin type system entirely. A database migration rewrites all existing plugin:quilltap-rp references to a built-in template UUID, and the built-in "Quilltap RP" template sits alongside "Standard" as a first-class citizen that requires no plugin infrastructure to exist.
The create and edit dialog now includes a full delimiter array editor — add, remove, configure — and rendering patterns are auto-generated from delimiter definitions, so custom templates get proper text styling without anyone needing to write regular expressions by hand. Import handles backward compatibility with the old annotationButtons format.
The @quilltap/plugin-types and @quilltap/plugin-utils packages have been updated accordingly. The roleplay template builder utilities are gone from the main exports. The types are preserved in a backward-compatible path for existing code that imports them, but new work should not reach for them. They are, in the language of the Estate, retired staff — still listed in the directory, no longer expected at breakfast.
The Word That Wouldn't Leave
The codebase has carried the word "persona" since before the plugin system, before the Commonplace Book, before the Estate had a name. It referred to user-controlled characters — the ones you play, as distinct from the ones the LLM plays. Over time, the concept was absorbed into the broader character system, but the terminology persisted: persona in the message pipeline, personaName in memory extraction, PERSONA as a character type, getFirstPersona in salon hooks, --qt-badge-persona-* in every CSS theme. The word was everywhere and meant nothing that "user character" did not already mean better.
Quilltap 4.2 removes it. Comprehensively. persona becomes userCharacter across the entire message pipeline — types, orchestrator, context builder, system prompt builder, template processor. personaName becomes userCharacterName. getFirstPersona becomes getFirstUserCharacter. addPersona and removePersona become addPartnerLink and removePartnerLink. The deprecated findByPersonaId is gone from the memories repository. Every CSS badge variable has been renamed across all five bundled themes, the Storybook, and the create-quilltap-theme template. The database migration renames characters.personaLinks to partnerLinks and drops memories.personaId.
The {{persona}} template variable survives, because SillyTavern import/export compatibility is a promise, not a preference. Everything else is gone. The guest has left the building.
The Wardrobe
What It Is
Every character now owns a composable wardrobe of individual garment items stored in a new wardrobe_items database table. Each item has a title, a description, one or more type tags (top, bottom, footwear, accessories), and an appropriateness field for context. Items belong either to a specific character (personal wardrobe) or to no one in particular (the Archetype Library — shared items available to any character, like a house costume collection).
Each chat tracks an equipped outfit per character — which top, which bottom, which footwear, which accessories are currently worn. This is character state in the fullest sense: it persists across the conversation, it's visible to other characters, it informs image generation, and it changes when characters change their clothes.
What Characters Can Do
Three new LLM tools give characters agency over their appearance:
list_wardrobe retrieves available items on demand, filtered by type and appropriateness, including outfit presets. The wardrobe is not injected into every system prompt — it's retrieved when needed, keeping token costs proportional to use.
update_outfit_item equips or removes items by slot. It handles multi-type displacement correctly: equipping a new top when a dress (covering both top and bottom) is worn will clear both slots the dress occupied. Outfit presets can be applied in a single call via preset_id.
create_wardrobe_item lets a character author new garments mid-conversation — describe a dress they just bought, conjure armor from thin air, improvise a disguise. Created items persist in the character's personal wardrobe and are available in future chats.
Two character flags — canDressThemselves and canCreateOutfits, both enabled by default — govern which tools are available. For models that don't support native tool calling, text-block equivalents ([[WARDROBE]], [[EQUIP]], [[CREATE_WARDROBE_ITEM]]) provide the same functionality through stream parsing.
What Users Can Do
The participant sidebar now shows an outfit indicator for every character — user-controlled and LLM-controlled alike — with inline slot-change dropdowns for manual outfit management. Shared archetype items appear in the dropdowns with a "(shared)" label.
Gifting. Characters can create wardrobe items for other characters via a recipient parameter on create_wardrobe_item. Users can gift items via a dedicated button on each character's participant card. Because sometimes you want to hand someone a scarf without making the LLM do it.
Outfit Presets. Save named outfit combinations for quick equipping. Save the current outfit as a preset, apply presets from the wardrobe management UI or the outfit selector. A "Use Saved Preset" mode in the outfit selector resolves presets client-side as manual slot assignments.
Archetype Library. Shared wardrobe items with no character owner — Roman soldier tunics, Victorian formalwear, standard-issue starship uniforms — available to any character without copying. Create, browse, and equip directly.
Wardrobe Archiving. Soft-delete items you don't want cluttering the list but aren't ready to destroy. Archived items are hidden from lists and tools but stay equipped if currently worn. Deleting an item outright cleans up all equipped references across chats and removes it from presets.
Getting Dressed
Chat creation now includes outfit selection: default outfit, manual selection, "Let Character Choose" (a cheap LLM picks contextually appropriate items based on scenario and personality, with automatic fallback to defaults on failure), or none. User-controlled characters now get their default wardrobe items equipped automatically on chat creation — previously only LLM-controlled characters received this treatment. The bundled seed characters — Lorian and Riya — now ship with default wardrobe items, so new users encounter the system already furnished.
When outfits change mid-conversation — via the sidebar, via tool use, via gifting — a glowing "Notify 👗" pill button appears above the composer. Click it to insert the change description at the top of your message, wrapped in the current roleplay template's narration delimiters. The notification supports multiple characters and distinguishes clothing changes (equip) from wardrobe changes (gift). Notifications persist in localStorage until consumed.
All characters in the chat are informed of outfit changes on their next turn. The scene state tracker uses equipped wardrobe items. The system prompt shows a structured "Current Outfit" and "Available Wardrobe" section. Image generation receives equipped items for accurate rendering. The wardrobe is not decoration. It is infrastructure.
Wardrobe Action Notices
When wardrobe tools fire — equip, unequip, create, gift — the chat now displays a prominent inline summary in warm amber-and-gold double-border styling, so users can see at a glance what happened without parsing tool JSON. CSS variables (--qt-chat-wardrobe-*) are themeable with per-theme overrides for all five bundled themes.
Import from Image
A camera icon button in the Personal Wardrobe section header lets you upload a reference image — a photograph, a piece of artwork, a screenshot of a character from another application — and have a vision-capable LLM analyze it to propose wardrobe items. Upload the image with optional guidance notes, review and edit the proposed items, select what you want to keep, and import. The analysis routes through the existing vision provider infrastructure. A new API endpoint (POST /api/v1/wardrobe/analyze-image) and LLM log type (WARDROBE_IMAGE_ANALYSIS) support the feature.
AI Wardrobe Generation
The AI Wizard and Summon from Lore features now generate wardrobe items instead of embedding clothing descriptions in the physical description field. Physical description prompts no longer include clothing — those details belong to the wardrobe system, where they can be changed, where they have structure, where they mean something to the tools that need to know what a character is wearing. The AI Wizard offers "Wardrobe Items" as a selectable generation field, and Summon from Lore includes a dedicated wardrobe generation step.
Per-Conversation Avatars
An opt-in feature for the committed: when enabled on a chat, outfit changes trigger automatic portrait generation via a background job. The generated portrait — a 3/4 shot, thighs up, with scenario context — becomes the character's avatar for that conversation, creating a visual timeline as clothing changes over the course of the scene. Toggle it per-chat, per-project, or during chat creation. The portraits use equipped wardrobe items and are tagged to the character for gallery display. Generated avatars are stored in the project's directory when the chat belongs to a project.
A small camera icon on each participant's avatar in the sidebar lets you manually trigger regeneration on demand — because sometimes the automatic portrait captures the outfit but misses the mood. After any generation completes, the avatar auto-refreshes via polling that detects enriched avatar URL changes, so the new portrait appears without a page reload. The generation prompt now explicitly requests solo portraits, preventing the duplicate-figure artifacts that occasionally appeared when multiple characters shared a scene description.
Avatar generation now passes through the Concierge's dangerous content system — prompts built from physical descriptions and equipped wardrobe are classified before generation, with AUTO_ROUTE support for rerouting to uncensored image providers when needed. Because the Concierge, whatever else you may say about him, knows which doors to knock on.
Migration
Existing clothing records are automatically migrated to wardrobe items as full-coverage outfits. The legacy clothingRecords column is preserved for backward compatibility. Nothing is lost. The shape of the data changes; the data itself does not.
The Salon
Library File Attach
A new gutter button (document icon) in the chat composer lets you attach existing files from the General library or any project's library to the current message without re-uploading. A two-step picker selects scope, then browses files with preview. A new API endpoint (POST /api/v1/chats/[id]/files?action=link) links existing library files to chats without duplication.
Standalone Image Generation
A new gutter button (camera icon) opens a full image generation dialog with profile picker, available in every chat regardless of character image configuration. Generated images attach as tool output. The chat composer gutter now arranges its tools in a 2×2 grid — library and camera above the existing paperclip and dice.
Narration Delimiters
Roleplay templates now require a narrationDelimiters field declaring how narration and action text are delimited — a single character (* for *narration*) or an open/close pair ([/] for [narration]). The Standard template uses *; the Quilltap RP template uses brackets. The formatting toolbar in Document Mode derives its narration button from this field and removes any redundant annotation button whose delimiters match. Existing templates default to * via migration and schema default.
Tool Palette Reorganization
The Roleplay Template dropdown moved from Chat Settings into the Edit Content section of the tool palette. State moved to Organize. Memory actions (Re-extract, Delete) merged into Edit Content. The separate Memory section is gone.
Prospero's Study
Project Detail Card Reorganization
The monolithic Project Settings card has been split into focused cards: "Model Behavior" (agent mode, tool settings), "Image Generation" (avatars, story backgrounds), and a slimmed-down "Project Settings" (instructions, project state). "Allow Any Character" moved into the Characters card. The Project Settings card now spans two rows for more instruction space.
WebP Auto-Conversion
All images — uploaded, imported, and AI-generated — are now automatically converted to WebP format. SVGs are the sole exception. A startup migration converts all existing non-WebP, non-SVG images to WebP, updating database references and deleting originals only after verification. Consistent format, smaller files, less disk overhead.
Default Image Generation Profile
Projects can now specify their own default image generation profile, configured in the Image Generation card on the project detail page. When a chat belongs to a project, the profile resolution chain checks the project's preference before falling back to the character or global default — project trumps character trumps system, in the manner of all sensible hierarchies. Story background generation follows the same chain. The setting is stored as a nullable defaultImageProfileId column on the projects table, which is to say: it stays out of the way until you tell it not to.
Backup Coverage
Wardrobe items and outfit presets are now included in backup/restore, with full UUID remapping for new-account imports. The characters you restore arrive with their clothes.
The Plumbing
Concierge: Avatar Generation Routing
Character avatar generation now routes through the Concierge's content classification system. This was missing — avatar prompts built from physical descriptions and wardrobe items were going straight to the image provider without content classification, which meant an uncensored character's portrait request could be refused by a censored provider with no fallback. Now it classifies first, reroutes if needed.
Wardrobe Multi-Type Displacement
Equipping a wardrobe item correctly displaces conflicting items from all their type slots. A dress covering top and bottom vacates both slots when you equip a new top. Unequipping clears all slots the item covers. Applies across sidebar outfit changes, tool use, and preset application.
Outfit Description Consistency
Six scattered implementations of outfit description logic — some assuming defaults for empty slots, some omitting them entirely — have been consolidated into a single describeOutfit() utility. null means empty, not "default." Outfit Change Notices use the same canonical format.
Image Clipboard
Fixed "Failed to copy image to clipboard" in browser — the Clipboard API accepts only PNG, but images are stored as WebP. Now converts to PNG via canvas before writing. Also fixed a CSP violation from blob: URLs by switching to data: URLs. Tool message image copy buttons and missing attachment cleanup also received fixes.
Memory Cleanup Label
"Max Memories" / "Hard cap on total memories" has been relabeled "Maximum Unprotected Memories" with a list of the protection rules (importance ≥ 70%, reinforced 5+ times, manually created, accessed within 3 months). The hard cap has never deleted protected memories. The label now says so.
LLM Inspector: Image Generation
Image generation API calls — character avatars, story backgrounds, in-chat image tool — are now logged in the LLM Inspector with chat/character linkage, provider, model, prompt, duration, and error tracking.
Character Plugin Data
A new character_plugin_data table gives plugins a place to keep their notes. Each record maps a character ID and a plugin name to an arbitrary JSON blob — your MCP server's character preferences, a third-party tool's calibration state, whatever structured data a plugin needs that belongs to a character rather than to the system at large. The API is a straightforward REST surface: GET/POST on the collection, GET/PUT/DELETE per plugin name. Data is included in Quilltap exports and imports, cascade-deleted when a character is removed, and typed in @quilltap/plugin-types for anyone building against the interface. It is, in essence, a labeled drawer in the character's desk — small, private, and entirely the plugin's business what goes in it.
OpenRouter Image Generation
The OpenRouter plugin now supports image generation, joining OpenAI, Google, and xAI as a provider that can produce images natively. Models offering image generation through OpenRouter are available alongside other image providers in profile configuration — which means the wardrobe's "Import from Image" feature, per-conversation avatars, and story backgrounds can all route through OpenRouter if that's where your preferred image model lives.
Code Quality
The cycle produced the usual structural improvements: consolidated duplicate WardrobeItemType imports, unexported unused types (DedupClusterResult, CharacterDedupResult, DedupResult, ValidationResult), extracted a shared ChevronIcon component from six files, refactored the monolithic executeImageGenerationTool (438 lines) into five focused helpers, and extracted useEntitySearch/EntitySearchDropdown from the image generation dialog. The dead code report has been updated.
Subsystem Table
| Name | Function | What Changed |
|---|---|---|
| The Foundry | Architecture, plugins, packages, LLMs | Roleplay template plugin capability removed, character plugin data API, OpenRouter image generation, plugin-types 2.2.1, plugin-utils 2.2.1 |
| Prospero | Projects, agents, tools, files | Project detail card reorganization, default image generation profile, WebP auto-conversion, backup coverage for wardrobe |
| Aurora | Character creation, AI Import Wizard, identity | Persona→userCharacter rename, AI Wizard wardrobe generation, Summon from Lore wardrobe step, wardrobe import from image |
| The Commonplace Book | Memory and retrieval | Memory cleanup label fix, personaId column dropped |
| The Salon | Chat interface | Wardrobe action notices, outfit change notify button, library file attach, standalone image generation, gutter 2×2 layout, narration delimiters, tool palette reorganization |
| Calliope | Interface, themes | Wardrobe CSS variables, persona badge variable rename, whisper CSS variables added to theme-storybook |
| The Concierge | Content routing, moderation | Avatar generation routing through content classification |
| The Lantern | Image generation | Equipped wardrobe items in image prompts, per-conversation avatar generation, manual avatar regeneration, solo portrait fix, image clipboard fixes, OpenRouter image generation provider |
| Pascal | Noticed that the wardrobe has a drawer labeled "accessories." Filed it under "interesting." | |
| Saquel Ytzama | Encryption, key management | Quiet this cycle. One imagines she approves of systems that know what belongs to whom. |
Upgrading from 4.1
Database migrations handle themselves. The new wardrobe_items, outfit_presets, character_plugin_data tables and related columns are created automatically. Existing clothing records are migrated to wardrobe items on startup. The annotationButtons column is renamed to delimiters. The personaLinks field becomes partnerLinks. The memories.personaId column is dropped (the data was already duplicated in aboutCharacterId). Projects gain a nullable defaultImageProfileId column.
Your existing roleplay template plugin references are rewritten to the built-in template UUID. If you had custom roleplay template plugins, they will need to be converted to the native JSON format — the ROLEPLAY_TEMPLATE plugin capability no longer exists.
Theme authors should update any --qt-badge-persona-* CSS variables to --qt-badge-user-character-*. The new --qt-chat-wardrobe-* variables are available for styling wardrobe action notices.
Installation
Desktop App
Download from the quilltap-shell releases page:
macOS:
- Download the
.dmgfile and open it - Drag Quilltap to your Applications folder
- Launch Quilltap from Applications
Windows:
- Download and run the
.exeinstaller - If SmartScreen warns about an unknown publisher, click "More info" → "Run anyway"
- Launch Quilltap from the Start Menu or desktop shortcut
Linux:
- Download the
.AppImagefile, make it executable (chmod +x), and run it - Or install the
.debpackage:sudo dpkg -i quilltap_*.deb
Node.js (any platform)
npx quilltapOr install globally:
npm install -g quilltap
quilltapOpen http://localhost:3000 in your browser. Requires Node.js 22+. First run downloads ~150–250 MB and caches locally.
Docker
docker pull foundry9/quilltap:4.2.0Or use the startup scripts:
# Linux / macOS
curl -fsSL https://raw.githubusercontent.com/foundry-9/quilltap-server/refs/heads/main/scripts/start-quilltap.sh | bash
# Windows (PowerShell)
irm https://raw.githubusercontent.com/foundry-9/quilltap-server/refs/heads/main/scripts/start-quilltap.ps1 | iexThe Estate has a wardrobe now. Not a metaphorical one — not a "clothing records" field buried in a character card like a stage direction nobody revisits after opening night. A real wardrobe, with drawers that open and close, with items that can be given and received, with the quiet dignity of a system that knows the difference between a costume and a life. The characters dress themselves. They dress each other. They notice when someone has changed. They arrive at the beginning of a conversation already wearing something chosen for the occasion, by a mind that considered the weather, the company, and the mood — which is, when you think about it, what getting dressed has always been. The word "persona" is gone, and good riddance; it was a mask pretending to be a mirror. The templates have shed their plugin scaffolding and become what they always wanted to be: a few delimiters and a name. Aurora's workshop is full of new tools. The Salon has new buttons. Pascal is examining the accessories drawer with the quiet intensity of someone who has found a new category of thing to count. Come in. The staff are well-dressed. They would like you to notice.
— Aurora, for the Bureau
Installation
Desktop App (recommended)
The Quilltap desktop app (Electron) is available from
quilltap-shell 4.1.0.
Download the release for your platform (macOS, Windows, or Linux).
The quilltap-linux-arm64.tar.gz and quilltap-linux-amd64.tar.gz rootfs
tarballs attached to this release are used by the shell's Lima (macOS) and WSL2 (Windows) VM modes.
Node.js (any platform)
npm install -g quilltap
quilltapOn first run, the CLI downloads the application files (~150-250 MB)
and caches them locally. Subsequent launches start instantly.
Docker
docker pull foundry9/quilltap:4.2.0See the README for setup instructions.