← All courses ← Course home

Lesson 02 of 08

Prepare your writing data

Clean, format, and split your local writing so the adapter learns writing style, not secrets. Later you will be able to tell those two apart.

Agent brief (llms.md)

Why cleaning your writing comes first

Privacy starts before training. If a token, an address, or another person's message sits in the JSONL, it can sit in the baked model. Read the formatted set the way you would read a production config. Your writing collection (the corpus) never needs a network.

A small, focused set beats a giant dump. You are teaching rhythm and structure. You are not putting a large public scrape onto a phone.

The steps, one box at a time

Collect writing you own or have permission to use.

SourcesLocal writing

Strip secrets, tokens, and other people's private detail.

SourcesLocal writing
CleanRemove secrets and noise

Format every row the same way. Use instruction and response, or completion with a stable delimiter.

SourcesLocal writing
CleanRemove secrets and noise
FormatModel-ready examples

Hold out validation rows and a short list of human review prompts the trainer will never see.

SourcesLocal writing
CleanRemove secrets and noise
FormatModel-ready examples
SplitTrain and validation

Environment setup

Create the project before the first formatting command.

curl -LsSf https://astral.sh/uv/install.sh | sh
mkdir -p writing-style-lora && cd writing-style-lora
uv init --python 3.11
uv venv
uv add torch torchvision transformers peft datasets accelerate safetensors coreai-torch
uv run python -c "import torch; print(torch.__version__); print('MPS:', torch.backends.mps.is_available())"
mkdir -p data/raw data/clean artifacts

Worked path

Keep raw files in data/raw. Do not point the trainer at that folder. Write cleaned JSONL yourself or with a small script you can read.

{
  "instruction": "Rewrite this note clearly.",
  "input": "hey can you send the deck when you get a chance thx",
  "response": "Please send the deck when you have a moment. Thank you."
}

One object per line in data/clean/all.jsonl. Then split.

import json
from pathlib import Path
from random import Random

rows = [json.loads(line) for line in Path("data/clean/all.jsonl").read_text(encoding="utf-8").splitlines() if line.strip()]
rng = Random(0)
rng.shuffle(rows)
cut = max(1, int(len(rows) * 0.1))
val, train = rows[:cut], rows[cut:]
Path("data/clean/train.jsonl").write_text("\n".join(json.dumps(r, ensure_ascii=False) for r in train) + "\n", encoding="utf-8")
Path("data/clean/val.jsonl").write_text("\n".join(json.dumps(r, ensure_ascii=False) for r in val) + "\n", encoding="utf-8")
print(len(train), "train", len(val), "val")
uv run python split_corpus.py
# Inspect after formatting. JSON fields can still hold secrets.
rg -n "sk-|AKIA|password|ssn|BEGIN PRIVATE" data/clean || true

Write human review prompts that are not in the JSONL. You will reuse them against the base, the adapter, and the merged export.

{
  "review_prompts": [
    "Rewrite this Slack message so it sounds like me: 'circle back tomorrow on the numbers'",
    "Turn these bullets into a short update I would send.",
    "Say no to a meeting without sounding curt."
  ],
  "forbidden_in_corpus": ["api keys", "other people's medical notes", "unpublished credentials"]
}
Privacy check. Check the dataset after formatting. Logs, cached prompts, and checkpoints can all carry original text. Keep the source list outside the exported model.

Failure modes

Done when

Keep learning

PyTorch to Core AI in Xcode · From the metal to the model · Core AI models, typed · Model architectures in plain English · Diffusion LoRA to Core AI on device

Key concepts

  • Strip secrets, tokens, and third-party private detail before training.
  • Format rows the same way every time, then split train and val.
  • Write review prompts outside the JSONL.
  • A small focused set beats a giant dump for style.

Takeaways

  • Never point the trainer at raw uncleaned writing.
  • Near-duplicate train and val rows reward memorization.
  • Keep the corpus on the machine. No network is required.