stylesync
This server exposes StyleSync tools for rewriting Vietnamese drafts into the owner’s voice and checking backend health.
Rewrite a neutral Vietnamese draft into the owner’s casual voice using
rewrite_style, withtaskset tomessage,commit, orcomment.For commits, pass the whole commit message; the server preserves the conventional-commit prefix, trailers, and code spans outside the model’s rewriting.
Use the returned
textverbatim; ifguard_passedis false, fall back to the neutral draft and report warnings.Check whether the local
llama-serverbackend is reachable, the StyleSync adapter is loaded, model files are present, and last latency viahealth.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@stylesyncrewrite this commit message in my voice: feat: add login"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
stylesync
A small local model that rewrites a neutral Vietnamese draft in your own voice: your abbreviations, pronouns, code-mixing and sentence length. Coding agents (Claude Code, omp) call it through an MCP server before they write a commit message, a PR/issue comment or a chat message, so what they write sounds like you, not like an LLM.
Model: a LoRA (r16) on Gemma 4 E2B, served as GGUF (base Q4_K_M + a 48MB LoRA) by
llama-server. One server on127.0.0.1is shared by every agent session.Safety net: the model only changes the voice. The MCP server keeps the conventional-commit prefix, trailers and code spans out of the model's reach and checks the result. If anything fails it returns the neutral draft.
Data: your own Messenger and Discord exports. A large model (OpenAI Batch here) back-translates each of your messages into a neutral version, which gives (neutral → yours) training pairs.
This repository holds the code, configs, tests and the aggregate reports of one run. It ships no data and no model weights: an adapter trained on private chats memorises them, so the owner's adapter stays private, and yours should too.
Results of the reference run
From reports/ (owner's data, aggregates only):
Training data | 8,769 own messages → 17,038 neutral/own pairs; train 12,707 / val 1,649 / test 1,708 (time-based split, 24h embargo) |
Training | 31 min on an RTX 3060 12GB, 1 epoch |
Style on the test set | 100% classified as the owner's (base model zero-shot: 6%) |
Meaning kept (LLM judge, 1–5) | 4.81, against 4.90 for GPT few-shot with 10 retrieved examples |
Owner-written commit/comment set (40) | guard pass 100% with code-span masking, meaning 4.97 |
Blind test (owner, 50 pairs) | 68% told apart (goal ≈ 50%: not reached) |
Latency | 0.4–0.9s per call on an M4 (Metal); ~1.3s on Windows/Linux after the first call |
API cost | ≈ $1.62 of OpenAI Batch for neutralizing and judging |
Full write-up (Vietnamese): reports/project_report.md. Plan and design notes: IMPLEMENTATION_PLAN.md.
Related MCP server: Natural Voice MCP
Layout
Path | What |
| Phase 1: parse exports, burst merge, PII scrub, filters, style drift |
| Phase 2: back-translation with the OpenAI Batch API, validator |
| Phase 3: time-based split, TRL prompt-completion files |
| Phase 4: LoRA SFT with Unsloth + TRL (CUDA, Linux/WSL2) |
| Phase 5: style classifier, stylometry, LLM judge, gate |
| Phase 6: LoRA → GGUF, parity against PyTorch, install |
| Phase 7: MCP tools |
| Usage history and the owner's corrections, exported as training pairs |
| One YAML per phase; |
| omp skill and |
| Model/runtime benchmark with 40 synthetic sentences |
| Aggregate reports of the reference run |
Train your own voice
Only train on messages you wrote, keep data/, runs/ and models/ private (they are gitignored), and do not
publish the adapter. Python 3.11–3.13 and uv.
Exports. Put your Facebook export (
your_facebook_activity/, JSON) and your Discord data package (package/) in the repo root, or edit the paths and cutoffs inconfigs/filter.yaml.Clean (Phase 1).
uv run stylesync-datawritesdata/processed/mine.jsonl,configs/threads.yaml(setinclude: falseto drop a thread, then run again) andreports/data.md.Neutralize (Phase 2). Needs
OPENAI_API_KEYin the environment; only PII-scrubbed text is sent, withstore: false. Tryuv run stylesync-neutralize run --pilotandreview --n 100first, thenuv run stylesync-neutralize run. Batches can take hours.Dataset (Phase 3).
uv run stylesync-dataset.Train (Phase 4), on a CUDA GPU under Linux/WSL2 (8–12GB VRAM).
uv sync --group train, thenuv run --group train stylesync-train --exp gemma4-e2b-r16-e1. Experiments live inconfigs/train.yaml; add--max-steps 20 --limit 400for a smoke test and--resumeto continue from a checkpoint.Eval (Phase 5, optional).
uv run stylesync-eval gen --system <name>(GPU), thenfewshot,judgeandreport(OpenAI Batch). Settings inconfigs/eval.yaml.Export (Phase 6). Put the base GGUF (
gemma-4-E2B-it-Q4_K_M.gguf, Unsloth's Q4_K_M ofgoogle/gemma-4-E2B-itin the reference run) inmodels/gguf/, copyruns/<exp>/adapterto this machine, and set up the converter thatconfigs/export.yamlpoints at: a llama.cpp checkout intools/llama.cppand a venv intools/venv-convertwithrequirements/requirements-convert_lora_to_gguf.txtandtransformers>=5.17. Thenuv run stylesync-export convertand, optionally,parityandreport.
Tests need no model and no data: uv run pytest -q.
Use with Claude Code
Needs llama-server (llama.cpp) on PATH and the GGUF build from step 7.
uv run stylesync-export install
claude mcp add --scope user stylesync -- uv run --directory /path/to/fine-tune-chat stylesync-mcpIf Claude Code runs from an app whose PATH lacks Homebrew, give absolute paths: /opt/homebrew/bin/uv as the
command and -e STYLESYNC_LLAMA_SERVER=/opt/homebrew/bin/llama-server (after the server name).
install copies the base and LoRA GGUF to platformdirs.user_cache_dir("stylesync") (macOS:
~/Library/Caches/stylesync). The first rewrite_style call starts one llama-server on 127.0.0.1:18080,
detached, and later sessions reuse it; its log is llama-server.log next to the models. Overrides:
STYLESYNC_LLAMA_URL, STYLESYNC_MODEL_DIR, STYLESYNC_BASE_GGUF, STYLESYNC_LORA_GGUF, STYLESYNC_LLAMA_SERVER.
The tool description alone is not enough for Claude Code to call a deferred MCP tool (Phase 0), so add a rule to
~/.claude/CLAUDE.md:
## stylesync
- Trước `git commit`, `gh pr comment`, `gh issue comment` hoặc gửi tin thay t: viết bản trung tính tiếng Việt
(xưng anh/em như t, kh dùng tôi/bạn; code, path, identifier để trong backtick), gọi
`mcp__stylesync__rewrite_style` (task: commit | comment | message) và dùng nguyên văn `text` trả về.
- `guard_passed: false` → dùng `text` (bản trung tính) và báo t lý do trong `warnings`.
- T chê bản viết lại ("viết lại", "kh giống t", "bỏ chữ X"…) hoặc tự gõ bản khác: sửa tay theo ý t (kh gọi
lại `rewrite_style`, ra y chang), dùng bản mới, rồi gọi ngay `mcp__stylesync__rewrite_feedback` (`id` của lần
rewrite, `final_text` = nguyên văn bản mới đầy đủ, `by`: `owner` nếu t gõ nguyên câu, `agent` nếu m sửa theo
lời t). Mỗi lần sửa tiếp lại gọi với bản mới nhất. T nói ok luôn → gọi với `final_text` rỗng; t kh nói gì thì thôi.
- Tin gửi người thật: đưa t xem trước, kh tự gửi.Change the pronouns in the rule to the ones you use.
Collect corrections for the next training run
Each rewrite_style call is logged to history.jsonl in platformdirs.user_data_dir("stylesync") (macOS:
~/Library/Application Support/stylesync), owner-only and outside the repo; the tool returns its id. When you
ask the agent to change a rewrite and then approve a version, the rule above has it call rewrite_feedback with
that id and the approved text. A rewrite with no feedback counts as used as is after 24 hours.
STYLESYNC_HISTORY moves the file; STYLESYNC_HISTORY=off turns logging off.
uv run stylesync-feedback stats # counts, correction rate, progress toward 500 corrections
uv run stylesync-feedback review # go through your corrections, drop the bad ones
uv run stylesync-feedback export # PII-scrubbed pairs -> data/processed/feedback.jsonlAdding these pairs to the training set is not built yet (plan section 10.6).
Use with omp
omp (oh-my-pi) reads its own config, not Claude Code's. Add the server to ~/.omp/agent/mcp.json under
mcpServers (the tool is then mcp__stylesync_rewrite_style, called through xd://):
"stylesync": {
"type": "stdio",
"command": "/opt/homebrew/bin/uv",
"args": ["run", "--directory", "/path/to/fine-tune-chat", "stylesync-mcp"],
"env": {"STYLESYNC_LLAMA_SERVER": "/opt/homebrew/bin/llama-server"}
}Then link the skill and append the rule to the user-level context file:
ln -s "$PWD/integrations/omp/stylesync" ~/.agents/skills/stylesync
cat integrations/omp/AGENTS.md >> ~/.omp/agent/AGENTS.mdStop the backend: pkill -f "llama-server.*stylesync-lora" (Windows: end llama-server.exe in Task Manager).
Limits
Vietnamese only; one voice per adapter (no tone switch).
The blind test did not reach chance level, and the judge shares a model with the strongest baseline.
CI (
.github/workflows/ci.yml) runs the tests on Linux, macOS and Windows; the model itself was run by hand on macOS (Metal), Windows and WSL2.
License
MIT, see LICENSE. The license covers this code only. Base models keep their own licenses (Gemma 4: Apache 2.0),
and a model trained on chat exports carries the privacy of everyone in those chats.
Available Tools
2 toolshealthA
Report the local llama-server backend: reachable, stylesync adapter loaded, model files, last latency.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full burden, and it does disclose the report contents (reachable, adapter loaded, model files, last latency), which implies a non-mutating diagnostic. It does not say what happens when the backend is unreachable — a returned status versus an error — nor whether the call can block on a network probe, which matters for a health endpoint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One compact sentence, front-loaded with the verb and target, then a colon-delimited list of reported facets. Every token carries information; there is no preamble or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no parameters, the description effectively serves as the return-shape documentation by enumerating the reported fields, which is what an agent needs to interpret the result. The remaining gap is failure semantics — whether an unreachable backend produces a report value or throws.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero parameters, so there is nothing for the description to disambiguate; the baseline of 4 applies. The description correctly adds no parameter detail it does not need.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb (Report) and a specific resource (the local llama-server backend), then enumerates the exact facets reported: reachability, stylesync adapter load state, model files, last latency. That is clearly distinct from the only sibling, rewrite_style, but the differentiation is implicit rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the name and the diagnostic verb: call this to verify the backend before or after invoking rewrite_style. However, the description never says when to call it, when not to, or names rewrite_style as the downstream consumer, so the agent must infer the routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rewrite_styleA
Rewrite a neutral Vietnamese draft into the owner's own voice (casual, abbreviations, Gen Z).
Call this before writing a commit message, a PR/issue comment, or a chat message on the
owner's behalf. `text` is a complete neutral draft in Vietnamese that addresses people with
anh/em, as the owner does (not tôi/bạn); keep code, paths and identifiers in backticks.
`task` is message | commit | comment; for a commit pass the whole message: the
`type(scope):` prefix and trailers are kept by code. Use the returned `text` VERBATIM: do
not fix spelling, abbreviations or tone. If `guard_passed` is false, `text` is the neutral
draft; use it and tell the owner why (`warnings`). Never send a message to another person
without the owner seeing it first.
| Name | Required | Description | Default |
|---|---|---|---|
| task | No | message | |
| text | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: it discloses that code preserves the type(scope): prefix and trailers for commits, defines the guard_passed=false fallback (text reverts to the neutral draft, warnings explains why), and mandates verbatim use of the returned text. These are non-obvious behaviors an agent could not infer from the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, then the when-to-use, then parameter details and the verbatim/fallback rules. Dense but nearly every clause adds operative information; the closing safety instruction is policy-adjacent rather than tool behavior, a minor surplus.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description explains the return contract (text, guard_passed, warnings) and the exact obligation to reuse text verbatim. For a two-parameter transformation tool this leaves nothing an agent needs in order to call and consume it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and the task param has no enum in the schema, yet the description compensates fully: text is a complete neutral Vietnamese draft addressing people as anh/em (not tôi/bạn) with code/paths/identifiers in backticks, and task is enumerated as message | commit | comment with commit-specific guidance to pass the whole message.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with a concrete transformation target: rewrite a neutral Vietnamese draft into the owner's voice (casual, abbreviations, Gen Z). The input and output artifacts are both named, so an agent knows exactly what goes in and what comes out.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to call it (before writing a commit message, PR/issue comment, or chat message on the owner's behalf) and adds a hard constraint: never send a message to another person without the owner seeing it first. There is only one sibling (health), so no alternative routing is needed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.0.1- First observed
health - First observed
rewrite_style
TDQS
Scored across 2 tools
The two tools have clearly distinct purposes: rewrite_style transforms text into the owner's voice, while health reports backend status. There is no realistic overlap or risk of misselection between them.
rewrite_style follows a clear verb_noun snake_case pattern, while health is a standalone noun. This is a minor deviation, but the meaning remains obvious and predictable.
The surface is very narrow: one core transformation tool plus a health check. Two tools is borderline thin, though it may be appropriate for a tightly scoped style-rewriting backend.
The core rewrite operation covers message, commit, and comment use cases with guard and warning feedback, and health covers backend visibility. Minor gaps remain around style configuration or inspecting the owner profile, but core workflows are covered.
Maintenance
Related MCP Connectors
Rewrites the emails, messages and PR text your agent writes so they sound like you, every fact kept.
Voice and context layer: draft, check and approve posts in a real person's measured voice.
Rewrite AI-generated text so it reads as human, in a persona's voice.
Build a voice from your own texts, measure whether a text still sounds like you, then write in it.
Related MCP Servers
- FlicenseAqualityCmaintenanceEnables LLMs to access a user's personal writing context—voice, style, opinions, expertise, projects, and communication patterns—via curated markdown files, helping the LLM match the user's voice when generating written content.22-
- AlicenseNot gradedqualityCmaintenanceProvides writing guidance and mechanical lint checks to help AI clients draft or rewrite content in a specific natural voice.MIT
- FlicenseNot gradedqualityBmaintenanceEnables agents to rewrite drafts in your own voice, adapted to the occasion and channel, by learning your style from samples you wrote and from feedback on what you actually send. Supports multiple "Hands" per account with tools for creating, updating, and inspecting learned rules, style cards, and usage.-
- AlicenseAqualityBmaintenanceEnables AI assistants to learn a user's Korean writing style from their own posts, build style guides, and check drafts against that style, including per-kind conventions for blogs, notices, emails, and other writing types.12MIT