Building AI-Generated Fillable Templates That Actually Work

Building AI-Generated Fillable Templates That Actually Work

1. Building prompt structures that do not collapse during merge tags

First time I tried using ChatGPT to build a fillable Google Doc template, the whole thing broke at the curly brackets. It hallucinated sections, reordered variables, and somehow renamed one of my placeholders to “{Stage_ID}”, which didn’t exist in Airtable. Didn’t notice until I sent a client a doc that said: “Your stage is Stage_ID” — unsubtle.

If you’re generating fillable templates using AI, the problem starts immediately at how AI interprets variable syntax. Anything wrapped in {{double curly brackets}} is interpreted as both a markdown pattern, a potential templating system, or just plain code. The model tries to be helpful and adds logic where there isn’t any. So you need to frame your placeholders very literally and often use an alternate token pattern like <> or [Stage] just to prevent ChatGPT or Claude from helpfully rephrasing it.

I’ve tested this with both GPT-4 and Claude 3 Opus — GPT tends to reword prompt-styled variables inside text bodies unless heavily constrained. Claude does better with structural fidelity but will suddenly insert a colon or header if it thinks that improves readability. Which it doesn’t — not when the goal is dead-simple mail merge.

What worked best:

"Please do not reword placeholders. Use the exact syntax <>. Treat them as static tokens. Do not format them."

That line, verbatim, has salvaged more than one broken output.

2. Avoiding hallucinated headers and duplicate fields in generation

One of the weirdest bugs I hit: asked Claude to generate a fillable agreement from schema fields, and it inserted the field twice. The first as a label, then again as a formatted value. Like:

Project Start Date: <<StartDate>>

Start Date: <>

It thought it was improving formatting — but across 50+ templates, that duplication adds a lot of friction. In Notion, I noticed the synced copies of these templates started showing redundant rows because the AI had copied the field labels deeply enough they confused rollups and filtered views.

This gets weirder if you’re using embedded prompts from tools like Zapier or Make. If you paste a large prompt into a field, those tools often trim whitespace — which makes your carefully separated header and body merge, triggering the AI to collapse formats. You can prevent this with invisible characters (e.g. Unicode thin space or NBSP) between sections that you don’t want merged. Ridiculous, but true.

Undocumented tip: Add a zero-width space before every new field line. It survives most compiler trims and severely reduces ChatGPT’s urge to reformat.

3. Forcing plain-text layout inside Google Docs API interactions

When you store your template as a Google Doc and populate it via the Docs API, you’d assume plain text goes in, plain text comes out. Nope. Docs automatically adds styling inheritance if the parent block has rich formatting. One of my AI-generated templates suddenly showed all input fields in blue italics because the base template had “use friendly font” set in a section heading. Those styles cascaded.

Fixing this required stripping out styles in the insert phase, not just prepping the text. You have to explicitly define the text style as NormalText and remove all text style attributes in the batchUpdate call. Otherwise, any Template Field inserted by the AI inherits random Google Docs formatting and layout spacing. Side note — center-aligned templates will shift injected text to fully left-aligned unless overridden explicitly. Can’t trust the UI preview for this, it lies.

Snippet: Forcing plaintext on insert

{
  "insertText": {
    "location": {
      "index": 275
    },
    "text": "<>"
  },
  "textStyle": {
    "bold": false,
    "italic": false,
    "underline": false,
    "foregroundColor": {},
    "backgroundColor": {},
    "fontSize": {"magnitude": 11, "unit": "PT"},
    "weightedFontFamily": {
      "fontFamily": "Arial"
    }
  }
}

4. Dynamically referencing Airtable data without breaking rendering

I had this whole setup where Zapier pulled Airtable fields and fed them through a GPT-generated contract template. Airtable was supplying proper values — like “August 14, 2024” — but when rendered in the PDF, the placeholders showed actual strings like “<>” instead of the value. Turns out, if any field has a null value at execution time, the template converter skips the replacement entirely. Doesn’t crash — just ignores that merge key. Silently.

