Back Office · office.temerarii.xyz
SELF-IMPROVING-LOOP.md

← all docs

The Self-Improving Loop — how Temerarii learns from itself

Status: scaffolded + offline-ready. Learns once the GA4/Blotato outcome signal is live.

The studio is already self-consistent (one source → all lenses, 13 gates fail on drift) and

self-correcting offline (the 5× audit→simulate→enhance convergence loop). This adds the missing

half: learning from the world — measuring what published content actually does and rewriting the

plan's own inputs so the next cycle is better. Pattern borrowed from karpathy/autoresearch

(fixed harness + one honest metric + keep/discard + evolving meta-instructions) and the production

patterns in aiming-lab/AutoResearchClaw (a lessons store that feeds the next run; PROCEED/REFINE/

PIVOT; an anti-fabrication guard — our no-faked-receipts rail). (turboquant is unrelated — KV-cache

quantization, no feedback loop.)

The loop (one round)

 content-index.json (the assets)          outcomes.json (REAL GA4/UTM + Blotato metrics)
            │                                          │
            └──────────────┬───────────────────────────┘
                           ▼
              engine/lib/improve.py  ·  ONE round
   1 SCORE      every published asset → one comparable number (the metric)
   2 RANK       by score, within a lever (pillar · colorway · template family · hook)
   3 DECIDE     top-decile → SCALE · bottom-decile → KILL · middle → keep (PROCEED/REFINE/PIVOT)
   4 PROPOSE    write-back proposals to the SOURCE levers — never auto-applied:
                  · topics.yaml importance weights   · ground/colorway rotation
                  · template-family preference        · hook patterns that landed
   5 LEARN      append to lessons.json (time-decayed) — injected as context next round
                           │
                           ▼
        content/_generated/improvement-plan.json  (operator reviews → applies)
        content/_generated/lessons.json           (the memory that compounds)

The metric (honest, no fabrication)

engine/lib/outcomes.py defines the per-asset OUTCOME schema (impressions · engagement_rate ·

clicks · leads · revenue · score). The score is a weighted composite, but the inputs are REAL

— read from content/_generated/outcomes.json (filled by GA4 via utm.py + Blotato post metrics).

**Offline (today): the file is empty → 0 outcomes → the loop runs, proposes NOTHING, and reports

"awaiting signal." It never invents a number** (the VerifiedRegistry / no-faked-receipts rail).

Guardrails (the rails still bind)

  • Proposes, never auto-applies. Write-back to topics.yaml/treatment-plan is a separate, explicit,

operator-gated step (improve.py apply --confirm). No silent self-editing of the plan.

  • No fabricated outcomes. No GA4 signal → no scores → no proposals. Honest empty.
  • Brand rails hold. Proposals are constrained to the sanctioned levers (the 3 grounds, the template

families, the 8 pillars, sanctioned hooks) — the loop can reweight, never invent off-brand.

  • Deterministic + gated. A round is a pure function of (content-index, outcomes); re-running with

the same inputs yields the same plan. Gated alongside the 13 gates.

Files

  • engine/lib/outcomes.py — the OUTCOME schema + load_outcomes() + score() + has_signal() (graceful-empty).
  • engine/lib/improve.py — the round: score → rank → decide → propose → learn. CLI: python engine/lib/improve.py.
  • content/_generated/outcomes.json — the REAL signal (GA4/Blotato fill it; empty offline).
  • content/_generated/improvement-plan.json — the proposals (operator reviews).
  • content/_generated/lessons.json — the compounding memory (time-decayed).

Verify

  • Offline (now): python engine/lib/improve.py → "0 outcomes · awaiting GA4 signal · loop verified ready",

writes an improvement-plan.json with status: awaiting-signal + 0 proposals, 0 fabricated numbers.

  • Live (after gcloud auth + GA4): outcomes.json fills → the round scores 304 assets, proposes

scale/kill by lever, appends lessons; operator reviews improvement-plan.json and runs apply --confirm.

Unblock to make it LEARN

  1. gcloud auth login (the GA4 property) — the outcome signal. (Operator action — only they can.)
  2. Wire engine/integrations/ga4.py + Blotato post-metrics → write outcomes.json on a cadence.
  3. Schedule improve.py (cron, monthly — tied to the Receipts thread) → propose → operator applies.