How it works

← Back to the app
← Back to the app

Palmer Business Concepts Article Researcher

This tool turns a topic and your own stance into a research-grounded written piece — a LinkedIn post, a longer blog-style article, or another format you pick (see "Formats" below) — using a small pipeline of specialised AI agents instead of one model trying to do everything at once. Each agent has one job, hands its output to the next, and the whole thing runs on its own until there's a finished piece for you to look at — that's the one checkpoint that matters.

Accounts, and why there's an approval step

This app requires a login. By default, accounts are admin-created only: there's no public sign-up form, an admin creates your account for you directly from the Admin page (an email and a starting password they choose), and it's usable immediately, no separate verification or approval wait, since the admin creating it is already vouching for you.

Self-registration (a public "Register" page) can be turned on instead, if the deployment wants it — ask whoever runs this if you don't see a "Register" link on the login page and think you should. When it's on, registering doesn't get you in immediately:

  1. Register with your email and a password.
  2. Click the verification link sent to that email, to confirm you actually own it.
  3. Wait for an admin to approve your account. This is a real holding state, not a formality — you can't log in until it happens.

The very first person to ever register on a given deployment is the exception: they're automatically the admin, and skip the waiting-for-approval step (there's no one else yet to approve them).

Once you're logged in, your account is your identity here — there's no separate "who's posting" field to fill in. Every run you start is automatically credited to you, and written in your own voice (see "Edit my voice" on Step 1, and "Getting the most out of it" below).

Two small safeguards worth knowing about: registering with an email that already has an account here always shows the normal "check your email" confirmation — it never tells you outright that the address is taken, that's deliberate (a security measure, not a bug), and the actual account owner gets a heads-up email either way. And repeated failed login attempts from the same place get temporarily blocked for a few minutes; if you see that message, it isn't a login problem, just wait it out and try again.

Formats: this isn't just a LinkedIn-post tool

This project started as a LinkedIn post generator, and that's still one of the formats it writes. The "Format" dropdown on Step 1 picks which kind of piece the Writer produces, and it's a real behavioural switch, not a label: it changes the Writer's actual structural rules (target length, opening style, whether headings or hashtags make sense), while voice, grounding, and the agent chain itself stay exactly the same either way.

LinkedIn post

150–250 words, a scroll-stopping first line or two (LinkedIn truncates to "see more" on mobile), short paragraphs, and 0–3 hashtags added by the Reviewer at the very end.

Article (blog / newsletter / general)

500–1200 words, a substantive opening paragraph rather than a click-optimised hook, optional Markdown subheadings for longer pieces, and no hashtags anywhere.

Long-form article (deep dive)

1500–3000 words, multiple subheadings expected, for a topic that genuinely needs more room. The Researcher gathers a correspondingly deeper brief for this one (more facts, more counterarguments, an added background/context section), not just a bigger word-count target for the Writer — see "Why longer isn't just a bigger number" below for why that matters.

Whichever format you pick, the anti-fabrication rules never change: every statistic, named source, and quote still has to trace back to the research brief, and the Critic and Groundedness Checker enforce that identically regardless of format.

The agents, and why there are five of them

Splitting the work into separate agents, each with a narrow job and its own prompt, catches problems a single "write me something about X" prompt can't: a model drafting and grading its own work in one pass has no independent check on itself. Here, the Critic's entire job is to be adversarial toward the Writer's draft, and the Groundedness Checker's entire job is to re-verify the finished piece against the original research, independently of whatever the Writer and Critic already agreed on.

Researcher

Takes your topic, stance, and any extra context, and produces a research brief using Anthropic's web search tool (capped at a fixed number of searches per run). The brief includes key facts, data, and recent developments, each grounded in an actual citation the search tool returned — not the model's own paraphrase of what it searched. Those citations are what populate the Sources list.

Writer

