AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
MCP verified MIT Self-run

Persona Forge

mcp-ctkadvisors-persona-forge · by ctkadvisors

Fine-tune persona chatbots that never break character — synthetic roleplay data with judge filtering, DPO against assistant boilerplate, QLoRA recipes, and a local RAG loremaster over MCP

No reviews yet
0 installs
21 views
0.0% view→install

Install

$ agentstack add mcp-ctkadvisors-persona-forge

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/mcp-ctkadvisors-persona-forge)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
23d ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Persona Forge? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

persona-forge

Fine-tune a persona chatbot that never breaks character — and let it search your own books mid-chat with a local RAG "loremaster."

You bring three things: a corpus (plain text you have the rights to use — public-domain classics, your own novel, campaign notes), a base chat model, and any OpenAI-compatible endpoint to act as the data-generation teacher (a local llama.cpp/vLLM/LM Studio server works fine). Everything else is here.

Quickstart

pip install -e ".[data,train]"

# 1. Drop your corpus in:
cp /path/to/your/books.txt data/corpus.txt

# 2. Make your persona pack (start from the Arthurian example):
cp packs/camelot.json packs/mine.json   # then edit — see "Customizing" below

# 3. Generate the training blend (points at your teacher endpoint):
PACK=packs/mine.json CORPUS=data/corpus.txt \
OPENAI_BASE_URL=http://localhost:1234/v1 TEACHER=my-teacher-model \
python -m personaforge.build_data

# 4. Train — continued-pretraining on your corpus, then SFT, then DPO,
#    as one chained QLoRA adapter on a single GPU:
MODEL_ID=Qwen/Qwen3.6-27B DATA_DIR=out/data DO_CPT=1 CORPUS=data/corpus.txt \
python -m personaforge.train_run

# 5. Prove it holds character (bare assignments, provocations, style probe):
MODEL_ID=Qwen/Qwen3.6-27B ADAPTER=out/adapter PACK=packs/mine.json \
python -m personaforge.battery

# 6. Get numbers (held-out eval -> out/eval.json):
MODEL_ID=Qwen/Qwen3.6-27B ADAPTER=out/adapter PACK=packs/mine.json \
OPENAI_BASE_URL=http://localhost:1234/v1 JUDGE=my-teacher-model \
python -m personaforge.eval_run

The adapter in out/adapter is standard PEFT: merge_and_unload() it and convert to GGUF or MLX for serving with your stack of choice.

Give it a loremaster (RAG over your corpus, via MCP)

Persona models hallucinate lore confidently; retrieval fixes what fine-tuning can't. Build a local index, then register the MCP server in any MCP host (LM Studio, Claude Code, ...) so the model can look passages up mid-chat:

uv run personaforge/rag/build_index.py data/corpus.txt data/index

# in your MCP host's config:
#   command: uv
#   args: ["run", "/path/to/personaforge/rag/mcp_server.py"]
#   env:  LORE_INDEX_DIR=/path/to/data/index
#         LORE_DESCRIPTION="the collected Arthurian romances"

Models with native tool training keep that ability through the persona tune — they'll pick lore_search for lore questions and narrate the results in voice.

Customizing: the persona pack

All world flavor lives in one JSON file; the pipeline is world-agnostic. Edit these fields in your copy of packs/camelot.json:

| Field | What it does | |---|---| | world | Spliced into every prompt: "in the voice of {world}" | | cards | Your characters: name, persona, style, pronoun | | scenarios | Situation seeds for generated conversations | | provocations | Rude/crude/meta user turns your model must survive in character | | assignments | Casual persona-assignment phrasings ("be {name}", lowercase happens) | | boilerplate | The assistant-speak to train away from (used as DPO rejected) | | exemplars | A few hand-written dialogues that set the voice ceiling |

Knobs on build_data: N_CONVOS / N_DPO / N_ASSIGN / N_ASSIGN_DPO (volumes), IN_DIR (extend an existing blend instead of building fresh). Keep roleplay at 25–35% of the final SFT mix — the generated general-chat blend does this for you at the defaults.

Evals: retrain and swap models with confidence

build_data reserves every 4th provocation/assignment seed — training never sees them. eval_run generates replies to those held-out prompts and scores:

  • assignment_accuracy — bare "be {name}" answered by the named character

and no other (string check, free, objective)

  • boilerplate_rate — assistant-speak regex over provocation replies (free)
  • incharactermean / voice_mean — judge-scored, needs a teacher endpoint

(omit JUDGE to skip; the free metrics still run)

One JSON report per adapter, so comparing a retrain — or a different base model against the same DATA_DIR — is a diff, not a vibe. The battery (personaforge.battery) stays for eyeballing transcripts; the eval is what you gate a release on.

Why the weird data? (the two failure modes)

Naive persona tunes fail two ways, both reproducible: (1) the boilerplate break — the user gets rude or meta and the model drops the persona for "I am a professional and do not engage in such language"; (2) the wrong-character pickup — a bare "hey, you're merlin. roleplay as him" gets answered by a different character introducing themself. Both are data gaps. The pipeline generates conversations that survive provocation, assignments answered by the named character (with a hard wrong-name check), and DPO pairs whose rejected side is the failure verbatim. In our reference run (27B dense, single unified-memory GPU) this took the DPO reward margin from 0.003 to 0.45 and a clean sweep on the battery.

Recipe notes (hard-won)

  • Reuse the CPT adapter across retrains: set CPT_ADAPTER=out/cpt and skip

the expensive knowledge stage.

  • Pin device_map={"": 0} on unified-memory boxes; "auto" triggers

CPU-offload chaos. (Already done in the trainers.)

  • bitsandbytes 4-bit works on ARM/Blackwell for dense models; MoE models may

crash — set load_in_4bit=False in QLoRAConfig for bf16 LoRA.

  • Thinking-mode base models: eval with thinking disabled, and check your chat

template's default before shipping — some inference stacks force-inject enable_thinking=True.

  • Expect the judge to keep ~75% of generated conversations and ~90% of

introductions; lower than that usually means a weak teacher model.

License

MIT. No corpora, weights, or copyrighted-world data ship here — the pipeline is yours, your data responsibilities are your own.

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.