Loading works…
Blogtool
A desktop hub for running several blogs side by side. Topic suggestion, drafting, fact-checking, image sourcing, machine checks and Tistory publishing all run from one button; only the last click stays with me. Fact-checking reads authoritative sources in full and records why a source could not be read when it cannot.
Screenshots
Overview
A multi-blog hub for running several blogs and switching between them. Each blog keeps its own subject area, platform, voice and length rules. Everything from finding a topic to drafting to filling the publish screen is automated; only the final [Confirm]/[Publish] click stays with me.
It is a rebuild of an earlier tool (blog-kit) that was welded to a single site. Subject areas and voice rules lived in code, so adding a blog meant copying the code. Now a blog is a JSON profile you register and switch to.
The core
Title selection, prompt assembly, drafting, fact-checking, image sourcing and machine validation all run from one [Generate] button. No step is joined by hand.
Fact-checking is a gate. Figures and claims in the generated text are checked against web sources and corrected or cut, with the reasoning and the citations kept in a report. Sentences with no evidence behind them are removed.
Publishing is down to one channel, Tistory. A dedicated profile browser is driven directly to fill the title, body (with images), link cards, tags and category, and the tool rereads the editor to confirm the paste actually landed. A heavy draft can take several seconds to fill in, so it polls up to a deadline instead of waiting a fixed amount once. Once confirmed, the [Confirm] and [Publish] clicks stay with me.
For images, a contextual photograph leads rather than a synthesised card. Overlapping or clipped card text is measured in a real browser and fixed automatically. Posts that need tables or figures get a real spreadsheet driven and captured.
Fact-checking that actually reads its sources
Some findings from fact-checking used to stay unresolved. Sites like Korea's national statute database render the article body with JavaScript, so even the most authoritative source handed back only a few hundred characters. The more reliable a citation was, the less it could be confirmed.
Each site can now have its own way of getting the full text. A site like Korea's national statute portal, which offers an official API for the full article, gets read through that API first, and the verdict cites it by name (the official statute API) rather than the page it could not render. If that path fails, the check falls back to the plain page.
Some sources still cannot be read this way, such as the tax authority's statute portal, which has no public API. Instead of a bare "could not verify," the verdict records why the source could not be read, and points to an alternative statute source when one covers the same ground.
Figures such as insurance rates cannot be judged right or wrong without something to compare them to. National pension, health insurance, employment insurance and long-term care rates now sit in a table alongside their statute citations, and the machine checks the numbers in the draft against that table directly. It also confirms the cited statute name matches, so a lookup cannot land on the wrong law.
An unresolved finding no longer disappears quietly. It shows up as a "needs review" item in the check results, and the publish-readiness screen leads with that item.
Made to run outside my machine
There are now three writing backends: Claude Code, Codex, and a local model (run through Ollama). They are equals: any stage can run on any of them.
Each stage names a preference, but a preference is all it is. If the named backend is switched off or missing, another takes over automatically; only when none can be used does the tool speak up, and then it says exactly what to connect and how. It does not fail quietly.
So the person receiving this doesn't have to wire it up by hand, a single [Connect] button now handles it: if a CLI is missing it installs it (winget, or a fallback script), then walks through login. Paste a key in and it gets validated with a real call, not just stored. A blog just needs its address; the tool figures out the name and a publish-verification source (sitemap or RSS) on its own.
Login detection got firmer too. The old path spawned CLIs through npm's shim scripts and misread ENOENT/EINVAL as "not logged in"; it now resolves the native executable and entry script directly, which also stops a subscription login from silently leaking into API-key billing.
Runnable before a blog is even registered
The first-run order changed to AI connection → topic field → blog address (optional). Someone who hasn't picked a blog address yet can still look around the tool.
Choosing a topic field used to require an existing blog record, so if nothing is registered yet, the tool quietly creates one default blog behind the scenes, and leaves it alone if one already exists. This step counts as done not when a record exists but when a real address has been entered, so an auto-created empty blog is never marked "set up."
[Compose] builds the skeleton your way
Until now, [Add Manually] only worked one way: describe an idea, get several AI-suggested topics, pick one. The structure after picking it, how many subheadings, where the images go, was also decided by the AI.
The new [Compose] tab flips that. You stack text, image, video and file blocks in whatever order you want, building the skeleton (title, then tags, then content) yourself, and the AI only polishes the wording without touching that arrangement. Slipping in an extra block or reordering one doesn't count as a fix, it's treated as a rule violation, and deletions, additions and reordering are all caught mechanically.
A stale pass is not a pass
Edit the text after a check has passed and that pass is no longer a verdict on the text in front of you.
So verdicts now carry a fingerprint of the body. When the text changes, an old PASS is downgraded to "needs rechecking". Marking a post as published while the check has failed or gone stale prompts a confirmation.
Which stage a topic is at is likewise decided by whether the draft file actually exists, not by a stored status field. Status fields drift; files do not. The same idea covers an interrupted run: on the next launch, the tool rereads how far the output got and asks whether to resume from there.
Looking back at what piled up, and clearing it
As posts accumulate, some drop out of the working list. blog audit pulls back posts that were published and fell off the list; blog gc inventories the leftover artefacts and deletes only what it can identify. Files it cannot account for are left alone.
Publication verification is a set of methods rather than one. Each axis carries its own evidence, and Search Console can be disconnected if it is not wanted.
Stack
A Python tkinter GUI (standard library only) and a Node.js CLI engine (no external dependencies). Data is layered into dynamic/ (blogs, topics, material) and static/ (settings, rules) as JSON. No server, no database, entirely local.
The overall text scale is a setting now. It saves immediately but only applies on the next launch, since widgets already on screen cannot resize themselves.
Where it stands
As of 2026-09-29, the status tab shows 183 posts marked published, 4 that have passed the checks and are ready to go out, and 0 held up by a failing check. By channel: 183 on Tistory and 23 on Calqu, across 187 topics in total. Naver support ended in P13 and is no longer tracked as a channel.



