Skip to content
Development
Skill

/chat

**Read this before creating chat widgets.**

From plugin
pywry
9318 skills1 agent2 commands1 MCP
Install
$ npx -y skills add deeleeramone/PyWry --skill chat --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/chat

Context preview

The summary Claude sees to decide when to auto-load this skill.

**Read this before creating chat widgets.**

SKILL.md

chat.SKILL.md

Chat Component - Reference Guide

> **Read this before creating chat widgets.**

Overview

The chat component provides a full-featured conversational UI with:

  • Message rendering with inline markdown
  • Streaming responses with token-by-token display
  • Stop-generation (cancel in-flight LLM responses)
  • Thread management (create, switch, delete)
  • Slash command palette (type `/` to see commands)
  • Settings panel (model, temperature, system prompt)
  • LLM provider adapters (OpenAI, Anthropic, custom callback)

Quick Start

Via MCP Tool

{
  "name": "create_chat_widget",
  "arguments": {
    "title": "AI Assistant",
    "model": "gpt-4",
    "system_prompt": "You are a helpful assistant.",
    "streaming": true,
    "provider": "openai"
  }
}

Via Python

from pywry import App
from pywry.chat import ChatConfig, ChatWidgetConfig

app = App()
config = ChatWidgetConfig(
    title="AI Chat",
    height=600,
    chat=ChatConfig(
        system_prompt="You are helpful.",
        model="gpt-4",
        streaming=True,
        provider="openai",
    ),
)
# Widget creation handled by MCP or directly via app.show()

---

MCP Tools

create_chat_widget

Creates a chat widget. Returns `{widget_id, thread_id}`.

| Parameter | Type | Default | Description | |----------------|---------|----------|--------------------------------| | title | string | "Chat" | Window title | | height | integer | 600 | Window height | | system_prompt | string | "" | System prompt for LLM | | model | string | "gpt-4" | Model name | | temperature | number | 0.7 | Sampling temperature (0-2) | | max_tokens | integer | 4096 | Max tokens per response | | streaming | boolean | true | Enable streaming | | persist | boolean | false | Persist threads in ChatStore | | provider | string | — | "openai", "anthropic", "callback" | | show_sidebar | boolean | true | Show thread sidebar | | slash_commands | array | — | Custom slash commands |

chat_send_message

Send a user message. Returns `{message_id, thread_id, sent}`.

chat_stop_generation

Stop an in-flight generation. Idempotent. Returns partial content.

chat_manage_thread

Thread CRUD: create, switch, delete, rename, list.

chat_register_command

Register a slash command at runtime.

chat_get_history

Paginated conversation history with cursor (`before_id`).

chat_update_settings

Update model, temperature, system prompt, etc.

chat_set_typing

Show/hide the typing indicator.

---

Event Contract

Incoming Events (Python → Frontend)

| Event | Payload | |---------------------------|--------------------------------------------| | `chat:assistant-message` | `{messageId, text, threadId}` | | `chat:stream-chunk` | `{chunk, messageId, threadId, done}` | | `chat:typing-indicator` | `{typing, threadId}` | | `chat:switch-thread` | `{threadId}` | | `chat:update-thread-list` | `{threads: [{thread_id, title}]}` | | `chat:clear` | `{}` | | `chat:register-command` | `{name, description}` | | `chat:update-settings` | `{model, temperature, system_prompt}` | | `chat:state-response` | `{messages, threads, settings, activeThreadId}` | | `chat:generation-stopped` | `{messageId, threadId, partialContent}` |

Outgoing Events (Frontend → Python)

| Event | Payload | |--------------------------|---------------------------------------------| | `chat:user-message` | `{text, threadId, timestamp}` | | `chat:slash-command` | `{command, args, threadId}` | | `chat:thread-create` | `{title}` | | `chat:thread-switch` | `{threadId}` | | `chat:thread-delete` | `{threadId}` | | `chat:settings-change` | `{key, value}` | | `chat:request-history` | `{threadId, limit}` | | `chat:stop-generation` | `{threadId, messageId}` | | `chat:request-state` | `{}` |

---

Stop-Generation Mechanics

1. User clicks Stop button → frontend immediately re-enables UI 2. `chat:stop-generation` sent to backend 3. Backend sets `cancel_event` on `GenerationHandle` 4. LLM provider checks `cancel_event.is_set()` between chunks 5. Provider raises `GenerationCancelledError` → partial content saved 6. Backend emits `chat:generation-stopped` with partial content 7. Frontend marks message as "(stopped)"

The UI **never waits** for backend confirmation — recovery is instant.

---

Default Slash Commands

| Command | Description | |-----------|----------------------------| | `/clear` | Clear conversation | | `/export` | Export chat history | | `/model` | Switch model | | `/system` | Change system prompt |

Register custom commands via `chat_register_command` tool or `ChatConfig.slash_commands` list.

---

LLM Providers

OpenAI

{"provider": "openai"}

Requires `openai` package and `OPENAI_API_KEY` environment variable.

Anthropic

{"provider": "anthropic"}

Requires `anthropic` package and `ANTHROPIC_API_KEY` environment variable.

Custom Callback

from pywry.chat.providers.callback import CallbackProvider

provider = CallbackProvider(
    prompt_fn=my_prompt,   # (session_id, content_blocks, cancel_event) → AsyncIterator[SessionUpdate]
)

---

S

Read more
Ships withpywry

PyWry is a cross-platform app factory, rendering engine and UI toolkit for Python that produces native desktop, web, and notebook experiences from a single API.

Get the whole plugin

Other skills on pywry.