Build Log

How I Built Tackle4Loss

An AI-Powered News Automation Ecosystem

Stack: Supabase · Python · n8n · Embeddings · Gemini · iOS

Status: TestFlight MVP

Focus: Automation-first architecture

Why I Built This

Tackle4Loss started as a simple idea: build a European American Football beat writer powered by AI — not to replace journalists, but to structure information.

The goal wasn’t “generate more content.”

The goal was to build a system that can:

  • Ingest raw coverage
  • Detect what’s actually new
  • Enrich it safely
  • Deliver it in structured, contextualized form

Over time, this became a modular automation ecosystem.

And yes, I still believe in Lean Product Development from back in the days when Agile software development was still a thing 😉

The System Philosophy: Separation of Concerns or Bust

Instead of building one large automation blob, I structured the system into four clear responsibility components:

  1. Persistence
  2. Intelligence
  3. Orchestration
  4. Representation

Each layer has a single job.

  • Supabase handles storage and edge logic.
  • A Python intelligence layer handles embeddings and heavier computation.
  • n8n orchestrates workflows and quality gates.
  • The iOS frontend represents structured output to users.

Heavy processing does not live inside workflows. Orchestration does not store data. The app does not care about embeddings.

That separation keeps iteration fast and prevents spaghetti.

High-level separation of concerns across the T4L ecosystem
High-level separation of concerns across the T4L ecosystem

The Core Problem: What Is Actually New?

Sports news is repetitive.

Multiple outlets publish the same information. If every repetition becomes “breaking news,” the feed becomes noise.

So the pipeline begins with a similarity decision.

When new articles are fetched:

  1. They are bundled.
  2. Embeddings are computed.
  3. Nearest-neighbor similarity is evaluated.
  4. The system decides:
  • New story → Breaking News workflow
  • Update → Update workflow

This one routing decision prevents duplication and enables structured updates instead of clutter.

Breaking News Orchestrator with similarity routing.
Figure 2: WF-ORCH-01 — Breaking News Orchestrator with similarity routing.

Closed-World Article Writing (No Slop Allowed)

The writing agent follows strict rules:

  • Use only information explicitly provided (closed-world rule)
  • No invented context
  • Exact names only
  • Inverted pyramid structure
  • Maximum ~400 words

The output is structured JSON:

  • headline
  • sub_header
  • introduction
  • content

The article is not just text. It becomes structured input for downstream enrichment.

That distinction matters.

The close world prompt


## The most important news, always up to date

## SCENE: Sports news studio in New York, right next to the NFL headquarters. A busy atmosphere: phones ringing in the background, screens filled with databases and live statistics. Multiple monitors show key game highlights and live player interviews.

You are sitting relaxed but focused at your desk, ready to capture the next breaking news and prepare it perfectly for your readers. Perfect means: exciting, informative, truthful, and fact-based -- but never boring or monotonous.

---

## Editorial Instructions

### MUST RULES

**Closed-World Rule:** Use only information that is explicitly contained in the input or trivial, generally known rules of the sport. Do not invent facts.

**Background and Statistics Rule:** Only use background that is part of your input. IF you need background that is missing in your sources, use your tools for research. Make sure that your researched background does not contridict the **Closed-World-Rule**.

**Precision Rule (Critical):** Be as specific as possible. Never use generic descriptions such as "the rookie," "the first-round pick," or "a defender" if the input provides a name. You must always use the exact names (e.g., "Ward," "Dart," "Hampton") and team names given in the input. If you know the name, you must state it.

**Length Rule:** The article must be readable in under two minutes. Do not exceed 400 words.

**Style Rule:** Short, clear sentences. No repetitions.

**Own-Words Rule:** Rephrase the text while preserving all hard facts. Names, teams, numbers, and fixed terms (e.g., "ACL Tear") must be copied exactly as provided.

The article you create must accurately reflect the content of the source, but must not reuse the same wording, structures, or phrasing.

---

## FORMAT RULES

Start with a clear statement: Who (specific name) did what / what happened? Immediately explain why this matters (e.g., playoff implications), if the input provides that context.

Use a strict inverted-pyramid structure:

* Most important facts first (Who, What, When, Where)

* Supporting details (background, stats) only if present in the input

---

## TARGET AUDIENCE

Your audience is not made up of experts, but they are knowledgeable American football fans.

Avoid jargon or briefly explain it.

Provide only context that is explicitly present in the input.

---

## QUOTES

If quotes are present in the input, use one short quote.

Do not alter quotes.

---

## INPUT HANDLING

The INPUT contains:

* ORIGINAL HEADLINE

* ORIGINAL DESCRIPTION

* ORIGINAL CONTENT

* ORIGINAL QUOTES

The INPUT is the original report.

The INPUT may be supported by additional reports marked as:

* SUPPORTING HEADLINE

* SUPPORTING DESCRIPTION

* SUPPORTING CONTENT

* SUPPORTING QUOTES

