Summary
Add a display-only “language skin” system for dreb’s interactive TUI. A language skin would transform how transcript entries are rendered, without changing the canonical session log, provider context, tool inputs, tool outputs, or copy/export defaults.
The motivating proof of concept is medieval_dreb: a novelty skin where the user becomes “the warlock”, the parent agent becomes “the bound daemon”, subagents become “accursed imps”, tools become “rites”, file reads become “scrying the grimoire”, test runs become “trials by ordeal”, and CI becomes “the council of elders”.
This is partly a joke feature, but the underlying primitive is broadly useful: display-only transcript transforms could support localization, accessibility simplification, domain-specific terminology, corporate/plain-language filters, or other user-facing presentation layers without affecting agent quality.
Current Behavior
dreb supports color themes, extension-provided custom renderers, custom messages, custom tool rendering, status widgets, title updates, and input/context hooks. However, normal user/assistant/tool transcript display is still essentially canonical.
Extensions can transform input or provider context, but that is the wrong layer for this feature because it would change what the actual coding agent sees. The goal is deliberately different: the agents should continue operating on normal technical language while only the TUI presentation layer is transformed.
Current extension/rendering primitives that are relevant:
packages/coding-agent/docs/extensions.md
- Custom renderers exist for extension custom messages.
- Tool rendering can be customized.
- Input/context hooks can transform actual agent-facing content, but should not be used for language skins.
packages/coding-agent/docs/themes.md
- Themes currently cover colors/styles, not semantic/language presentation.
packages/coding-agent/src/core/context-buffer.ts
- Provides
RollingContextBuffer, labelMessageEnd, and labelToolEnd.
packages/coding-agent/src/core/buddy/buddy-controller.ts
- Maintains a rolling context buffer for buddy reactions.
packages/coding-agent/src/modes/interactive/tab-title.ts
- Uses
RollingContextBuffer plus a lightweight model call to generate a terminal title from recent session activity.
- This is a useful precedent for bounded, auxiliary, non-agent-facing model calls.
Proposed Behavior
Introduce a language skin/render skin layer for the interactive TUI:
- Keep the canonical session log unchanged.
- Keep provider requests unchanged.
- Keep tool arguments/results unchanged.
- Keep agent and subagent context unchanged.
- Store themed render output separately as derived display data.
- Render canonical text immediately.
- Asynchronously generate themed text in the background.
- Update the existing rendered transcript entry in place once themed output arrives.
- Allow users to disable the skin instantly and return to canonical display.
- Allow exact model configuration for the skin generator, including local/Ollama models.
- Use bounded rolling context so the themed voice remains consistent without feeding the full transcript every time.
- Treat skin enablement as a display preference, not a session mutation: if a user disables the skin, continues, or resumes a session with the skin disabled, the transcript should display the original canonical unthemed content.
The important invariant: language skins are presentation-only. They must never influence code quality by changing what the working agent sees.
Example: medieval_dreb
Possible glossary:
| Canonical concept |
Themed display |
| user |
the warlock |
| assistant / parent agent |
the bound daemon |
| subagent |
accursed imp |
| tool |
rite |
| read |
scry |
| write |
inscribe |
| edit |
amend the grimoire |
| bash command |
shell incantation |
| search / grep |
seek the sigil |
| build |
forge |
| test |
trial by ordeal |
| CI |
council of elders |
| error |
ill omen |
| success |
the rite is complete |
Example transformations:
I'll inspect the failing test.
The bound daemon shall consult the trial-script and divine its failing omen.
read packages/foo/test.ts
Scrying the grimoire: packages/foo/test.ts
Subagent completed
An accursed imp returns from the lower stacks, bearing tidings.
npm run build
Uttering the forge incantation: npm run build
Themed output should preserve technical identifiers exactly. The joke is in the surrounding prose and labels, not in corrupting paths, commands, code, diffs, or JSON.
Async Rendering UX
Async rendering is a core part of the desired experience:
- Canonical transcript text appears immediately.
- The skin generator queues a background render job.
- The UI marks the entry as pending in a subtle way.
- When the themed text is ready, the existing entry updates in place.
- If generation fails, canonical text remains visible and the UI shows a small warning/status.
Possible status labels for the medieval skin:
[true speech]
[weaving glamour...]
[glamoured]
[glamour failed: showing true speech]
A future implementation could add optional animations, such as a subtle shimmer/flicker before replacement, but animation is not required for the first version.
Canonical Log and Themed Sidecar
The canonical session log should remain the source of truth. The themed transcript should be stored separately as a derived sidecar/cache.
A themed entry might be keyed by:
{
"entryId": "abc123",
"skin": "medieval_dreb",
"skinVersion": "1.0.0",
"model": "ollama/qwen3:4b",
"sourceHash": "sha256:...",
"themedText": "The bound daemon doth proclaim...",
"createdAt": 1782400000000
}
Regeneration rules:
- If no themed entry exists, generate one.
- If the source hash changes, regenerate.
- If the skin version changes, regenerate.
- If the configured model changes, regenerate or treat old output as stale.
- If the sidecar/cache is deleted, canonical display still works.
Possible storage locations should be evaluated, but the themed data should not be mixed into normal agent context. It should be safe to delete/regenerate without affecting replay, debugging, compaction, or provider requests.
Rolling Context for Theming Consistency
The skin generator should not receive the full transcript every time. Instead, it should use the same general rolling-context trick already used by the buddy and terminal tab title systems.
Relevant prior art:
packages/coding-agent/src/core/context-buffer.ts
- Shared
RollingContextBuffer
labelMessageEnd
labelToolEnd
packages/coding-agent/src/core/buddy/buddy-controller.ts
- Captures recent user, assistant, and tool activity for buddy reactions.
packages/coding-agent/src/modes/interactive/tab-title.ts
- Captures recent activity and performs an auxiliary lightweight model call outside the main agent context.
For language skins, each render request should include:
- Skin system prompt / style instructions.
- Glossary.
- Strict preservation rules.
- Bounded style memory.
- Recent canonical/themed pairs, including both the pre-translation canonical text and the post-translation themed output.
- The new canonical text to render.
The recent pair context is important: the skin generator should know both what it was working from and what it previously produced. That lets it preserve consistent terminology, recurring character names/roles, tone, and joke-specific mappings without relying on the full transcript. Failed or pending skin generations should not be treated as authoritative examples.
Example prompt shape:
You are rendering dreb transcript text in Medieval Warlock style.
You are NOT the coding agent.
You are NOT speaking to the user directly.
You are only producing display text for a transcript skin.
Preserve exactly:
- code blocks
- inline code
- file paths
- commands
- JSON
- diffs
- tool arguments
- URLs
- error messages where exact wording matters
Glossary:
user => warlock
assistant => bound daemon
subagent => accursed imp
tool => rite
read => scry
write => inscribe
...
Recent successful canonical/themed pairs:
Canonical: "I'll run the tests now."
Themed: "The bound daemon shall now commence the trials."
Canonical: "Subagent completed."
Themed: "An accursed imp returns with tidings."
New canonical text:
...
This should make the skin feel consistent while bounding cost and latency.
Model Configuration and Cost Controls
The model used for language skins must be explicitly configurable. This feature should never silently select an expensive model.
Requirements:
- Users can specify the exact provider/model for skin generation.
- Local providers such as Ollama should be supported when available.
- The default should be disabled, or require explicit opt-in.
- There should be clear max character/token controls per request.
- The system should cache aggressively.
- Failures should fall back to canonical display.
- A failed skin generator must not interrupt the main agent.
- A slow skin generator must not block agent work.
Example settings shape:
{
"languageSkin": {
"enabled": true,
"skin": "medieval_dreb",
"model": "ollama/qwen3:4b",
"maxCharsPerRequest": 4000,
"rollingContextEntries": 20,
"rollingContextChars": 8000,
"cache": true,
"fallback": "canonical"
}
}
Potential commands:
/skin medieval
/skin medieval --model ollama/qwen3:4b
/skin off
/skin regenerate
/skin show-original
Preservation Rules
Language skins must preserve technical content unless a skin explicitly wraps it in display-only labels.
Must preserve exactly:
- Code blocks.
- Inline code.
- File paths.
- Shell commands.
- Tool arguments.
- Tool result data where exact content matters.
- Diffs.
- JSON/YAML/TOML.
- URLs.
- Error messages where exact wording is useful.
- Line numbers.
- Identifiers and symbols.
Safe transformations:
- Surrounding prose.
- Role labels.
- Tool display labels.
- Status text.
- Non-technical assistant narration.
- Collapsed tool titles.
- Decorative metadata.
Unsafe transformations:
- Changing code.
- Changing commands.
- Translating file paths.
- Rewording diffs.
- Rewording structured data.
- Rewording anything copied into a future command.
Copy and Export Behavior
Canonical text should remain the default for copy/export.
Possible behavior:
/copy defaults canonical.
/export defaults canonical.
- “Copy as displayed” is explicit opt-in.
- “Export themed transcript” is explicit opt-in.
- The UI should make it clear whether copied/exported content is canonical or themed.
This avoids accidentally sharing confusing themed logs when debugging.
Documentation Requirements
Docs should be explicit that language skins are a novelty/presentation feature and may be unsuitable during serious debugging.
Documentation should warn:
- Skins may add latency.
- Skins may incur model/API costs.
- Skins may make technical output more confusing.
- Skins should be disabled for delicate debugging, review, or when sharing exact logs.
- Canonical logs remain the source of truth.
- Copy/export defaults to canonical text.
- Users should choose a cheap/local model where possible.
- Users are responsible for configuring the model used by the skin generator.
Docs should also explain the serious uses:
- localization
- accessibility simplification
- “explain like I’m new to coding”
- domain-specific terminology layers
- corporate/plain-language filters
- novelty/roleplay skins
Acceptance Criteria
- dreb supports a display-only language skin layer for the interactive TUI.
- Canonical session logs remain unchanged.
- Provider requests remain canonical.
- Tool inputs and outputs remain canonical.
- Agent/subagent behavior is unaffected by active skins.
- Themed output is stored separately as derived render data.
- Themed output is keyed by canonical entry identity, source hash, skin, skin version, and model.
- Missing/stale themed output can be regenerated.
- Canonical text renders immediately while themed output is generated asynchronously.
- Rendered entries can update in place when themed output becomes available.
- Slow/failed themed generation does not block or fail the main agent.
- Users can disable skins and return to canonical display immediately.
- Continuing or resuming a session with skins disabled displays the original canonical unthemed transcript, not cached themed text.
- Users can configure the exact model used for skin generation.
- Local/Ollama models can be used when configured.
- A bounded rolling context mechanism keeps style consistent without sending the full transcript.
- The implementation reuses or mirrors the
RollingContextBuffer pattern from buddy/tab-title where appropriate.
- Preservation rules prevent corruption of code, commands, paths, diffs, JSON, and tool arguments.
- Copy/export defaults to canonical content.
- Themed copy/export, if implemented, is explicit opt-in.
- Documentation covers latency, cost, confusion risk, model configuration, and canonical-vs-themed behavior.
Technical Notes
This likely requires a core rendering extension point rather than an input/context transform.
Possible API directions:
dreb.registerLanguageSkin({
name: "medieval_dreb",
version: "1.0.0",
model: "...",
transformDisplayText: async (request) => {
...
}
});
or:
dreb.registerDisplayTransform({
name: "medieval_dreb",
appliesTo: ["user_message", "assistant_message", "tool_title", "tool_result", "status"],
transform: async (request) => {
...
}
});
The request object likely needs:
- canonical entry id
- role/kind
- canonical text
- structured content metadata
- source hash
- recent rolling context
- prior successful canonical/themed pairs, including both pre-translation and post-translation text
- abort signal
- skin config
The response likely needs:
- themed text
- preservation diagnostics if relevant
- model used
- token/cost metadata if available
- cache metadata
Rendering components will need a way to:
- render canonical immediately
- subscribe to skin-cache updates
- invalidate/re-render when themed text arrives
- show pending/failure state
- fall back cleanly to canonical
Open design questions:
- Should skins be built-in resources, extensions, packages, or theme-adjacent resources?
- Should color themes and language skins be bundled into “premium themes” / richer theme packages?
- Where should sidecar/cache data live?
- Should themed output participate in session export metadata, or remain an external cache unless explicitly exported?
- How much of tool result output should be skinned versus only tool labels/statuses?
- Should the first implementation only skin prose/status/tool titles, leaving raw tool output canonical?
Summary
Add a display-only “language skin” system for dreb’s interactive TUI. A language skin would transform how transcript entries are rendered, without changing the canonical session log, provider context, tool inputs, tool outputs, or copy/export defaults.
The motivating proof of concept is
medieval_dreb: a novelty skin where the user becomes “the warlock”, the parent agent becomes “the bound daemon”, subagents become “accursed imps”, tools become “rites”, file reads become “scrying the grimoire”, test runs become “trials by ordeal”, and CI becomes “the council of elders”.This is partly a joke feature, but the underlying primitive is broadly useful: display-only transcript transforms could support localization, accessibility simplification, domain-specific terminology, corporate/plain-language filters, or other user-facing presentation layers without affecting agent quality.
Current Behavior
dreb supports color themes, extension-provided custom renderers, custom messages, custom tool rendering, status widgets, title updates, and input/context hooks. However, normal user/assistant/tool transcript display is still essentially canonical.
Extensions can transform input or provider context, but that is the wrong layer for this feature because it would change what the actual coding agent sees. The goal is deliberately different: the agents should continue operating on normal technical language while only the TUI presentation layer is transformed.
Current extension/rendering primitives that are relevant:
packages/coding-agent/docs/extensions.mdpackages/coding-agent/docs/themes.mdpackages/coding-agent/src/core/context-buffer.tsRollingContextBuffer,labelMessageEnd, andlabelToolEnd.packages/coding-agent/src/core/buddy/buddy-controller.tspackages/coding-agent/src/modes/interactive/tab-title.tsRollingContextBufferplus a lightweight model call to generate a terminal title from recent session activity.Proposed Behavior
Introduce a language skin/render skin layer for the interactive TUI:
The important invariant: language skins are presentation-only. They must never influence code quality by changing what the working agent sees.
Example:
medieval_drebPossible glossary:
Example transformations:
I'll inspect the failing test.The bound daemon shall consult the trial-script and divine its failing omen.read packages/foo/test.tsScrying the grimoire: packages/foo/test.tsSubagent completedAn accursed imp returns from the lower stacks, bearing tidings.npm run buildUttering the forge incantation: npm run buildThemed output should preserve technical identifiers exactly. The joke is in the surrounding prose and labels, not in corrupting paths, commands, code, diffs, or JSON.
Async Rendering UX
Async rendering is a core part of the desired experience:
Possible status labels for the medieval skin:
[true speech][weaving glamour...][glamoured][glamour failed: showing true speech]A future implementation could add optional animations, such as a subtle shimmer/flicker before replacement, but animation is not required for the first version.
Canonical Log and Themed Sidecar
The canonical session log should remain the source of truth. The themed transcript should be stored separately as a derived sidecar/cache.
A themed entry might be keyed by:
{ "entryId": "abc123", "skin": "medieval_dreb", "skinVersion": "1.0.0", "model": "ollama/qwen3:4b", "sourceHash": "sha256:...", "themedText": "The bound daemon doth proclaim...", "createdAt": 1782400000000 }Regeneration rules:
Possible storage locations should be evaluated, but the themed data should not be mixed into normal agent context. It should be safe to delete/regenerate without affecting replay, debugging, compaction, or provider requests.
Rolling Context for Theming Consistency
The skin generator should not receive the full transcript every time. Instead, it should use the same general rolling-context trick already used by the buddy and terminal tab title systems.
Relevant prior art:
packages/coding-agent/src/core/context-buffer.tsRollingContextBufferlabelMessageEndlabelToolEndpackages/coding-agent/src/core/buddy/buddy-controller.tspackages/coding-agent/src/modes/interactive/tab-title.tsFor language skins, each render request should include:
The recent pair context is important: the skin generator should know both what it was working from and what it previously produced. That lets it preserve consistent terminology, recurring character names/roles, tone, and joke-specific mappings without relying on the full transcript. Failed or pending skin generations should not be treated as authoritative examples.
Example prompt shape:
This should make the skin feel consistent while bounding cost and latency.
Model Configuration and Cost Controls
The model used for language skins must be explicitly configurable. This feature should never silently select an expensive model.
Requirements:
Example settings shape:
{ "languageSkin": { "enabled": true, "skin": "medieval_dreb", "model": "ollama/qwen3:4b", "maxCharsPerRequest": 4000, "rollingContextEntries": 20, "rollingContextChars": 8000, "cache": true, "fallback": "canonical" } }Potential commands:
Preservation Rules
Language skins must preserve technical content unless a skin explicitly wraps it in display-only labels.
Must preserve exactly:
Safe transformations:
Unsafe transformations:
Copy and Export Behavior
Canonical text should remain the default for copy/export.
Possible behavior:
/copydefaults canonical./exportdefaults canonical.This avoids accidentally sharing confusing themed logs when debugging.
Documentation Requirements
Docs should be explicit that language skins are a novelty/presentation feature and may be unsuitable during serious debugging.
Documentation should warn:
Docs should also explain the serious uses:
Acceptance Criteria
RollingContextBufferpattern from buddy/tab-title where appropriate.Technical Notes
This likely requires a core rendering extension point rather than an input/context transform.
Possible API directions:
or:
The request object likely needs:
The response likely needs:
Rendering components will need a way to:
Open design questions: