Skip to content
[bmdpat]
All writing
5 min read

My Local Blog Writer Drops Private Lines First

My local blog writer reads a daily log. I remove private lines before drafting, then check the output again. Here is what those checks can miss.

Share LinkedIn

I changed what my local blog writer can read. On September 13, 2026, I made yesterday's daily log its source. That also gave me a concrete privacy problem: the same log holds public build notes and private details.

A local model can still put private text into a public draft. My pipeline removes matching lines before drafting and checks the result again before publication. These checks cover named patterns, so a clean result still needs editorial review.

Canonical URL: https://bmdpat.com/blog/local-blog-writer-drop-private-lines-2026

Drop matching source lines, check the generated draft, and stop publication when private terms match

Why filter the source if the model runs locally?

My normal writer uses Gemma through Ollama on owned hardware. That controls where the normal drafting request runs. It does not decide what belongs on my public blog.

Ollama's FAQ says the company does not see prompts or data when users run locally. It distinguishes local execution from cloud models. That is a statement about inference. My application still decides which files enter a prompt and where the finished text goes.

The daily writer also has an availability fallback. I need to know which model answered, as I explain in local model fallback provenance. I apply the source filter before drafting either way. A failed local load must not change which source lines the writer receives.

Why drop a whole line instead of replacing a name?

The function is scrub_devlog in config/blog/devlog_source.py. It removes the frontmatter, skips a private section, and drops any line that matches a configured private pattern. The remaining lines become the source text.

I chose deletion because a replacement marker can become part of the draft. A model can copy that marker into a sentence and leave the reader with missing information. Removing the line gives the writer less material, but avoids supplying that broken sentence in the first place.

Here is a synthetic example. One line says a parser now rejects a missing field. Another line gives the machine's private contact details. I want the parser result in the source. I want the contact line absent. I do not need the writer to explain that something was hidden.

The tradeoff is blunt. If one line contains both a useful result and a private detail, the filter removes both. I accept that loss for this source path. If the missing result matters, I can write a separate public note that stands on its own.

What do the checks actually test?

The implementation uses Python regular expressions. Python's re documentation describes the pattern matching operations behind those checks. The patterns cover configured categories such as machine names, profile paths, private addresses, contact details, and financial amounts.

On September 14, I ran the existing test_devlog_source.py suite. All eight tests passed. The mixed-source fixture checks that private sections and matching lines disappear. It also checks that a public pull-request result and an expression of doubt survive.

Other tests check clean text, category detection, source-date selection, and the command's exit codes. They also check that the voice profile exists. A missing voice profile raises an error instead of silently giving the writer no profile.

That test count describes this module. It does not measure recall across every possible private fact. It does not prove a model cannot infer a detail from the remaining context. I have no such result to report.

Why check the output again?

The writer's devlog validation scans the title, excerpt, and body for private terms. The publisher scans those fields again before its API request. The publisher sends a matching draft to its rejected folder and records the failure.

I want that last check because source filtering and output validation inspect different text. The first checks the material I supply. The second checks what the model wrote, including text introduced during revision.

This is the same reason I separate valid empty results from failures in my Ollama JSON parser example. The downstream step needs an explicit outcome. A draft that fails a privacy check must not quietly become a publishable draft.

What remains outside this filter?

A pattern list cannot understand every private fact. It can miss an unfamiliar name, an indirect reference, or an address format absent from the list. Several harmless lines can also reveal something when read together.

I still review the finished article. I keep source removal, output checks, and editorial review as separate steps. The useful result from September 13 is narrower: the daily writer now receives fewer private lines, and the publisher has a concrete stop condition.

For a local writer fed by your own notes, start with that boundary. Test one mixed note. Check exactly which lines survive. Then test a generated draft that reintroduces a forbidden detail. Neither test needs a new model or a faster GPU.

Accompanying prompt

What the prompt does: It asks a coding assistant to test source filtering and output rejection with synthetic notes.

Copy/paste this prompt:

Copy-ready prompt

Paste the exact block into your coding agent.

No article chrome, no footnotes, no formatting drift.

Role: Review my local drafting pipeline. Context: It turns private daily notes into public drafts. Task: Inspect source filtering and the final publication check. Output: Give tests for a clean note, a mixed note, and a draft that reintroduces a private detail. State what each test proves. Constraints: Use synthetic data only. Do not read private notes. Do not call a model, publish content, or change the policy. List untested cases. Do not claim complete privacy protection.
8 lines478 chars
Ready

This prompt and every other one we publish live in the free prompt library.

Copy the block above.

Get the 5090 Reports by email.

Get the Local AI Field Kit

Four copy-ready tools now, then one evidence-backed Local AI Lab Note on Friday when there is something worth sharing.

Try the free agent run check first

Get the requested artifact now, then at most one evidence-backed Local AI Lab Note on Friday when there is something worth sharing. One-click unsubscribe. No sponsored placements. Privacy.

PH

Patrick Hughes

I build BMD and publish measured AI runs, failure reports, and reusable checks. Nashville, Tennessee.

More writing