Back to Theory
Theory8 min read · June 30, 2026

Context → Creative → ROAS: How the Loop Actually Works

The performance loop that compounds is context → creative → campaign → ROAS data → back to context. Each stage feeds the next. Here is the mechanics of how it actually runs, with code at each transition point.

F
Feather DB
Engineering

The loop most teams are not running

Performance marketing teams describe their work as iterative. Brief, creative, test, optimize. Each cycle is supposed to produce better output than the last. In practice, most cycles are not truly iterative — they are repeated cold starts. The brief for cycle 5 does not systematically build on the learnings from cycles 1–4. It builds on whatever the strategist happened to remember.

The loop that actually compounds is: context → creative → campaign → ROAS data → back to context. Each stage feeds the next. The context stage is informed by accumulated ROAS data from all previous cycles. The creative stage is grounded in what context says worked. The ROAS data from the new campaign enriches the context for the next cycle. The loop closes, and it tightens with each iteration.

This document describes how the loop actually works, stage by stage, with the mechanics at each transition point.

Stage 1: Context

Context is not a prompt. It is the accumulated, weighted, graph-connected institutional knowledge of what the brand knows about its audience, its creative history, and its competitive environment. At brief time, the context engine surfaces the most relevant subset of that knowledge for the current decision.

The quality of the context stage determines the quality of everything downstream. Bad context (flat, stale, unsegmented) produces generically plausible creative strategy. Good context (decayed, spend-weighted, graph-connected) produces defensible, brand-specific creative strategy grounded in evidence.

import feather_db as fdb
from feather_db import ScoringConfig

db = fdb.DB.open("brand_acme.feather", dim=768)

def get_context(brief_params: str, embedder) -> dict:
    q = embedder.embed(brief_params)
    return {
        # Proven hooks: what worked, weighted by recency and spend
        "hooks": db.search(q, k=6, namespace="brand::hooks",
                           scoring=ScoringConfig(half_life=270.0, weight=0.3, min=0.0)),
        # Competitive landscape: what competitors are doing now
        "competitors": db.search(q, k=4, namespace="brand::competitors",
                                  scoring=ScoringConfig(half_life=45.0, weight=0.45, min=0.0)),
        # Audience insights: what this segment responds to
        "audiences": db.search(q, k=3, namespace="brand::audiences",
                               scoring=ScoringConfig(half_life=90.0, weight=0.35, min=0.0)),
        # Guardrails: what constraints are non-negotiable
        "guardrails": db.search(q, k=3, namespace="brand::guardrails",
                                scoring=ScoringConfig(half_life=3650.0, weight=0.05, min=0.0)),
    }

At 0.19ms p50 ANN latency, this four-namespace query adds under 1ms of overhead to the brief generation call. The cost of the retrieval is negligible. The cost of not doing it is a cold-start brief.

Stage 2: Creative

The creative stage receives the context as structured input to the brief generation model. The model is not generating from first principles — it is generating from a ranked, evidenced, contextually positioned set of what has worked for this brand.

The output of the creative stage is a brief (or a set of creative variants) that is grounded in the context. Specific hook recommendations with CPL evidence attached. Creative angles positioned against the current competitive landscape. Constraints that reflect the brand's proven guardrails, not just the generic ones in the brand guidelines document.

def generate_brief(context: dict, brief_params: str, llm) -> str:
    context_block = format_context_for_brief(context)

    prompt = f"""You are generating a creative brief for a D2C brand campaign.

Current brief parameters:
{brief_params}

Brand context (proven hooks, competitive intelligence, audience insights, guardrails):
{context_block}

Generate a creative brief that:
1. Builds on the proven hooks with the strongest recent performance
2. Addresses the current competitive landscape
3. Applies to the identified audience segment insights
4. Respects the brand guardrails

Be specific. Reference the performance evidence."""

    return llm.generate(prompt)

Stage 3: Campaign

The campaign stage is where the creative goes to market. This stage is where performance marketing teams have the most existing tooling — ad managers, attribution platforms, analytics dashboards. The context engine does not replace any of this tooling. It reads from it.

