Skip to content

ROLE: Founder / CEO ​

examples/20-role-founder.halo policies |* parallel

Morning briefing — synthesize metrics, news, and investor updates into an executive summary

Open in the playground →

halo
// ============================================================
// ROLE: Founder / CEO
// PURPOSE: Morning briefing — synthesize metrics, news, and
//          investor updates into an executive summary
// ============================================================

policy Confidential    : Redact(Revenue) & Redact(SalaryData)
policy BrevityPolicy   : MaxWords(500)

// --- Tools ---
tool StripeAPI       : REST("api.stripe.com/v1", apiKey: Env.STRIPE_KEY)
tool AnalyticsAPI    : REST("api.mixpanel.com/data", apiKey: Env.MIXPANEL_KEY)
tool NewsFeed        : REST("api.newsapi.org/v2", apiKey: Env.NEWS_KEY)
tool SlackFounder    : POST("hooks.slack.com/services/founder-digest")
tool InvestorCRM     : POST("api.affinity.co/api/updates")

// --- Store ---
tool DailyDigests    : VectorStore(Env.PINECONE_KEY, namespace: "founder-digests")
tool CompetitorIntel : VectorStore(Env.PINECONE_KEY, namespace: "competitor-tracking")

// --- Agents ---
@shadow(Analyst_V2)
agent Analyst [anthropic/claude-sonnet-4, temp: 0.1]
  system """
    You are a senior financial analyst at a Series B startup.
    Respond with structured JSON containing: value, delta,
    trend ("up"|"down"|"flat"), and confidence (0.0-1.0).
    Cross-reference metrics with news sentiment when available.
  """
  equips StripeAPI, AnalyticsAPI, NewsFeed, CompetitorIntel
  requires Confidential

agent Summarizer [openai/gpt-4o-mini, temp: 0.3]
  system """
    You are an executive communications specialist.
    Write concise, scannable briefings for a startup CEO.
    Use bullet points for metrics. Lead with what changed.
    Never exceed the word limit set by policy.
  """
  requires BrevityPolicy, Confidential

// --- The Pipeline ---
@timeout(5m)
@retry(2, 30s)
pipeline MorningBriefing(date: Date, company_name: String) -> Digest:
  date
    // Step 1: Fan-out — pull all data sources in parallel (fast, independent reads)
    |* {
         Analyst.fetch_metric(
           tool: StripeAPI,
           metric: "mrr",
           date: context.data.date,
           compare_to: "30d_ago"
         ) as stripe,
         Analyst.fetch_metric(
           tool: AnalyticsAPI,
           metric: "dau",
           date: context.data.date,
           compare_to: "7d_ago"
         ) as analytics,
         Analyst.search_news(
           tool: NewsFeed,
           query: context.data.company_name,
           sentiment: true
         ) as news,
         Analyst.track_competitors(
           tool: CompetitorIntel,
           since: "24h",
           signals: ["launch", "funding", "layoff"]
         ) as competitors
       }

    // Step 2: Context merges automatically — analyze trends
    |> Analyst.analyze_trends(
         metrics: [context.data.stripe, context.data.analytics],
         news: context.data.news,
         competitor_updates: context.data.competitors
       ) as trends

    // Step 3: Gate — if nothing significant changed, skip detailed report
    |? (context.data.analyze_trends.notable_changes > 0)

    // Step 4: Compose executive brief (max 500 words enforced by policy)
    |> Summarizer.brief(
         trends: context.data.analyze_trends,
         section_order: ["metrics", "news", "competitors", "action_items"],
         tone: "executive"
       ) as brief

    // Step 5: Post to founder Slack
    |> SlackFounder.post(
         message: context.data.brief.text,
         blocks: [context.data.brief.kpi_cards, context.data.brief.alerts],
         channel: "founder-morning"
       )

    // Step 6: Log to digest history for trend correlation
    |> DailyDigests.log(
         date: context.data.date,
         content: context.data.brief.text,
         tags: context.data.analyze_trends.tags
       )

curl -fsSL https://halolang.com/install.sh | sh