{% extends "base.html" %} {% set active_nav = "dashboard" %} {% block title %}Distill Dashboard{% endblock %} {% block content %}

Dashboard

v{{ version }}

{% set has_corpus = topics or total_videos or site_count or paper_count %} {% if not has_corpus %}

Start here

Build your first corpus

Initialize Distill, verify the local setup, then preview a source before you ingest it.

  1. distill --cost-mode no-metered init
  2. distill --cost-mode no-metered doctor
  3. distill --cost-mode no-metered papers "topic" -n 5 --preview

These commands refuse API-billed routes. Use distill --cost-mode paid-ok init only when you intend live cloud-key validation.

{% else %}
{% for label, value in [ ("Topics", topics|length|string), ("Channels", total_channels|string), ("Videos", total_videos|string), ("Sites", site_count|string), ("Papers", paper_count|string), ("Recent Spend", "$%.2f"|format(recent_spend) if recent_spend is not none else "Unavailable"), ("Next Sweep", "$%.2f"|format(next_sweep_cost)) ] %}
{{ label }}
{{ value }}
{% endfor %}

Stay Current

    {% for t in topics[:8] %}
  • {{ t }} {{ lib.get_channels(t)|length }} ch
  • {% endfor %}
{% if watchlist %}

Channel Watches

    {% for w in watchlist[:6] %}
  • {{ w.name }} {{ w.topic }} / {{ w.days }}d
  • {% endfor %}
{% endif %} {% if topic_watchlist %}

Topic Watches

    {% for tw in topic_watchlist[:6] %}
  • {{ tw.name }} {{ tw.cadence }} / {{ tw.days }}d / {{ tw.limit }} picks {% if tw.paused %}paused{% endif %}
  • {% endfor %}
{% endif %}

Learn Fast

  • {{ synthesis_count }} topic syntheses
  • {{ report_count }} reports / {{ brief_count }} briefs
  • {{ page_count }} site pages

What Changed

    {% if topic_changes %} {% for topic_name, summary in topic_changes %}
  • {{ topic_name }} · {{ summary }}
  • {% endfor %} {% elif recent_artifacts %} {% for mtime, kind, label in recent_artifacts %}
  • {{ kind }}: {{ label }} {{ mtime.strftime('%b %d %I:%M %p') }}
  • {% endfor %} {% else %}
  • No recent changes
  • {% endif %}

Build Corpus

  • {{ total_videos }} video insights ({{ full_videos }} full / {{ scan_videos }} scan)
  • {{ site_count }} sites / {{ page_count }} pages
  • {{ paper_count }} papers
{% if topic_spend_rollups %}

Top Spend (30d)

    {% for topic_name, cost, runs in topic_spend_rollups %}
  • {{ topic_name }} · ${{ "%.2f"|format(cost) }} / {{ runs }} runs
  • {% endfor %}
{% endif %} {% if source_spend_rollups %}

By Source (30d)

    {% for source, cost, runs in source_spend_rollups %}
  • {{ source }} · ${{ "%.2f"|format(cost) }} / {{ runs }} runs
  • {% endfor %}
{% endif %}

Recent Activity

{% for entry in recent_runs|reverse %} {% else %} {% endfor %}
Recent activity
WhenCommandCostTime
{{ entry.get('timestamp', '')|format_timestamp }} {{ entry.get('command', 'unknown') }} ${{ "%.2f"|format(entry.get('actual_cost', 0)|float) }} {{ "%.1f"|format(entry.get('elapsed_seconds', 0)|float) }}s
No runs logged yet

Needs Attention

{% if latest_results.get('failed') %}
Latest run failed items: {{ latest_results.failed }}
{% endif %} {% if latest_issues %}
Latest run issues: {{ latest_issues|length }}
{% endif %} {% for msg in stale_topic_watches[:5] %}
{{ msg }}
{% endfor %} {% for msg in corpus_health_warnings[:5] %}
{{ msg }}
{% endfor %} {% for msg in budget_messages[:5] %}
{{ msg }}
{% endfor %} {% for item in cost_warnings[:5] %}
{{ item.message }}
{% endfor %} {% if not latest_results.get('failed') and not latest_issues and not stale_topic_watches and not corpus_health_warnings and not budget_messages and not cost_warnings %} {% if recent_runs %}
No immediate issues from the latest run logs
{% else %}
No run issues logged yet. Issues appear after ingest or watch runs.
{% endif %} {% endif %}
{% endif %}
{% endblock %}