The C Agents
S's autonomous travel journal — full agent architecture
Daily Run — End to End
What happens every day at 14:00 UTC
C-TravelAgent
Arc Planner
weeklyPlanner · Sun 10:00 UTC · deterministic · schedules arcs + home-active gaps → tripSchedule
↓ or manual override
AB
Manual Trip (optional)
trips.html · city + dates → tripSchedule
↓ 3 days before start
C-Planner
Trip Planner
Sonnet · 13:00 UTC · generates itinerary JSON
↓ next morning
⏰
dailyBlog fires
Cloud Function · 14:00 UTC · every day
↓
C-Weather
Weather Fetch
Open-Meteo API · 3 retries · Firestore cache fallback · geocode + 7-day conditions
↓
C-Fashion
Stylist
Sonnet · designs N outfits · dedup against prior days · weather-aware · flux_phrase + narrative_phrase
↓ inline enrichments assembled for C-Storyteller
inline
Storyteller Inputs
assembled inline — no separate agents
• Sensory Palette — buildSensoryPalette() deterministic · weather feel, sounds, smells, texture
• Return Visit Memory — loadReturnMemory() · prior-visit fragments from travelerWorld
• Disruption — dayBrief.disruption field from C-Planner (Imperfection Engine · ~20% of mid-trip days)
• Research — optional C-Brief web_search output (--research flag)
• Return Visit Memory — loadReturnMemory() · prior-visit fragments from travelerWorld
• Disruption — dayBrief.disruption field from C-Planner (Imperfection Engine · ~20% of mid-trip days)
• Research — optional C-Brief web_search output (--research flag)
↓
Narrative revision loop · max 2 revisions · threshold 8/10
C-Storyteller
Storyteller
Sonnet · 200–350 word diary · voice + place · consumes all inline inputs above
↔
C-Critic
Narrative QC
Opus · 2 retries · scores 1–10 per dimension · voice, specificity, structure · revise if overall <8
↓
C-Photographer
Photographer
Sonnet · extracts 3 + 1 spare scene · writes Flux prompts · weather-aware
↓
Image generation · 3 scenes + spare · fal.ai 3 retries · C-QC 3 retries · smart retry swaps spare on persistent failure
Flux Ultra
Image Generation
fal-ai/flux-pro/v1.1-ultra · img2img · strength 0.72 · 3:4 · 3 retries
↔
C-QC
Image QC
Sonnet · 3 retries · vision · hair color lock, solo, anatomy, style · retry at 0.65 · spare scene swap
↓
C-BRoll
B-Roll Scenes
Sonnet · atmospheric establishing shots · text-to-image · 16:9 · no character · 3 retries
↓
C-Editor
Coherence Gate
Sonnet · 3 retries · multi-modal · narrative vs images · hard conflicts trigger rewrite
↓
C-BlogEditor
Layout Editor
Haiku · reads narrative + scene descriptions · places all images contextually · fallback: positional (40%/75%)
↓
C-Archivist
Archivist
firebase-admin · saves day to Firestore · blog.html reads from here
↓
C-Report
Daily Email
nodemailer · HTML digest → epochblognet@gmail.com
↓ last day only
C5
Trip Archive
Haiku · archiveTrip() · tripSummary + openThreads + characterNote → travelerWorld
Mixed models: Sonnet for reasoning · Opus for critique · Haiku for fast tasks · Director wraps the loop when --director flag is set
Orchestration
Director
Narrative
Fashion
Vision / Image
Quality Control
Archive / Memory
External Model
Phase 0 — Trip Input
C-Planner
Trip Planner
Watches
tripSchedule Firestore collection for upcoming trips. 3 days before departure, generates a full multi-day itinerary JSON — areas, anchor hotels, day arcs, outfit seeds. Saves to trips/{tripId}.json and kicks off the blog pipeline.
IN: tripSchedule → city, country, startDate, endDate | OUT: trip JSON → Firestore + local file
claude-sonnet-4-6
Scheduled Cloud Function
runs daily @ 13:00 UTC
Scheduled Cloud Function
runs daily @ 13:00 UTC
Live
Phase 1 — Director (Agentic Loop)
Director
Orchestrator
Agentic orchestrator with tool-use loop. Autonomously decides which sub-agents to call and in what order. Holds per-day working state. Tools: research_locations, design_outfits, write_story, extract_scenes, generate_images, edit_narrative (6 tools, director.js:38–110). Up to 10 reasoning loops per day with fallback to sequential steps on tool failure. Enabled via
--director flag; the hardcoded linear pipeline remains as manual/fallback path.
IN: trip JSON, traveler config, S's World | OUT: fully published day (narrative + images)
claude-sonnet-4-6
director.js · runDirector()
--director flag (optional)
director.js · runDirector()
--director flag (optional)
Live
Phase 2 — Narrative
C-Weather
Weather Feed
Fetches real daily conditions for every day of the active trip using Open-Meteo's geocoding and forecast/archive APIs — no API key required. 3 retries with backoff. Falls back to Firestore weatherCache if API fails. Returns a weatherByDay map with temperature range, WMO condition code, precipitation, and sensory prose. Injected into C-Fashion, C-Storyteller, C-Photographer, Sensory Palette, and the email report.
IN: city, country, startDate, endDate | OUT: weatherByDay{ [dateString]: { temp, condition, prose } }
Open-Meteo API
No LLM · free · no key
blog-weather.js
No LLM · free · no key
blog-weather.js
Live
Runs in parallel — Research & Fashion design
C-Brief
Travel Desk
Web search agent. Queries real information about the day's locations — architectural details, cultural context, local textures. Builds a researchContext block for C-Storyteller to use. Prevents generic hallucinated descriptions.
IN: location list | OUT: researchContext JSON
claude-haiku-4-5
web_search tool
--research flag
web_search tool
--research flag
Optional
C-Fashion
Stylist
Designs S's outfit for each scene, grounded in her styleProfile DNA. Provides two phrases per scene: a Flux-ready visual description for image generation, and a narrative phrase for prose. Avoids outfit repetition by loading prior-day outfits from Firestore.
IN: styleProfile, dayBrief, priorOutfits | OUT: outfitBriefs[] per scene
claude-sonnet-4-6
styleProfile from
traveler-config.js
styleProfile from
traveler-config.js
Live
Narrative revision loop
max 2 revisions · threshold 8/10
C-Storyteller
Storyteller
Writes S's diary entry in her established voice — spare, perceptive, rooted in place. Uses research context for location authenticity and C-Fashion's outfit phrases to weave clothing into the prose naturally.
IN: dayBrief, outfitBriefs, researchContext | OUT: raw narrative draft
claude-sonnet-4-6
Live
C-Critic
Narrative QC
Scores the narrative 1–10 on each dimension (voice fidelity, location specificity, structure, emotional authenticity). Overall score 1–10, threshold 8. Returns summary, score, suggested revisions, and critique type (content/voice/structure). C-Storyteller rewrites; loop repeats up to 2 revisions.
IN: narrative + scoring rubric | OUT: critiqueSummary, critiqueScore, suggestedRevisions, critiqueType
claude-opus-4-6
blog-prompt.js:369
2 retries
blog-prompt.js:369
2 retries
Live
Phase 3 — Scene Extraction
C-Photographer
Photographer
Reads the finalized narrative and extracts 3 + 1 spare scene briefs — each with a location description (architectural, never just a name), shot type, lighting, secondary elements, and a Flux-ready image prompt with S's outfit embedded. The 4th spare scene is held in reserve for smart retry on QC failures.
IN: narrative, outfitBriefs | OUT: scenes[] JSON
claude-sonnet-4-6
blog-prompt.js:636
upgraded Phase 1
blog-prompt.js:636
upgraded Phase 1
Live
Phase 4 — Image Generation
Flux Ultra
Single-Stage
Default image path. Takes C-Photographer's scene prompt + S's canon reference image. Runs img2img at strength 0.72 (locked) with 3 retries. Blank detection (<15KB) triggers retry at 0.65 fallback. Smart retry swaps spare scene on persistent QC failure. Uploaded to Firebase Storage for permanent URLs.
IN: scene prompt, canonUrl, strength | OUT: image URL (fal.media CDN)
fal-ai/flux-pro/v1.1-ultra
img2img · strength 0.72
aspect 3:4 · retry at 0.65
img2img · strength 0.72
aspect 3:4 · retry at 0.65
Live
Phase 5 — Quality Control & Coherence
Runs in sequence — Vision QC then narrative coherence check
C-QC
Image QC
Vision model inspects each generated image. Checks: solo subject (no co-subjects), S present, no anatomical errors, style match. Verdict: pass / retry / flag. On retry, regenerates the scene up to 3 times before flagging.
IN: image URL, scene brief | OUT: verdict + reason
claude-sonnet-4-6
vision · url source
blog-qc.js:34
3 retries w/ backoff
vision · url source
blog-qc.js:34
3 retries w/ backoff
Live
C-Editor
Coherence Gate
Multi-modal editorial check. Loads narrative + all published images. Flags: existence conflicts (narrative denies photography), outfit mismatches, weather contradictions, mood mismatches. Hard conflicts trigger narrative rewrite; soft conflicts may flag scenes for regeneration.
IN: narrative + image URLs | OUT: conflicts[], revisedNarrative, scenesToRegenerate
claude-sonnet-4-6
multi-modal (vision)
--skip-editor to bypass
3 retries with backoff
multi-modal (vision)
--skip-editor to bypass
3 retries with backoff
Live
C-BlogEditor
Layout Editor
Reads the final narrative and all scene/B-roll descriptions. Decides contextually where each image should appear in the text — matching scene moments to the paragraphs that describe them. Character images and B-roll are woven into the reading flow. Falls back to mechanical positional placement (hero + 40% + 75%) if the agent fails or returns no data.
IN: narrative + scene descriptions + broll descriptions | OUT: placements[], narrativeFlow
claude-haiku-4-5
text-only (no vision)
blog-layout.js
2 retries · fallback: positional
text-only (no vision)
blog-layout.js
2 retries · fallback: positional
Live
Phase 6 — Archive & Memory
Archive runs in parallel
C-Archivist
Archivist
Saves completed day data to Firestore
travelerBlog collection. Stores narrative, scenes, image URLs, QC verdicts, outfit briefs, critic scores, and generation metadata. The source of truth for the blog reader.
IN: complete day object | OUT: Firestore write
firebase-admin
Firestore write
blog-firestore.js
Firestore write
blog-firestore.js
Live
C-Memory
World Memory
Updates S's World — the persistent cross-trip memory in Firestore
world collection. Tracks places visited, people encountered, recurring motifs, emotional threads. Referenced by C-Storyteller for continuity across trips.
IN: day summary | OUT: world Firestore update
claude-haiku-4-5
world-firestore.js
cross-trip memory
world-firestore.js
cross-trip memory
Live
C-Report
Daily Email
Fires at the end of every
dailyBlog run. Builds a dark-theme HTML digest with pipeline status, S's hero image, real weather, outfit briefs, agent verdicts, narrative excerpt, and runtime metrics. Sent via Nodemailer to AB's project inbox.
IN: trip, dayDoc, weather, pipelineStart | OUT: HTML email → epochblognet@gmail.com
nodemailer + Gmail
GMAIL_USER secret
blog-report.js
GMAIL_USER secret
blog-report.js
Live
Autonomous Travel Agency
Zero-input trip planning — C-TravelAgent picks destinations, schedules arcs, manages home gaps
⏰
weeklyPlanner fires
Cloud Function · Sundays 10:00 UTC · checks if next arc is needed
↓
C-TravelAgent
Travel Agency
105 cities · seasonal scoring · novelty + recency + region variety · transit time from NYC · arc companions
↓ schedules 2–3 city arc
Firestore
tripSchedule
Writes city + dates → C-Planner picks up 3 days before → fully autonomous
↓ between arcs
⏰
dailyHome fires
Cloud Function · 14:00 UTC daily · checks for home-active periods · Mon/Wed/Fri only
↓
Home Mode
NYC Home Entries
150–250 words · 5 entry structures · real NYC weather · 1 B-Roll image · no character
Three-state rhythm: arc (full travel) → home-active (NYC Mon/Wed/Fri) → home-rest (dark)
Agent Index
Quick reference — all agents, models, and entry points
| Agent | Role | Model | Entry Point | Triggered by |
|---|---|---|---|---|
| C-Planner | Trip Planner | claude-sonnet-4-6 | blog-c0.js | Cloud Function scheduler · tripSchedule Firestore |
| Director | Orchestrator | claude-sonnet-4-6 | director.js · runDirector() | --director flag in run-blog.js |
| C-Storyteller | Storyteller | claude-sonnet-4-6 | blog-prompt.js · buildDayStory() | Director tool: write_story / doStory() |
| C-Critic | Narrative QC | claude-opus-4-6 | blog-prompt.js · critiqueNarrative() | Inside C-Storyteller loop · 2 retries |
| C-Photographer | Photographer | claude-sonnet-4-6 | blog-prompt.js · extractScenes() | Director tool: extract_scenes / doScenes() |
| C-Brief | Travel Desk | claude-haiku-4-5 | blog-prompt.js · researchLocations() | Director tool: research_locations / --research flag |
| C4 (Flux) | Image Gen | fal-ai/flux-pro/v1.1-ultra | blog-generate.js | Director tool: generate_images / doImages() |
| C-Weather | Weather Feed | Open-Meteo API | blog-weather.js · fetchTripWeather() | Start of dailyBlog, before C-Fashion |
| C-QC | Image QC | claude-sonnet-4-6 | blog-qc.js · checkBlogImage() | After each image generation · 3 retries |
| C-Fashion | Stylist | claude-sonnet-4-6 | blog-fashion.js · designDayOutfits() | Director tool: design_outfits / doFashion() |
| C-Report | Daily Email | nodemailer | blog-report.js · sendDailyReport() | End of dailyBlog, after C-Archivist save |
| C-Editor | Coherence Gate | claude-sonnet-4-6 | blog-editor.js · runEditPass() | Director tool: edit_narrative / doEdit() · 3 retries |
| C-BlogEditor | Layout Editor | claude-haiku-4-5 | blog-layout.js · runLayoutPass() | After C-Editor · --mode=layout for manual · fallback: positional |
| C-Archivist | Archivist | firebase-admin | blog-firestore.js · saveDay() | End of each day loop, auto |
| C-Memory | World Memory | claude-haiku-4-5 | blog-prompt.js · archiveTrip() | Last day of trip only, after saveDay() |
| C-BRoll | B-Roll Scenes | claude-sonnet-4-6 | blog-prompt.js · extractBrollScenes() | After character images · text-to-image 16:9 |
| C-TravelAgent | Travel Agency | Deterministic (no LLM) | travel-agent.js · planNext() | weeklyPlanner Cloud Function · Sundays 10:00 UTC |
| Home Mode | NYC Entries | claude-sonnet-4-6 | blog-home.js · runHomeEntry() | dailyHome Cloud Function · Mon/Wed/Fri during gaps |
Firestore Collections
Data architecture — what lives where
tripSchedule
{tripId}
city · country
startDate · endDate
status (planned/running/done)
→ Written by: trips.html + C-TravelAgent
→ Read by: C-Planner
startDate · endDate
status (planned/running/done)
→ Written by: trips.html + C-TravelAgent
→ Read by: C-Planner
travelerBlog
{tripId} / days / {dayN}
narrative · scenes[] · spareScene
images[] · brollImages[]
outfitBriefs · criticScore
narrativeCriticError · disruption
→ Written by: C-Archivist
→ Read by: blog.html, dashboard.html
images[] · brollImages[]
outfitBriefs · criticScore
narrativeCriticError · disruption
→ Written by: C-Archivist
→ Read by: blog.html, dashboard.html
travelerRoom
{travelerId}
canonUrl · styleProfile
name · origin · voice
→ Written by: traveler.html
→ Read by: C-Storyteller, C-Fashion
name · origin · voice
→ Written by: traveler.html
→ Read by: C-Storyteller, C-Fashion
travelerWorld
{travelerId}
visitedCities[] · tripHistory[]
openThreads[] · characterNote
returnVisitFragments
→ Written by: C-Memory
→ Read by: Return Visit Memory
openThreads[] · characterNote
returnVisitFragments
→ Written by: C-Memory
→ Read by: Return Visit Memory
weatherCache
{city-slug-startDate}
weatherByDay{}
cachedAt timestamp
→ Written by: blog-weather.js
→ Read by: fallback on API fail
cachedAt timestamp
→ Written by: blog-weather.js
→ Read by: fallback on API fail
travelerBlog/nyc-home/days
{YYYY-MM-DD}
narrative · brollImages[]
entryType · weatherContext
tripSchedule doc: nyc-home-{startDate}
→ Written by: blog-home.js
→ Read by: blog.html
entryType · weatherContext
tripSchedule doc: nyc-home-{startDate}
→ Written by: blog-home.js
→ Read by: blog.html
CLI Run Modes
node src/run-blog.js — common invocations
| Command | What it does |
|---|---|
| --mode=trip --trip=osaka-2026-03 --director | Full agentic run — Director orchestrates all agents autonomously (primary mode) |
| --mode=trip --trip=osaka-2026-03 | Linear fallback pipeline: fashion → story → scenes → images → QC → editor → layout → save |
| --mode=trip --trip=osaka-2026-03 --day=3 | Run a single day of the linear pipeline end-to-end |
| --mode=plan --trip=osaka-2026-03 | Run C-Planner (C0) to generate the trip JSON |
| --mode=brief --trip=osaka-2026-03 --day=3 | Run C-Brief Travel Desk web_search research for a day's locations |
| --mode=fashion --trip=osaka-2026-03 --day=3 | Run C-Fashion only — preview outfit briefs |
| --mode=story --trip=osaka-2026-03 --day=3 | Run C-Storyteller + C-Critic loop only |
| --mode=scenes --trip=osaka-2026-03 --day=3 --scenes=3 | Run C-Photographer scene extraction (default scenes=3) |
| --mode=generate --trip=osaka-2026-03 --day=3 | Generate images from existing scenes (Flux Ultra img2img) |
| --mode=broll --trip=osaka-2026-03 --day=3 | Extract + generate B-roll environmental scenes (no character) |
| --mode=qc --trip=osaka-2026-03 --day=3 --force | Re-run C-QC on existing images; --force re-checks prior passes |
| --mode=edit --trip=osaka-2026-03 --day=3 | Run C-Editor coherence gate only on saved day |
| --mode=layout --trip=osaka-2026-03 --day=3 | Run C-BlogEditor — compute smart image placement |
| --mode=archive --trip=osaka-2026-03 | Run C5 / archiveTrip on a completed trip (tripSummary + openThreads) |
| --research | Enable C-Brief web_search during full runs (feeds C-Storyteller) |
| --skip-editor | Bypass C-Editor coherence gate (speed mode) |
| --no-weather | Skip C-Weather fetch (dev/offline runs) |
| --two-stage | Two-stage image pipeline: gpt-image-1 → flux-fill inpaint/img2img |
| --dry-run | No Firestore writes, no image generation (smoke test) |