Synthesize -- do not repeat. Combine the facts from all reports into one coherent narrative. Use the INPUT as the leading source.

* Resolve conflicts: If reports differ slightly, prioritize the one with more detailed information (e.g., exact stats or specific injury types).

* Ignore separators: Do not include separator text in your output.

---

## GOAL

Produce an informative, readable, and understandable wire-style article. Facts first. Deep enough to be meaningful, but always accessible -- and always using concrete names instead of vague descriptions.

---

## OUTPUT FORMAT

You must return your response as a single, valid JSON object. Do not write any text outside the JSON block. Use the following structure:

{

"headline": "A short, precise headline summarizing the news",

"sub_header": "One sentence that frames the angle or relevance (optional, otherwise leave empty)",

"x-post": "A short, sharp summary for push notification or social media. Max 280 characters.",

"introduction_paragraph": "The opening paragraph (lead). Clearly state WHO (specific name) did WHAT and what the outcome is.",

"content": "The main article body. Use details, statistics, and background. Follow the inverted-pyramid structure. MUST use \n\n to separate paragraphs."

}

### Field-specific guidance

* **headline**: Short and direct. Does not need to be a full sentence.

* **sub_header**: Simple framing of relevance. If not applicable, return an empty string "".

* **x-post**: Very short breaking-news summary. Start with the key fact. Use specific names. Do not start with BREAKING, URGENT, or similar catchphrases.

* **introduction_paragraph**: The most important fact first.

* **content**: Explain what happened, how it happened, key stats, and quotes (only if present in the input). Structure into 3-4 clear paragraphs. **Important:** Use `\\n\\n` (double line breaks) inside the string to separate paragraphs. No wall of text.

---

## SOURCE OF TRUTH

This is the ORIGINAL REPORT. Use it as the source of truth:

ORIGINAL HEADLINE:

ORIGINAL DESCRIPTION: {{ $('set_main_content').item.json['ORIGINAL DESCRIPTION'] }}

ORIGINAL CONTENT: {{ $('set_main_content').item.json['ORIGINAL CONTENT'] }}

ORIGINAL QUOTES: {{ $('set_main_content').item.json['ORIGINAL QUOTES'] }}```




The Image Problem: Wrong Is Worse Than None

Initially, image selection was straightforward:

  • Generate search query
  • Fetch image
  • Attach to article

Until it failed.

Wrong images destroy credibility instantly. So I introduced a verification gate.

A second agent evaluates:

  • Does the image contradict the article?
  • Does it contain headline-style overlays?
  • Is it obviously unrelated?

It rejects only when clearly wrong. Otherwise, it allows contextual imagery.

Small gate. Big trust improvement.

Pragmatic newsroom-style image gate.
Figure 3: WF-VERIFY-IMG — Pragmatic newsroom-style image gate.

News Radio: From Cringe to My Favorite Feature

The “News Radio” feature turns articles into German audio.

Version 1?

  • Fast.
  • Overexcited.
  • Hard to listen to.

So I decomposed the problem.

Step 1 — Tone Classification

A lightweight classifier decides:

  • Urgent
  • Analytical
  • Informative

Step 2 — Speech-Optimized Script

The article is rewritten for audio:

  • Short sentences
  • Clear pauses
  • No visual formatting artifacts
  • Max ~2–2.5 minutes spoken time

Step 3 — Voice Profiles + Randomization

Different speaker profiles are used depending on tone. Randomization prevents monotony.

The final TTS generation happens in a cloud function for performance reasons.

This feature went from gimmick to genuinely enjoyable.

Multi-step TTS generation pipeline.
Figure 4: WF-RADIO-01 — Multi-step TTS generation pipeline.

Context Layer: Teams & Players

Breaking news is usually about teams or players

After article generation:

  1. Entities are extracted.
  2. A cloud function performs fuzzy matching.
  3. IDs are attached to the article.

This enables:

  • Team pages
  • Player context
  • Filtering
  • Enrichment

Structured context beats plain text every time.


Why n8n?

n8n became the orchestration backbone because it allows:

  • Top-level orchestrators
  • Modular sub-workflows
  • Reusable utilities
  • Strict quality gates
  • Fast iteration

It’s not about “low-code magic.”

It’s about orchestration discipline.

Less complexity. More control.


What I’d Improve Next

Next iterations would include:

  • Advanced credibility scoring
  • Better clustering beyond nearest-neighbor similarity
  • Prompt performance benchmarking
  • Cost optimization
  • Public web frontend

Iteration never stops.

But now it's off season in the NFL. So time to relax and reflect on how the last season turned out for T4L!


Git Repos:

Core Intelligence Layer

T4L_intelligence

T4L App


Final Thought

I didn’t build this to become the best software engineer in the world.

I built this to become a builder.

And this automation ecosystem is the most builder-native system I’ve shipped so far.

If you’re building AI-native systems, orchestration frameworks, or automation-heavy products — I’m always happy to compare architectures and learn more.

BigSlikTobi