Learn the user's writing style per outreach channel (email, LinkedIn, Twitter/X, WhatsApp, Slack, SMS, Discord, Telegram — whatever is connected for this ten...
---
name: outclaw-style
description: >
Learn the user's writing style per outreach channel (email, LinkedIn,
Twitter/X, WhatsApp, Slack, SMS, Discord, Telegram — whatever is
connected for this tenant). Runs the Prompt Learning Protocol from
https://gist.github.com/milstan/3b12f938f344f4ae1f511dd19e56adce on
≥20 outbound samples per channel (falls back to what's available).
Triggers on: 'learn my style', 'learn my voice', 'retrain style for
<channel>', 'style report', 'how's my style score'. Auto-invoked (no
user prompt) by outclaw-plan when a planned channel lacks a learned
style for the current tenant.
version: 2.1.33
metadata:
openclaw:
emoji: "🎨"
homepage: https://github.com/leadbay/outclaw
---
# OutClaw — Style
Learns a per-channel style prompt for the **current tenant** and persists
it at `~/.openclaw/outclaw/styles/<tenant>/<channel>_style.md`. Each style
prompt is what `outclaw-plan` uses to draft messages on that channel.
## Resolver mandate
Before writing styles, memory entries, or any KB update, read
`shared/references/RESOLVER.md`. Styles go in
`styles/<tenant>/<channel>_style.md`. NEVER hand-craft a different path.
A trained-style summary goes to tenant memory as
`type=user, key=style_trained_<channel>` so `outclaw-plan` can find it
quickly without re-reading the style file.
## When this skill runs
1. **Explicit user request** — `learn my style`, `retrain style for email`.
2. **Auto-invoked, silent** — when `outclaw-plan` builds a plan that
includes a channel with no learned style for this tenant, it invokes
this skill for that one channel, waits for completion, then continues.
No user prompt. No interruption.
## Prompt Learning Protocol (implements the user's gist)
The gist at https://gist.github.com/milstan/3b12f938f344f4ae1f511dd19e56adce
prescribes:
1. **Sample collection** — gather ≥20 outbound messages per channel (or
≥1 000 words / ≥10 pairs, whichever floor is higher). If fewer are
available, work with what you find; mark `confidence` accordingly.
**Do not fabricate samples.**
2. **Analysis** — a thinking model identifies dimensions of quality,
structural/stylistic patterns, anti-patterns the samples avoid.
3. **Candidate prompt** — direct, actionable instructions
("Write sentences that average 12-18 words"), target 500-2 000 words,
with an explicit Avoid section.
4. **Iteration loop (5 cycles default)** per channel:
- Generate test output with moderate temperature (0.6-0.8)
- Evaluate against dimensions (0-100 LLM judgments)
- Track best-of-N
- Refine (lower temperature 0.2-0.4, focus on lowest-scoring dimensions)
5. **Output**: learned prompt + best score + iteration number + dimensions
+ conformity log. Save to
`~/.openclaw/outclaw/styles/<tenant>/<channel>_style.md` with YAML
frontmatter (tenant, channel, trained_at, sample_count, best_score,
best_iteration, dimensions).
See `references/style-learning.md` for the detailed steps and
`agents/style-learner.md` for the delegated sub-agent spec.
## Per-channel sources (which tools to use)
For each channel we care about, list where outbound samples can be read
from. The agent picks only channels this tenant has `ready` in the
capability map (`capabilities/<tenant>.json`).
| Channel | Sample source |
|---------|---------------|
| Gmail | `gog gmail messages search "from:me" --max 50` |
| LinkedIn | `linkedin-cli posts --author me --max 50` (if connected) or export |
| Twitter/X | `XActions` or direct API via xurl |
| Slack | `slack-mcp-server` message history where sender=me |
| WhatsApp | `whatsapp-mcp-ts` conversation export, filter author=me |
| Telegram | `telegram-mcp` sent messages |
| Discord | `discord-mcp` messages where author=me |
| iMessage/SMS | `mac_messages_mcp` sent messages |
| Bluesky | `bsky-mcp-server` user posts |
## Flow
1. **Pick channels** — from memory `tool_inventory`, enumerate channels
that have a `ready` plugin AND a sample source. Skip channels with
no connected plugin entirely (no point training).
2. **For each selected channel**, run a sub-task:
a. Pull outbound samples via the channel's plugin. Write raw samples
to `kb/raw/style-<tenant>-<channel>-<ts>.jsonl` (NOT into the KB's
people/orgs — this is training data, filed under raw/).
b. If the sample count is <20 or <1 000 words, log a memory
observation and proceed anyway:
`{type: observation, key: "style_thin_<channel>", insight:
"only <N> samples — learned prompt confidence will be lower",
source: "observed", confidence: 6}`.
c. Two-stage classify: heuristic pre-filter (outbound, non-trivial
length, not auto-reply) → LLM OUTREACH_COLD/FOLLOWUP/WARM vs.
NOT_OUTREACH (see `scripts/message_classifier.py`).
d. Run the 5-iteration Prompt Learning Protocol
(`scripts/style_evaluator.py`).
e. Write the learned style to
`~/.openclaw/outclaw/styles/<tenant>/<channel>_style.md`.
f. Log: `{type: user, key: "style_trained_<channel>", insight:
"<channel> style trained; score <N>/100; <K> samples",
source: "observed", confidence: <N/10>}`.
3. **If auto-invoked** (from `outclaw-plan`): do ONE channel (the one
requested), silent, then return to the caller. **NEVER ask the user
for "preferred tone" or "desired format"** — the whole point of this
skill is that we infer style from samples. If a channel has no
outbound samples at all (e.g. user just connected Discord today),
log an observation:
`{type: observation, key: "style_nosamples_<channel>",
insight: "no outbound samples on <channel>; using neutral template",
source: "observed", confidence: 6}`
and emit a minimal neutral template at
`styles/<tenant>/<channel>_style.md` with sample_count: 0,
best_score: null, and a generic "direct, concise, warm-professional"
prompt. Return to caller.
4. **If user-invoked**: show a compact report — which channels were
trained, best score each, sample count, confidence.
## Filing rules (RESOLVER-compliant)
- Style prompt: `styles/<tenant>/<channel>_style.md` — NEVER
`kb/styles/*`, NEVER `kb/me/styles/*`.
- Raw outbound samples (the training data): `kb/raw/style-<tenant>-<channel>-<ts>.jsonl`.
- Summary for fast lookup: tenant memory, `type=user`,
`key=style_trained_<channel>`.
- Do NOT put learned styles in `kb/me/self.md` — voice description there
is for context, the style prompt lives separately.
## Consent
Sample collection is a one-time opt-in, captured during
`outclaw-setup` Step 2 as a memory `preference` entry. If no consent
entry exists when this skill runs:
- Explicit invocation: ask once, record the decision.
- Auto-invocation from plan: proceed only if the tenant has an opt-in
`style_consent` entry. If missing, log an observation and fall back
to a neutral template style. Never silently scrape without consent.
## Output format (style prompt file)
```markdown
---
tenant: outclaw
channel: gmail
trained_at: 2026-04-22T12:00:00Z
sample_count: 42
best_score: 82
best_iteration: 3
dimensions: [sentence_length, formality, personalization, cta_style, structure, tone, greeting_pattern, signoff_pattern]
conformity_log:
- {iter: 1, score: 64}
- {iter: 2, score: 71}
- {iter: 3, score: 82}
- {iter: 4, score: 80}
- {iter: 5, score: 78}
---
# Gmail style — outclaw (tenant)
## Instructions
<the learned prompt — 500-2000 words, direct + actionable>
## Avoid
- <anti-pattern 1>
- <anti-pattern 2>
## Reference samples
- <path>/raw/style-outclaw-gmail-<ts>.jsonl (not included verbatim here;
pointer only)
```
This format lets `outclaw-plan` parse the "Instructions" section directly
into the draft-generation prompt.
don't have the plugin yet? install it then click "run inline in claude" again.
added explicit intent, detailed inputs (plugin sources, auth scopes, rate limits), 6-step procedure with input/output pairs, decision trees for consent/sample sufficiency/fallbacks, output contract with file formats and memory keys, and outcome signals for both explicit and auto-invoked modes.
learns your writing style per outreach channel (email, LinkedIn, Twitter/X, WhatsApp, Slack, SMS, Discord, Telegram, etc.) and persists it as a reusable prompt. the skill runs the Prompt Learning Protocol on ≥20 outbound samples per channel, extracts patterns (sentence length, tone, structure, anti-patterns), and generates a 500-2000 word style guide. use this when you want to audit your voice across channels, or let outclaw-plan auto-invoke it silently whenever a planned channel lacks a trained style. the learned prompt lives at ~/.openclaw/outclaw/styles/<tenant>/<channel>_style.md so downstream drafting tools can adopt your authentic voice without manual tone specification.
learns the user's authentic writing style per channel by analyzing outbound message samples, then distills that style into a reusable prompt guide. this skill runs on explicit user request ("learn my style", "retrain style for email") or auto-invokes silently when outclaw-plan builds a draft plan that includes a channel with no trained style. the output is a markdown file with actionable instructions (not generic tone advice) that outclaw-plan consumes directly for message generation. use this to ensure all outreach sounds like you, even across 8+ channels, without asking the user to describe their own voice.
plugins and connections (read from capability map capabilities/<tenant>.json; skill enumerates only ready channels):
gog gmail messages search "from:me" --max 50 (native tool)linkedin-cli posts --author me --max 50 (or user export if not connected)XActions or direct API via xurlslack-mcp-server message history where sender=mewhatsapp-mcp-ts conversation export, filter author=metelegram-mcp sent messagesdiscord-mcp messages where author=memac_messages_mcp sent messagesbsky-mcp-server user postsmemory and context:
tool_inventory memory entry (lists connected plugins)style_consent preference entry (opt-in flag, set during outclaw-setup Step 2; required unless user confirms consent inline during explicit invocation)styles/<tenant>/*_style.md (to detect if retraining)external script references:
scripts/message_classifier.py: two-stage heuristic + LLM classifier (OUTREACH_COLD/FOLLOWUP/WARM vs. NOT_OUTREACH)scripts/style_evaluator.py: 5-iteration Prompt Learning Protocol with test generation, scoring, refinementreferences/style-learning.md: detailed protocol stepsagents/style-learner.md: delegated sub-agent specrate limits and auth edge cases:
channels:history and groups:history for DM/channel scraping. if missing, skip.step 1: resolve invocation context.
<channel> parameter. if explicit, extract channel list (or assume all ready channels).style_consent memory entry. if missing and explicit invocation, ask user once: "sample your outbound messages to learn your style. ok?" if no, log observation, skip to step 6. if yes, record {type: preference, key: style_consent, value: true}. if auto-invoked and no consent, log observation {key: "style_no_consent", insight: "auto-invoke blocked; user has not opted in"}, fall back to neutral template, return to caller.step 2: enumerate and validate channels.
ready in capabilities/<tenant>.json and have a sample source defined (see inputs table).step 3: pull outbound samples per channel (parallelize if possible).
kb/raw/style-<tenant>-<channel>-<timestamp>.jsonl (one JSON object per line: {id, body, timestamp, platform}). do not mutate or filter yet.{type: observation, key: style_thin_<channel>, insight: only <N> samples / <W> words, learned prompt confidence will be lower, source: observed, confidence: 6}. proceed anyway.{type: observation, key: style_nosamples_<channel>, insight: no outbound samples on <channel>; using neutral template, source: observed, confidence: 6}. skip to step 3b for this channel.step 3a: classify messages (for channels with ≥1 sample).
scripts/message_classifier.py (LLM + heuristic): classify each message as OUTREACH_COLD, OUTREACH_FOLLOWUP, OUTREACH_WARM, or NOT_OUTREACH (e.g. internal chat, personal notes).step 3b: run Prompt Learning Protocol (5 iterations, per channel).
scripts/style_evaluator.py for implementation):{iter: <N>, score: <avg_score>, dimensions: {sentence_length: <X>, ...}}.step 4: write learned style file.
~/.openclaw/outclaw/styles/<tenant>/<channel>_style.md (never kb/styles/* or kb/me/styles/*).tenant, channel, trained_at (ISO 8601 timestamp), sample_count, best_score, best_iteration, dimensions (array), conformity_log (array of {iter, score} objects).## Instructions (the learned prompt, actionable and direct), ## Avoid (list of anti-patterns the user avoids), ## Reference samples (pointer to the raw .jsonl file, not verbatim dump).step 5: update memory (tenant KB).
{type: user, key: style_trained_<channel>, insight: "<channel> style trained; score <best_score>/100; <sample_count> samples", source: observed, confidence: <best_score/10>}.step 6: report to user (if explicit invocation) or return silently (if auto-invoke).
consent check (step 1):
style_consent memory entry exists and true, proceed.channel readiness (step 2):
ready in capability map, skip it entirely (no plugin available).ready but plugin call times out or returns 401/403, log observation and skip that channel. proceed with others.sample sufficiency (step 3):
outreach classification (step 3a):
iteration refinement (step 3b):
scripts/style_evaluator.py.neutral template fallback (step 3b, 4):
---
tenant: <tenant>
channel: <channel>
trained_at: <ISO 8601>
sample_count: 0
best_score: null
best_iteration: null
dimensions: []
conformity_log: []
---
# <channel> style , <tenant>
## Instructions
Write in a direct, warm, professional tone. Keep sentences concise (12-18 words average).
Personalize the opening. End with a single, clear call-to-action.
## Avoid
- corporate jargon
- unnecessary formality
## Reference samples
No outbound samples available.
mark confidence as 6/10 in memory.auto-invoke return (step 6):
style prompt file:
~/.openclaw/outclaw/styles/<tenant>/<channel>_style.md (one file per channel per tenant).## Instructions section (500-2000 words, actionable style guide), ## Avoid section (bulleted anti-patterns), ## Reference samples section (pointer to raw .jsonl file).raw samples archive:
kb/raw/style-<tenant>-<channel>-<timestamp>.jsonl (JSONL, one message per line).{id, body, timestamp, platform, classified_as} (e.g. "OUTREACH_COLD").memory entry:
style_trained_<channel>.{insight: "<channel> style trained; score <X>/100; <N> samples", source: observed, confidence: <X/10>}.error/observation logging:
style_thin_<channel> (if <20 samples), style_nosamples_<channel> (if 0 samples), style_no_consent (if consent missing on auto-invoke), style_auth_failed_<channel> (if plugin auth expired), etc.explicit invocation (user says "learn my style"):
styles/<tenant>/email_style.md, styles/<tenant>/slack_style.md, etc.style_trained_email, style_trained_slack, and any style_thin_* observations.~/.openclaw/outclaw/styles/<tenant>/*_style.md to read the learned Instructions and Avoid sections.auto-invoke (outclaw-plan calls during draft planning):
styles/<tenant>/<channel>_style.md before outclaw-plan resumes.style_trained_<channel> entry./styles/<tenant>/, they see the trained style file and know the channel was auto-styled.failure cases (user knows something went wrong):
style_auth_failed_slack); channel skipped; user prompted to reconnect plugin.