The worst part? Zapier doesn’t fail the Zap. It thinks everything went fine. You only catch it when someone opens the signed PDF and says “What’s <> supposed to mean?”

A quick fix: in-between AI and PDF generation, I now run a tiny formatter step that replaces nulls or unknowns with a fallback string like “[missing data]”. At least I can regex for that later and manually fix it.

Also spent a morning chasing a template bug that turned out to be a case mismatch — <> got inserted instead of <>, because Claude thought lowercase was more casual. That ruined downstream field matching and caused Zapier to silently create a new row in Google Sheets without the client value.

5. Using AI output safely inside Markdown to HTML conversions

If you think AI-generated templates will be clean inside Markdown ➝ HTML workflows, brace yourself. Markdown engines (especially ones inside Notion or Obsidian exports) treat <> as potential HTML tags. They get stripped or converted unpredictably, especially by email renderers.

I had a welcome email template built via Claude. Looked fine in test preview but the actual deliverable had entire fields missing — Gmail’s preview collapsed “<>” because it parsed that as a broken tag. Fails silently.

Fix: Wrap placeholders in &lt;&lt;Placeholder&gt;&gt; during pre-processing and decode them right before render. It’s a dumb extra step, but stops most malformed HTML escapes.

On export to PDF or docx though, you’ll want to decode those entities fully — otherwise you get PDFs that literally say “<<CompanyName>>” and you have an intern going line-by-line for replacements. (Yes, me. I was the intern.)

6. Controlling awkward line breaks and sentence wrapping in generated text

Every AI model has a different take on what constitutes a good line break. GPT-4 adds newlines like it’s helping, Claude tends to cram everything into blobs, and Mistral (when fine-tuned) does minimal formatting at all.

I generated a terms of service template that looked fine in the JSON, but printing it in Acrobat Pro shoved entire sentences into margin-overflow errors because GPT inserted soft line breaks inside justified paragraphs — not visible in Docs, but fatal in PDF.

Quick test trick: Export your template to .docx and open in Word. Enable “Show formatting”. If you see manual line breaks (little bent arrow), your source has AI garbage inside it.

To fix this, I had to strip control characters from the AI output. Did a re.sub(r"[\x0b\r\f]", "", text) pass before feeding the text downstream. Also makes it easier to count actual character lengths for capped templates (like form emails where SendGrid has pixel limits).

7. Creating conditional template sections without hitting model max tokens

We hit a cap problem trying to auto-generate multi-scenario contracts. Sections like “if NDA is required, include this block” started pushing GPT-4 responses over the token limit on 8K context. Even at 32K, the system message plus JSON structure plus prompt instructions plus field examples started choking. Half the time, the last few sections just didn’t render.

Solution we landed on:

  • Break prompts into segment templates per feature/section
  • Insert logic flags in the base doc (e.g. <>==true)
  • Use AI only to generate those sections, not the full document
  • Assemble the pieces downstream in Zapier (or Make), not upstream in the prompt
  • Render final doc in Google Docs API after merge

It’s more brittle, but massively improves render consistency. Even lets you translate per-section instead of fighting a 5-language merge artifact from a prompt that went 400 tokens too long.

8. Dealing with flaky spacing and extra paragraphs on final renders

One day the rendered Google Doc had two extra paragraphs after the signature block, one of which just said “Agreement.” Turns out, the AI had added a manual newline + repeated header label, probably because I copied part of the Claude training data from an email chain that had that at the end. Garbage in, garbage infinitely out.

The paragraph didn’t show up in preview. Only in exported docx. Acrobat noticed it when I tried to flatten the PDF. I spent two hours trying to backtrack what it was.

The fix was re-generating the original text generation step, but this time adding hard end-of-content delimiters. Like:

"STOP inserting content after you reach the field <>. Do NOT add extra lines, labels, or footers. End immediately."

You’d think that’s obvious, but without that, the AI just keeps going. Every single time.