What matters for the loop is that the campaign stage generates structured output at the end: hook text, performance data (CTR, CPL, ROAS, spend), audience segment, competitive context references. This output is the input to stage 4.

Stage 4: ROAS data back to context

The loop closes at stage 4. Campaign results are ingested into the context engine, enriching the knowledge base for the next brief cycle. High-spend, high-performance results get high importance weights. Low-spend tests get lower weights. Failures get encoded with the lowest weights but are still present in the index to prevent repetition of known-failing territory.

def ingest_campaign_result(result: dict, embedder):
    importance = min(1.0, result["spend"] / 100_000)

    meta = fdb.MetaRecord()
    meta.set_attribute("importance", importance)
    meta.set_attribute("ctr", result["ctr"])
    meta.set_attribute("cpl", result["cpl"])
    meta.set_attribute("roas", result["roas"])

    db.add(
        id=result["campaign_id"],
        vec=embedder.embed(result["hook_text"]),
        text=result["hook_text"],
        namespace="brand::hooks",
        meta=meta
    )

    # Connect to the context that informed this campaign
    if result.get("competitor_context_id"):
        db.link(from_id=result["campaign_id"],
                to_id=result["competitor_context_id"],
                rel_type="responded_to", weight=0.8)

What the loop produces over time

The compounding effect is observable in the Hawky.ai results: 27% CPL reduction, 20% CTR uplift within 7 days of deployment, 160 hours saved per brand per month. The 7-day CTR uplift reflects the immediate impact of starting from evidenced context rather than cold-start briefs. The 27% CPL reduction is the accumulated effect of running the loop — each cycle making the next brief better, with each campaign adding to the evidence base.

After 6 months of running the loop, the context engine for a D2C brand contains enough signal to surface non-obvious patterns. Which emotional angles work best for which audience segments in which competitive environments. Which offer structures minimize CAC while maximizing LTV. Which competitor moves historically predicted category-wide creative pivots. None of this is programmed. It emerges from data accumulating in a system designed to make it queryable.

The benchmark comparison

The LongMemEval score of 0.693 for Feather DB versus 0.640 for GPT-4o full-context demonstrates that structured memory retrieval outperforms unstructured context access for the kind of long-horizon reasoning that the context → ROAS loop requires. The 40x cost advantage at equivalent or better quality means the loop is economically viable at any scale — the full benchmark run costs $2.40 with Gemini Flash, versus approximately $2.25 per single brief call with brute-force context stuffing.

Getting started

pip install feather-db

The full loop — ingestion, brief-time retrieval, loop closure — is under 300 lines of Python. One .feather file per brand. No cloud dependencies. Runs wherever your marketing AI runs. The HNSW index, context graph, and adaptive scoring are all embedded in the file format. You open it, you query it, you close it.

The loop starts with the first campaign you ingest. It gets better with every campaign after that.

FAQ

How does the context-creative-ROAS loop actually improve performance?

Each stage feeds the next with better input than the previous cycle. Context retrieval surfaces proven hooks at brief time, grounding creative strategy in evidence. Better creative grounding produces better campaign performance. Better campaign performance generates richer evidence for the next retrieval cycle. The loop compounds over time.

What is the starting point for the loop if there is no campaign history?

Start by ingesting existing campaign data from historical records — even basic creative text with CTR and spend data is sufficient. Industry-level creative principles can be seeded with low importance weights as a bootstrap. The first few brief cycles will be less well-grounded than later ones, but the loop begins producing useful context from the first ingestion batch.

How quickly does the context-ROAS loop produce measurable improvement?

Hawky.ai reports 20% CTR uplift within 7 days of deployment. The immediate improvement comes from starting briefs from evidenced context rather than cold-start generation. The 27% CPL reduction is the cumulative effect of running the loop across multiple campaigns. Both timescales — immediate and cumulative — are real; they measure different parts of the same compounding system.

Can the loop work with any LLM for the creative generation stage?

Yes. Feather DB is model-agnostic. The context retrieval layer supplies structured context as text. Any LLM can receive that context and generate the brief or creative variants. GPT-4o, Claude, Gemini — the choice of generation model is independent of the context engine layer.