Turns the brief plus your stance into a full draft, in your (or the selected voice's) writing style, following whichever format you picked (see "Formats" above). Every statistic, named source, or quote it uses must come from the brief — it's not allowed to invent supporting facts, regardless of how the piece's tone or structure is shaped by a voice profile.

Critic

Reviews the draft adversarially against the brief and flags anything unsupported, weak, or off-stance. It ends every review with an explicit verdict — APPROVE, MINOR_REVISE, or MAJOR_REVISE — which is what actually drives the loop back to the Writer (see "How a run flows" below).

Reviewer

A final formatting and voice pass over the piece once the Critic has approved it (or the round cap is hit). This is what actually produces the text you see as the "Final post" (the panel keeps that name regardless of which format you picked).

Groundedness Checker (optional, on demand)

A second, independent pass over the finished piece, run separately from the four above. It cross-checks every statistic, named source, and quote against the research brief one more time, catching a plausible-sounding fabrication that slipped past both the Writer and the Critic. It scores the piece 0–5 and produces a claim-by-claim report you can feed straight back into Revise.

Source Overview Agent (only if you turn on source review)

Runs once per source, only when "Review sources before drafting starts" is checked. It fetches each source's actual page and writes a short overview of what it covers plus a relevance note, so you're deciding what to keep based on real content, not just a citation link.

How a run flows

The normal path

Researcher
web search → brief + sources
Writer
brief + stance → draft
Critic
draft vs. brief → verdict
Reviewer
approved draft → final piece

If the Critic's verdict isn't APPROVE, the draft goes back to the Writer with the critique as feedback, and the Critic reviews it again — this repeats automatically until an APPROVE, or until the critique/revise round cap is hit (default 3, adjustable per run), whichever comes first. You don't click anything to make this loop happen; it's what "Run" is doing behind the scenes while you watch Step 3 fill in.

Optional: reviewing sources first

If you check "Review sources before drafting starts," the run stops right after research instead of going straight to the Writer. The Source Overview Agent writes a short summary of each source, you get to drop ones that miss the mark and paste in your own, and only once you click "Continue to Draft" does the rest of the pipeline (Writer → Critic loop → Reviewer) run. Continuing actually re-runs research from scratch with your final source list as a hard requirement/exclusion list — not a quick edit of the existing brief — because prose that already wove in a since-removed source can't be cleanly un-influenced after the fact.

Where you actually step in

The pipeline is designed around one real checkpoint — the finished piece — not one approval click per stage. Everything before that runs on its own. Once you have a final piece, a few things are available:

Getting the most out of it

Write your stance like you'd say it out loud

The stance field is free text on purpose. "I think most AI governance policies are compliance theatre, the real risk work has to happen at the architecture level" gives the Researcher and Writer something with an actual point of view to work from. A diplomatic, hedge-everything summary gives them nothing to sharpen against, and you'll get a blander piece back.

Use "Suggested source URL" when you already know the piece

If you've already read the article you want this piece to respond to or draw on, paste its URL in rather than leaving it to search luck. It becomes a REQUIRED source: the Researcher must weave it in, and the Critic checks that it actually did, so it can't quietly get dropped during revisions.

Turn on source review for anything you'll put your name on

The Researcher's citations are grounding metadata, not something you've read. Reviewing sources first costs one extra step, but means every source that goes into the brief is one you've actually looked at and endorsed — worth it for anything more than a low-stakes piece.

Always run groundedness before you actually publish

It's off the critical path on purpose — a second, independent pass, not a rubber stamp from the same process that already approved the draft. It's the single best defence against a confident-sounding fabricated statistic making it into a piece with your name on it.

Give feedback to Revise like you're editing, not restarting

"Cut the second paragraph, it's too long" or "lead with the number instead of the question" works better than vague notes like "make it better." Revise reuses the existing research, so specific, editorial feedback is what it's actually built to act on efficiently.

Set up your own voice once you're logged in

"Edit my voice" on Step 1 isn't just cosmetic — it's the actual writing style the Writer, Critic, and Reviewer use for every run you start. Write it about how you actually write (opening style, paragraph length, tone), not a generic label; it shapes structure, never the facts a piece is allowed to state.

If you hit the round cap, fix the brief, not the draft

Hitting the critique/revise cap without an APPROVE usually means the stance or topic framing needs work, not that one more Writer pass would have fixed it. Read the last critique (visible in the stream) to see what kept failing, then adjust your stance/context and start a fresh run.

A cancelled or errored run still gets exported

Every run — finished, cancelled, or errored — is saved to runs/<run_id>.json the moment it stops, so partial work from an interrupted run is never silently lost, even without a "browse past runs" view in the UI yet.

Why longer isn't just a bigger number

Each format's research brief is sized to actually support its own target length (see "Formats" above). If a topic needs more than 1200 words, pick "Long-form article" rather than pushing a shorter format's target way up: its brief has more real material to draw on, so a revision has less reason to pad or drift into an unsupported claim to fill space, which is exactly what a critique round further along in the loop is checking for.

Technical notes

Why re-research instead of editing the brief

When you continue after source review, the pipeline resets brief and sources and calls the Researcher again from scratch, rather than trying to strip a removed source's influence out of prose that already incorporated it. There's no reliable way to "un-cite" something from already-generated text; a second full research pass with an explicit exclusion/requirement list is the only way to guarantee the brief the Writer sees matches your final call.

The critique/revise loop is a capped backstop, not a target

The loop exits the moment the Critic's own VERDICT: line says APPROVE; the round cap (default 3, configurable per run up to 10, or via ARTICLE_AGENT_MAX_CRITIQUE_ROUNDS) only exists so a stubborn draft can't loop forever. If the Critic's response doesn't parse a recognisable verdict at all, the pipeline fails closed — it's treated as MAJOR_REVISE (keep looping), never silently treated as an approval.

A later round can score worse than an earlier one, and that's handled

Every critique round is an independent read of whatever the current draft is, the Critic never sees its own previous verdict, so revisions aren't guaranteed to improve monotonically round over round — fixing one of its seven criteria can introduce a new issue on a different one, especially on a longer piece with more room to drift. The pipeline tracks the best-scoring round across the whole loop, not just the latest one, and uses THAT draft for the final review if the loop ends on a worse round than an earlier one achieved. You'll see a round N's revision scored worse... note in the stream when this happens; the finished post may then come from an earlier round than the very last critique you watched stream in, that's expected, not a bug.

What "required source" enforcement actually means

A suggested source URL and any URL you add during source review are both fetched directly (not via web search) and handed to the Researcher as binding, not optional. The Critic separately checks whether the draft actually incorporates something specific from each required source — not just a generic statement that happens to be compatible with it — and treats a missing one as grounds for at least MINOR_REVISE by itself, regardless of how the rest of the draft scores. Both an ordinary web page and a PDF link work here, the text gets extracted either way; a password-protected PDF or anything that isn't a page or a PDF (an image, a raw API endpoint) fails the fetch the same way an unreachable link would.

Live updates use Server-Sent Events, not polling

Starting a run returns a run_id immediately; the page then opens a one-way event stream (GET /api/runs/<run_id>/events) and renders each stage as it arrives. Revise and Check groundedness reopen that same stream with a since parameter so only the new pass replays, not the entire run's history from the start.

Cancellation is cooperative, not instant

Clicking Cancel sets a flag the pipeline checks at the start of its next stage (research/draft/critique/final-review/groundedness) — never mid-call. Whatever Anthropic API call is already in flight when you click always finishes first; there's no cheap way to abort a streaming request mid-generation without real added complexity for a few seconds saved at most.

The footer's timestamp is the server, not the page

"Server running since …" at the bottom of the main page is when the running server PROCESS last started, not when any file was last edited. A real deploy (rebuilding/restarting the container) always changes it; a browser just showing you a stale cached page does not, that's exactly what makes it useful for telling those two apart if an update ever looks like it "didn't take."

Suggested-source fetches are SSRF-guarded

Any URL fetched directly (a suggested source, or one you add during source review) has its hostname resolved and checked before the fetch happens; anything resolving to a private, loopback, link-local, or reserved address (plus localhost and *.local) is refused. This matters once the app is reachable from more than just your own machine, since a raw URL-fetch field is otherwise a way to make the server issue requests to itself or other machines on its network.

Voice text never touches the correctness rules

A person's voice text only ever shapes the Writer/Critic/Reviewer's tone, word choice, and structure. The anti-fabrication instructions (the Writer's "every statistic must come from the brief," the Critic's factual-risk check, the Groundedness Checker's independent pass) live in separate, fixed prompt text that no voice parameter ever reaches — a voice can change how a piece sounds, never whether its claims are allowed to be made up. The format picker (see "Formats" above) works the same way: it's a separate, fixed structural block per format, never something a voice or a prompt injection in your own topic/stance text could bend.