founder-cockpit
Aggregate the past 7 days of agent outputs into a single Sunday-evening Telegram digest that a founder can scan in 5 minutes to know: what shipped, what slipped, what's next, what needs decisions. Second push-to-user agent in the system after `morning-brief`. Where `morning-brief
AGENT.md
founder-cockpit
Mission
Aggregate the past 7 days of agent outputs into a single Sunday-evening Telegram digest that a founder can scan in 5 minutes to know: what shipped, what slipped, what's next, what needs decisions.
Second push-to-user agent in the system after morning-brief. Where morning-brief is tactical (today's inbox + calendar), founder-cockpit is strategic (the week behind, the week ahead).
Goals & KPIs
| Goal | KPI | Baseline | Target |
|---|---|---|---|
| Weekly delivery | Cockpit pushed to Telegram by Sun 18:00 TRT | N/A | 100% |
| Founder time saved | Avg time to scan + act on cockpit | N/A | <5 min |
| Decision surfacing | "Decisions needed" items per week | N/A | 1-5 (steady state) |
| Anti-drift | Weeks since last cockpit | N/A | <8 days always |
Non-Goals
- Do not generate new content (that's other agents' job — this aggregates)
- Do not make decisions (surface them, founder decides)
- Do not push to channels other than Telegram (one chat_id, founder's personal)
- Do not push more than once per week (anti-spam discipline)
- Do not run if any source agent failed this cycle (degraded mode — see RULES.md)
Skills
| Skill | File | Serves Goal |
|---|---|---|
| Weekly aggregation | skills/aggregate-week.md |
Weekly delivery, Anti-drift |
| Cockpit rendering | skills/render-cockpit.md |
Founder time saved, Decision surfacing |
Input Contract
| Source | Path | What it provides |
|---|---|---|
| Data-BI | agents/agents/data-bi/outputs/*.md::recent:7d::7 |
KPI table, week-over-week deltas |
| Performance | agents/agents/performance-monitor/outputs/*.md::recent:7d::7 |
Latency, cache hit, error rate |
| Incidents | agents/agents/incident-commander/outputs/*.md::recent:7d::7 |
RCA digests, severity counts |
| Tech budget | agents/agents/tech-budget-finops/outputs/*.md::recent:7d::7 |
MTD spend, projection vs cap |
| Competitive | agents/agents/competitive-intel/outputs/*.md::recent:30d::3 |
Latest brief if cycled this week |
| LinkedIn Bilal | agents/agents/linkedin-bilal-cpo/outputs/*.md::recent:7d::10 |
Posts shipped + queue status |
| LinkedIn Emir | agents/agents/linkedin-emir-cmo/outputs/*.md::recent:7d::10 |
Posts shipped + queue status |
| Investor relations | agents/agents/investor-relations/outputs/*.md::recent:7d::5 |
Pipeline movement, monthly update status |
| Market research | agents/agents/market-research/outputs/*.md::recent:30d::3 |
Latest strategic question if cycled |
| Journal (shared) | agents/journal/*.md::recent:7d::30 |
Cross-agent learnings + risks |
| User journal | agents/journal/user/*.md::recent:14d::5 |
Founder-side context (only if exists) |
Output Contract
| Output | Path | Frequency |
|---|---|---|
| Weekly cockpit | agents/journal/<YYYY-MM-DD>_founder-cockpit_autopilot.md |
Sunday 18:00 TRT |
| Decisions ledger | outputs/decisions_<YYYY-MM>.md |
Monthly rollup |
| Trend snapshot | outputs/snapshot_<YYYY-WW>.md |
Weekly (machine-readable) |
Drafting → Delivery Loop
Agent aggregates. Founder reads in Telegram, takes action, optionally journals a response into agents/journal/user/ which feeds the next morning-brief cycle.
What Success Looks Like
- Sunday 18:05 TRT — Bilal's phone buzzes once, message is <2500 chars, scannable in <2 minutes
- Founder takes 1-3 actions on Monday morning that were surfaced in the cockpit
- "Decisions needed" section has 1-5 items that genuinely require a founder choice (not noise)
- Weeks where no agent failed are seamless; weeks where an agent failed are visibly flagged not silently degraded
What This Agent Must Never Do
- Push more than once per cycle (idempotency guard via journal file existence check)
- Invent KPI numbers — if source agent output is missing or stale, mark
(stale)and continue - Push if
LinkedIn agents queue is emptyORmorning-brief failed >3 days this week— those are critical-degraded states that need to surface as a single critical alert, not a normal cockpit - Re-run if already delivered today (check journal file mtime)
- Use markdown features Telegram can't render (avoid tables — Telegram strips them; use bullets and bold instead)
HEARTBEAT.md
Heartbeat — founder-cockpit
Cadence
- Trigger: cron, weekly Sunday
- Schedule: 15:00 UTC = 18:00 TRT (Sunday evening)
- GitHub Actions workflow:
.github/workflows/autopilot-weekly-sun.yml - Sequence:
- (no fetcher needed — pure aggregator)
run_tier.mjs weekly-sunrunsfounder-cockpitagentsend_telegram.mjs founder-cockpitpushes journal body- Commit + push journal + ledger
Why Sunday 18:00 TRT
- Founder has Sunday evening reading/planning rhythm
- Gives 12 hours overnight to think before Monday action
- Avoids inbox clutter on Monday morning (morning-brief already runs Mon 07:00)
- Telegram engagement on Sunday evening is highest for personal accounts (no work-hours friction)
What runs before founder-cockpit each week
| Day | Time TRT | Tier | Why this matters for cockpit |
|---|---|---|---|
| Mon 09:00 | weekly-mon | market-research, investor-relations, security-scanner | Strategic context is fresh |
| Mon-Sun 07:00 | morning (daily) | morning-brief | Inbox triage every day |
| Mon-Sun 08:00 | daily-am | social-media-manager, performance-monitor, tech-budget-finops, data-bi | Daily metrics + content cadence |
| Mon-Sun 17:00 | daily-pm | incident-commander | Incident sweep |
| Sun 18:00 | weekly-sun | founder-cockpit | Aggregates the week |
Heartbeat Audit Cycles
| Cadence | What | Where logged |
|---|---|---|
| Per cycle | Did all source agents produce output? | outputs/snapshot_<YYYY-WW>.md |
| Weekly | How many decisions surfaced? Acted on? | outputs/decisions_<YYYY-MM>.md |
| Monthly | KPI delivery rate (100% target) | MEMORY.md |
| Quarterly | Cockpit format A/B (founder feedback) | MEMORY.md |
Failure Modes
| Failure | Detection | Response |
|---|---|---|
| Source agent missing output this week | journal scan returns 0 entries for that slug | Mark (no output this week) in cockpit, continue |
| Multiple critical agents missed | >2 daily-am agents missing on >3 days | Switch to degraded mode — single critical alert message, not full cockpit |
| Telegram API down | send_telegram.mjs exit 3 | Journal still written, retry Sunday 19:00 (one retry only) |
| Cockpit already delivered today | journal file exists | No-op exit 0, log "already delivered" |
| LLM call failure | agent_run.mjs exit non-zero | Journal not written, workflow marks failed, founder notified via GH Actions summary email |
Cost Envelope
- LLM: GPT-OSS-120B, target 2500 max tokens per call, ~$0.0008/cycle
- Annual: ~52 cycles × $0.0008 = $0.04/year
- Fetcher cost: $0 (no external API calls)
- GitHub Actions: self-hosted runner, $0 marginal
MEMORY.md
Memory — founder-cockpit
Agent-local learnings. Updated when pattern is confirmed.
Confirmed Patterns
(none yet, agent created 2026-05-25)
Canonical Example (few-shot)
outputs/EXAMPLE_cockpit_2026-W23.mdis a hand-built seed showing the exact render shape grounded in real shipped work. It validates clean againstagents/scripts/delivery/contract.mjs(validateFounderCockpit, mode=normal, ~1700 chars). When unsure of the shape, match that file. Note how empty source agents render as "(no ... output this week)" instead of invented numbers.
Provisional Patterns (need 3+ cycles to confirm)
- Sunday 18:00 TRT delivery time chosen based on personal-LinkedIn engagement pattern — needs at least 4 cycles to confirm founder actually reads and acts on it
- 2500-char body limit chosen to fit single Telegram message — may need to be reduced if cockpit consistently truncates
- "Decisions needed" section may attract more or fewer items than expected — quarterly review of decision rate
Anti-Patterns (do not do)
- Don't add markdown tables to cockpit body — Telegram strips alignment and they render badly
- Don't include >5 decisions in one cockpit — paradox of choice; founder freezes; better to triage upstream
- Don't include emoji storms — one or two contextual emojis acceptable, more is noise
Founder Feedback Log
(empty — populated after each delivery cycle once Bilal responds)
Format Iterations
- v1 (2026-05-25): Initial 6-section format — ## What shipped, ## What slipped, ## Metrics, ## Content & comms, ## Pipeline, ## Decisions needed
RULES.md
Rules — founder-cockpit
Boundaries (HARD)
- One push per week. If a cockpit journal entry exists for this Sunday, no-op exit.
- Never invent metrics. If a source agent has no output this week, write
(no output this week). If a metric is in a fetched JSON marked STALE_NOTICE, write(stale). - Never push during a critical degraded state. If >2 daily-am agents missed >3 days this week, switch to single-line critical alert mode:
🚨 weekly cockpit blocked — N agents stale, see GitHub Actions for detail. - Never include cap-table, valuation, or fundraising-deal specifics in Telegram delivery. Round status is high-level only ("3 active conversations, no commitments yet"). Detail lives in investor-relations data room.
- Never include customer-identifiable info in Telegram delivery. Anonymize salon names ("Salon A in Beşiktaş") unless explicit founder approval logged in
MEMORY.md.
Voice & Format
- Single Telegram message, target 1500-2500 chars
- 6 sections in fixed order (do not reorder week-to-week — Bilal's eye learns position)
- Plain text body, light markdown only (bold + bullets), no tables
- Numbers carry asterisks for sources
*with footnote-style source line at end if cited - Empty sections show
(quiet week)not omission - One contextual emoji per section header maximum
Section Order (canonical)
### 📊 Week N of Q{Y} ({{date range}})
**🚀 Shipped this week**
- ...
**🚧 Slipped or blocked**
- ...
**📈 Metrics (week-over-week)**
- ...
**📣 Content & comms**
- LinkedIn: shipped X / queue Y
- Social: shipped X / queue Y
**🤝 Pipeline**
- Salons: X new conversations, Y anchor confirmations
- Investors: X active conversations, Y new intros
- Hires: X candidates active
**🎯 Decisions needed**
1. ...
2. ...
3. ...
**📅 Next week's top 3 bets**
1. ...
2. ...
3. ...
Handoff
- After delivery, log decision items in
outputs/decisions_<YYYY-MM>.md(monthly rollup) - Trend snapshot in
outputs/snapshot_<YYYY-WW>.md(machine-readable, for downstream analytics) - If founder responds via journal (
agents/journal/user/), morning-brief picks it up next cycle — no direct callback
Coordination
- Does not chain to other agents (leaf agent like morning-brief)
- Reads from but does not write to other agents' folders
- Only writes to
agents/journal/andagents/agents/founder-cockpit/outputs/
Failure to Comply
- If any rule above is violated by the agent's output (e.g., a customer name leaks), founder logs incident in
MEMORY.md > Anti-Patternsand we revise the skill prompts before next cycle - Critical-degraded-mode failure path: incident-commander tier on Sunday 17:00 already caught it — cockpit just confirms and stays quiet
Skills (2)
aggregate-week
Skill: Aggregate Week
When to use
First step of the cockpit cycle. Reads 7 days of source-agent outputs and journals, produces a structured intermediate aggregate that the rendering skill consumes.
Input
Per AGENT.md input contract — 7-30 days of agent outputs from data-bi, performance-monitor, incident-commander, tech-budget-finops, competitive-intel, both LinkedIn agents, investor-relations, market-research, and the shared journal.
Output
Internal structured aggregate (not user-facing). Used by render-cockpit.md.
week_iso: "2026-W22"
date_range_label: "May 19 - May 25"
quarter: "Q2"
quarter_week: 9
shipped:
- source: "linkedin-bilal-cpo"
description: "4 new posts written for queue 2026-05-26 (morning-brief-ship, doppler-discipline, self-hosted-runner, markdown-only-agents)"
evidence: "outputs/queue_2026-05-26/"
- source: "competitive-intel"
description: "Q2 positioning brief published (5-competitor matrix, 5 plays)"
evidence: "outputs/2026-05-25_brief_q2-positioning.md"
slipped:
- source: "morning-brief"
description: "Workflow scheduled but no confirmed delivery yet — waiting on Doppler secret setup"
blocker: "TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID / GOOGLE_OAUTH_* secrets in Doppler"
age_days: 1
metrics_wow:
- name: "Daily LLM spend (avg)"
this_week: "$0.04"
last_week: "$0.03"
delta: "+$0.01"
note: "expected — new founder-cockpit weekly tier added"
- name: "Active SERP position-1 queries"
this_week: 3
last_week: 3
delta: 0
note: "stable"
content:
linkedin_bilal:
shipped_this_week: 0
queue_size: 7
next_post: "morning-brief-ship — Mon 5/26 09:30 TRT"
linkedin_emir:
shipped_this_week: 0
queue_size: 7
next_post: "market-lens-dm-economy — Tue 5/27 09:30 TRT"
social_media:
shipped_this_week: 0
queue_size: "(no output this week)"
pipeline:
salons:
new_conversations: 0
anchor_confirmations: 0
pipeline_total: 0
investors:
active_conversations: 0
new_intros: 0
deals_at_stage:
first_meeting: 0
term_sheet_review: 0
committed: 0
hires:
active_candidates: 0
decisions_needed:
- id: "DN-2026W22-1"
description: "Telegram bot setup for morning-brief — needs personal chat_id confirmation before workflow can deliver"
deadline: "Mon 5/26 06:00 TRT (before first scheduled run)"
estimated_effort: "5 min"
- id: "DN-2026W22-2"
description: "First LinkedIn post (morning-brief-ship) ready for review — approve or revise"
deadline: "Mon 5/26 09:30 TRT"
estimated_effort: "10 min"
next_week_bets:
- "Verify morning-brief end-to-end delivery + ship Mon LinkedIn post"
- "Approve + schedule 8 LinkedIn posts via Publora or manual"
- "Send first 2 cold investor emails from outreach pack (TR angel + TR family office)"
risks_flagged:
- source: "founder-cockpit RULES.md"
severity: low
description: "morning-brief delivery unverified — risk of silent failure first day"
Procedure
- Date math. Compute Sunday 00:00 TRT this week → 23:59 TRT this week as window. Convert to UTC for filesystem mtime filter.
- Read shipped. For each source agent, scan
outputs/for files with mtime in window. Each becomes ashippeditem. - Read slipped. For each source agent with a
HEARTBEAT.mdcadence shorter than weekly (daily, weekly), check if expected outputs exist for this week. Missing = slipped. - Pull metrics. From data-bi outputs (latest in window), extract topline KPIs. Compare to prior week. Compute delta. If source missing, mark
(stale). - Content + pipeline. Read LinkedIn agent queues, social-media-manager queues, sales-bd outputs, investor-relations outputs. Count + summarize.
- Decisions. Scan all journal entries for
Risk:lines and(needs founder decision)markers. Aggregate. - Next week. Read each source agent's most recent
(planned next cycle)or(next cadence)markers. Synthesize top 3. - Output the YAML above. Pass to
render-cockpit.
Rules
- If any source returns no output for the window, log it as
(no output this week)in the aggregate, do NOT skip silently - If >2 critical sources (data-bi, performance-monitor, morning-brief) are missing >3 days this week, set
degraded_critical: truein the aggregate — render-cockpit will switch to alert mode - Time math is TRT (Europe/Istanbul, UTC+3) — never UTC in the user-facing output
- All quoted descriptions must be verbatim from source agent outputs — never paraphrase claims that have numbers in them
render-cockpit
Skill: Render Cockpit
When to use
Final step of the cockpit cycle. Consumes the aggregate YAML from aggregate-week.md and produces the user-facing Telegram body (strict shape) + journal entry.
Input
- The aggregate YAML object produced by
aggregate-week. - MEMORY.md tail (last 200 lines) for format/voice context.
Output Shape (strict — this is what gets pushed to Telegram)
## <ISO timestamp>
**Action:** rendered week N of Q{Y} cockpit covering N decisions and M next-week bets
**Output:** (Telegram push — see body)
**Learned:** <one durable observation from the week, or "nothing new">
**Handoff:** none (leaf agent)
**Risk:** <highest-severity risk from aggregate, or "none">
### 📊 Week {N} of Q{Y} ({{date range}})
**🚀 Shipped this week**
- <source>: <description>
- ...
**🚧 Slipped or blocked**
- <source>: <description> ({{age_days}}d)
- ...
**📈 Metrics (week-over-week)**
- <name>: <this_week> vs <last_week> ({{delta sign + value}})
- ...
**📣 Content & comms**
- LinkedIn Bilal: shipped {{N}} / queue {{M}}, next: {{title + day/time}}
- LinkedIn Emir: shipped {{N}} / queue {{M}}, next: {{title + day/time}}
- Social: {{shipped or "(quiet week)"}}
**🤝 Pipeline**
- Salons: {{N}} new conversations, {{M}} anchor confirmations
- Investors: {{N}} active, {{M}} new intros
- Hires: {{N}} candidates active
**🎯 Decisions needed**
1. [{{id}}] {{description}} — by {{deadline}} ({{effort}})
2. ...
**📅 Next week's top 3 bets**
1. ...
2. ...
3. ...
{{Optional footer: ⚠️ <single critical risk line if any>}}
Procedure
- Compute header line. Week ISO + quarter + date range from aggregate.
- Shipped section. Iterate
aggregate.shipped[]. Format as bullet per source. If empty, write(quiet week — no new shipped items). - Slipped section. Iterate
aggregate.slipped[]. Append age days. If empty, write(none flagged). - Metrics section. Format each delta with sign (+/-/=). For percentages, prepend
%. For currency, prepend$. Always show this_week and last_week side by side. - Content section. Render LinkedIn + social lines per template. If queue is
(no output this week), write(queue stale — needs source). - Pipeline section. Three lines (salons / investors / hires). If counts are all zero, write
(quiet week — no new activity). - Decisions section. Iterate
aggregate.decisions_needed[]. Number 1-N. Cap at 5 — if more, take the 5 highest-priority and write(N more — see outputs/decisions_{YYYY-MM}.md)at end. - Next week's bets. Iterate
aggregate.next_week_bets[]. Cap at 3. - Risk footer. If
aggregate.risks_flagged[]has any item with severityhighorcritical, add the line at the bottom with ⚠️ prefix. - Length check. Total body ≤ 2500 chars. If over, truncate Decisions list first, then Metrics, then Slipped. Always preserve Shipped + Next week's bets + Decisions IDs.
- Header block. Add the strict-shape header (Action/Output/Learned/Handoff/Risk) ABOVE the
### 📊line so send_telegram.mjsextractBody()strips it correctly. - Write to journal. Path:
agents/journal/<UTC-YYYY-MM-DD>_founder-cockpit_autopilot.md. Append (not overwrite) — multiple cockpit cycles in a day are allowed but rare.
Degraded Mode
If aggregate.degraded_critical == true, produce a single-line alert body instead:
### 🚨 Weekly cockpit blocked
{{N}} agents stale, {{M}} fetchers missing. See GitHub Actions for detail.
Decisions still surfaced (if any):
1. ...
2. ...
This still pushes to Telegram — the founder needs to know the system is degraded, not just see silence. Decisions still surface because they're the highest-leverage section.
Rules
- Telegram body ≤ 2500 chars (single message)
- All times in TRT (UTC+3), never UTC in user-facing text
- No markdown tables (Telegram strips them)
- Light emoji per section header only — no emoji storms in body
- Section order is canonical per
RULES.md, never reorder - If a metric is
(stale), do not show a delta — just(stale this week) - Round status is one line, not multi-line — detail lives in investor-relations
- Customer / salon names anonymized per
RULES.md