chore: add standup dashboard with CI audit integration

Dash app at .codeflash/standups/ that pulls GitHub PR data across
codeflash, codeflash-internal, codeflash-agent, and github-workflows,
renders standup notes from markdown, and includes CI audit report.
This commit is contained in:
Kevin Turcios 2026-04-23 09:25:37 -05:00
parent 3ee9c22c8e
commit fdfddea297
5 changed files with 704 additions and 0 deletions

475
.codeflash/standups/app.py Normal file
View file

@ -0,0 +1,475 @@
"""Codeflash Standup Dashboard
Two-tab report served at http://localhost:8052/:
1. Today hero metrics, open PRs, recently merged PRs, standup notes
2. History past standup entries with PR activity timeline
"""
import json
from pathlib import Path
import plotly.graph_objects as go
from dash import Dash, Input, Output, dash_table, dcc, html
from theme import (
ACCENT,
AMBER,
BG,
BLUE,
CARD,
CARD_BORDER,
FONT,
GRAY,
GREEN,
GRID_OVERLAY,
MONO,
PURPLE,
SLATE,
TABLE_CELL,
TABLE_DATA,
TABLE_DATA_CONDITIONAL,
TABLE_HEADER,
TABLE_WRAP,
WHITE,
)
DATA_FILE = Path(__file__).parent / "data.json"
def load_data() -> dict:
return json.loads(DATA_FILE.read_text(encoding="utf-8"))
app = Dash(__name__)
app.title = "Codeflash Standup"
def hero_card(label: str, value: str | int, color: str = ACCENT) -> html.Div:
return html.Div(
[
html.Div(str(value), style={"fontSize": "36px", "fontWeight": "700", "color": color, "fontFamily": MONO}),
html.Div(label, style={"fontSize": "13px", "color": GRAY, "marginTop": "4px"}),
],
style={**CARD, "textAlign": "center", "minWidth": "160px", "flex": "1"},
)
def pr_table(prs: list[dict], table_id: str) -> html.Div:
rows = []
for pr in prs:
rows.append(
{
"Repo": pr["repo"],
"#": pr["number"],
"Title": pr["title"],
"Author": pr["author"],
"Updated": pr["updated_at"][:10],
}
)
if not rows:
return html.Div("No PRs", style={"color": GRAY, "padding": "16px"})
return html.Div(
dash_table.DataTable(
id=table_id,
columns=[{"name": c, "id": c} for c in ["Repo", "#", "Title", "Author", "Updated"]],
data=rows,
style_header=TABLE_HEADER,
style_cell=TABLE_CELL,
style_data=TABLE_DATA,
style_data_conditional=TABLE_DATA_CONDITIONAL,
page_size=15,
style_table={"overflowX": "auto"},
),
style=TABLE_WRAP,
)
def notes_section(notes: list[dict]) -> html.Div:
if not notes:
return html.Div("No standup notes yet.", style={"color": GRAY, "padding": "16px"})
children = []
for note in notes:
title = note.get("title", note["date"])
sections = note.get("sections", {})
items = []
for section_name, bullets in sections.items():
items.append(
html.H4(section_name.title(), style={"color": ACCENT, "margin": "16px 0 8px 0", "fontSize": "16px"})
)
for i, b in enumerate(bullets, 1):
items.append(
html.Li(
f"{i}. {b}",
style={"color": SLATE, "fontSize": "16px", "lineHeight": "1.6", "marginBottom": "8px"},
)
)
children.append(
html.Div(
[
html.H3(title, style={"color": WHITE, "fontSize": "16px", "marginBottom": "8px"}),
html.Ol(items, style={"listStyle": "none", "paddingLeft": "20px"}),
],
style={**CARD, "marginBottom": "16px"},
)
)
return html.Div(children)
def repo_breakdown_chart(prs: list[dict], title: str) -> dcc.Graph:
repo_counts: dict[str, int] = {}
for pr in prs:
repo_counts[pr["repo"]] = repo_counts.get(pr["repo"], 0) + 1
repos = list(repo_counts.keys())
counts = list(repo_counts.values())
colors = [ACCENT, BLUE, GREEN, PURPLE, AMBER]
fig = go.Figure(
go.Bar(
x=repos,
y=counts,
marker_color=colors[: len(repos)],
text=counts,
textposition="outside",
textfont={"color": WHITE, "size": 14},
)
)
fig.update_layout(
title={"text": title, "font": {"color": WHITE, "size": 16}},
paper_bgcolor="rgba(0,0,0,0)",
plot_bgcolor="rgba(0,0,0,0)",
font={"color": SLATE, "family": FONT},
xaxis={"gridcolor": CARD_BORDER, "color": GRAY},
yaxis={"gridcolor": CARD_BORDER, "color": GRAY, "dtick": 1},
margin={"l": 40, "r": 20, "t": 50, "b": 40},
height=300,
)
return dcc.Graph(figure=fig, config={"displayModeBar": False})
def before_after_chart(labels: list[str], before: list[float], after: list[float], title: str) -> dcc.Graph:
fig = go.Figure()
fig.add_trace(
go.Bar(
name="Before",
x=labels,
y=before,
marker_color="#f87171",
text=before,
textposition="outside",
textfont={"color": WHITE, "size": 12},
)
)
fig.add_trace(
go.Bar(
name="After",
x=labels,
y=after,
marker_color=GREEN,
text=after,
textposition="outside",
textfont={"color": WHITE, "size": 12},
)
)
fig.update_layout(
barmode="group",
title={"text": title, "font": {"color": WHITE, "size": 16}},
paper_bgcolor="rgba(0,0,0,0)",
plot_bgcolor="rgba(0,0,0,0)",
font={"color": SLATE, "family": FONT},
xaxis={"gridcolor": CARD_BORDER, "color": GRAY},
yaxis={"gridcolor": CARD_BORDER, "color": GRAY},
legend={"font": {"color": SLATE}},
margin={"l": 40, "r": 20, "t": 50, "b": 40},
height=320,
)
return dcc.Graph(figure=fig, config={"displayModeBar": False})
def build_ci_audit_tab(audit: dict) -> html.Div:
billing = audit.get("billing", {})
ops = audit.get("operational_before_after", {})
run_vol = audit.get("run_volume", {})
hero_row = html.Div(
[
hero_card(
"Workflows", f"{ops.get('workflow_files', [0, 0])[0]}{ops.get('workflow_files', [0, 0])[1]}", GREEN
),
hero_card(
"Required Checks",
f"{ops.get('required_checks', [0, 0])[0]}{ops.get('required_checks', [0, 0])[1]}",
GREEN,
),
hero_card("Runs Eliminated/mo", f"{run_vol.get('total_eliminated_monthly', 0):,}", ACCENT),
hero_card("Annual Savings", f"${billing.get('overage_saved_annual_usd', 0):,}", GREEN),
],
style={"display": "flex", "gap": "16px", "marginBottom": "32px", "flexWrap": "wrap"},
)
charts_row = html.Div(
[
html.Div(
before_after_chart(
["Workflow Files", "Required Checks"],
[ops.get("workflow_files", [0])[0], ops.get("required_checks", [0])[0]],
[ops.get("workflow_files", [0, 0])[1], ops.get("required_checks", [0, 0])[1]],
"Operational Simplification",
),
style={"flex": "1", **CARD},
),
html.Div(
before_after_chart(
["Monthly Run Volume"],
[run_vol.get("codeflash_feb", 0)],
[run_vol.get("codeflash_apr_projected", 0)],
f"codeflash Runs ({run_vol.get('codeflash_reduction_pct', 0)}% reduction)",
),
style={"flex": "1", **CARD},
),
],
style={"display": "flex", "gap": "16px", "marginBottom": "32px", "flexWrap": "wrap"},
)
findings_rows = []
for repo, items in audit.get("findings", {}).items():
for f in items:
findings_rows.append(
{
"Repo": repo,
"Finding": f["finding"],
"Impact": f["impact"],
"Fix": f["fix"],
"PR": f.get("pr") or "",
}
)
findings_table = html.Div(
[
html.H2("Findings", style={"color": WHITE, "fontSize": "20px", "marginBottom": "16px"}),
html.Div(
dash_table.DataTable(
id="findings-table",
columns=[{"name": c, "id": c} for c in ["Repo", "Finding", "Impact", "Fix", "PR"]],
data=findings_rows,
style_header=TABLE_HEADER,
style_cell={**TABLE_CELL, "whiteSpace": "normal", "maxWidth": "300px"},
style_data=TABLE_DATA,
style_data_conditional=TABLE_DATA_CONDITIONAL,
page_size=20,
style_table={"overflowX": "auto"},
),
style=TABLE_WRAP,
),
],
style={"marginBottom": "32px"},
)
audit_prs = audit.get("prs_merged", [])
pr_rows = [{"PR": p["pr"], "Repo": p["repo"], "Date": p["date"], "Title": p["title"]} for p in audit_prs]
prs_table = html.Div(
[
html.H2("Audit PRs Merged", style={"color": WHITE, "fontSize": "20px", "marginBottom": "16px"}),
html.Div(
dash_table.DataTable(
id="audit-prs-table",
columns=[{"name": c, "id": c} for c in ["PR", "Repo", "Date", "Title"]],
data=pr_rows,
style_header=TABLE_HEADER,
style_cell=TABLE_CELL,
style_data=TABLE_DATA,
style_data_conditional=TABLE_DATA_CONDITIONAL,
page_size=15,
style_table={"overflowX": "auto"},
),
style=TABLE_WRAP,
),
],
style={"marginBottom": "32px"},
)
billing_row = html.Div(
[
hero_card("Overage Before (min/mo)", f"{billing.get('overage_before_min', 0):,}", "#f87171"),
hero_card("Overage After (min/mo)", f"{billing.get('overage_after_min', 0):,}", GREEN),
hero_card("Saved (min/mo)", f"{billing.get('overage_saved_min', 0):,}", ACCENT),
hero_card("Saved ($/mo)", f"${billing.get('overage_saved_monthly_usd', 0):,}", GREEN),
],
style={"display": "flex", "gap": "16px", "marginBottom": "32px", "flexWrap": "wrap"},
)
return html.Div(
[
html.Div(
f"Audit: {audit.get('audit_date', '?')} — Completed: {audit.get('completion_date', '?')}",
style={"color": GRAY, "fontSize": "13px", "marginBottom": "20px"},
),
hero_row,
charts_row,
billing_row,
findings_table,
prs_table,
]
)
def build_today_tab(data: dict) -> html.Div:
summary = data["summary"]
open_prs = data["open_prs"]
merged_prs = data["merged_prs"]
notes = data["notes"]
return html.Div(
[
html.Div(
[
hero_card("Open PRs", summary["total_open"], BLUE),
hero_card("Merged (7d)", summary["total_merged_7d"], GREEN),
hero_card("Drafts", summary["draft_count"], AMBER),
hero_card("Active Repos", summary["repos_with_open_prs"], PURPLE),
],
style={"display": "flex", "gap": "16px", "marginBottom": "32px", "flexWrap": "wrap"},
),
html.H2(
[
"Standup Notes ",
html.Span(
"(eventually everyone will create their own notes — a summary of what you worked on yesterday, what you'll be working on today, and any blockers)",
style={"color": GRAY, "fontSize": "14px", "fontWeight": "400"},
),
],
style={"color": WHITE, "fontSize": "20px", "marginBottom": "16px"},
),
notes_section(notes),
html.Div(
[
html.Div(
[
html.H2("Open PRs", style={"color": WHITE, "fontSize": "20px", "marginBottom": "16px"}),
pr_table(open_prs, "open-pr-table"),
],
style={"flex": "1", "minWidth": "0"},
),
html.Div(
[
html.H2(
"Merged (Last 7 Days)",
style={"color": WHITE, "fontSize": "20px", "marginBottom": "16px"},
),
pr_table(merged_prs, "merged-pr-table"),
],
style={"flex": "1", "minWidth": "0"},
),
],
style={"display": "flex", "gap": "24px", "marginBottom": "32px", "flexWrap": "wrap"},
),
html.Div(
[
html.Div(repo_breakdown_chart(open_prs, "Open PRs by Repo"), style={"flex": "1", **CARD}),
html.Div(repo_breakdown_chart(merged_prs, "Merged PRs by Repo (7d)"), style={"flex": "1", **CARD}),
],
style={"display": "flex", "gap": "16px", "marginBottom": "32px", "flexWrap": "wrap"},
),
]
)
def serve_layout():
data = load_data()
return html.Div(
[
html.Div(style=GRID_OVERLAY),
html.Div(
[
html.H1(
"Codeflash Standup",
style={"color": WHITE, "fontSize": "28px", "fontWeight": "700", "marginBottom": "4px"},
),
html.Div(
f"Generated {data['generated_at'][:10]}",
style={"color": GRAY, "fontSize": "13px", "marginBottom": "12px"},
),
html.Div(
"Hi guys, I wanted to introduce a new way to do standups. Remember it's still a WIP and I will improve it based on feedback, but for now bear with it...",
style={
"color": WHITE,
"fontSize": "18px",
"fontWeight": "500",
"lineHeight": "1.7",
"marginBottom": "28px",
"padding": "20px 24px",
"background": "rgba(255,210,39,0.08)",
"borderLeft": f"3px solid {ACCENT}",
"borderRadius": "8px",
},
),
dcc.Tabs(
id="tabs",
value="today",
children=[
dcc.Tab(
label="Today",
value="today",
style={
"color": GRAY,
"backgroundColor": "transparent",
"border": "none",
"padding": "12px 24px",
},
selected_style={
"color": ACCENT,
"backgroundColor": "transparent",
"border": "none",
"borderBottom": f"2px solid {ACCENT}",
"padding": "12px 24px",
},
),
dcc.Tab(
label="CI Audit",
value="ci_audit",
style={
"color": GRAY,
"backgroundColor": "transparent",
"border": "none",
"padding": "12px 24px",
},
selected_style={
"color": ACCENT,
"backgroundColor": "transparent",
"border": "none",
"borderBottom": f"2px solid {ACCENT}",
"padding": "12px 24px",
},
),
],
style={"marginBottom": "24px", "borderBottom": f"1px solid {CARD_BORDER}"},
),
dcc.Store(id="data-store", data=data),
html.Div(id="tab-content"),
],
style={
"maxWidth": "1200px",
"margin": "0 auto",
"padding": "40px 24px",
"position": "relative",
"zIndex": "1",
},
),
],
style={"backgroundColor": BG, "minHeight": "100vh", "fontFamily": FONT, "color": SLATE},
)
app.layout = serve_layout
@app.callback(Output("tab-content", "children"), Input("tabs", "value"), Input("data-store", "data"))
def render_tab(tab: str, data: dict):
if tab == "ci_audit":
ci_audit = data.get("ci_audit")
return (
build_ci_audit_tab(ci_audit)
if ci_audit
else html.Div("No CI audit data found.", style={"color": GRAY, "padding": "16px"})
)
return build_today_tab(data)
if __name__ == "__main__":
app.run(port=8052, debug=True)

View file

@ -0,0 +1,124 @@
"""Pull GitHub PR data and standup notes into data.json for the Dash app."""
import json
import os
import re
from datetime import datetime, timedelta, timezone
from pathlib import Path
import requests
REPOS = ["codeflash", "codeflash-internal", "codeflash-agent", "github-workflows"]
ORG = "codeflash-ai"
NOTES_DIR = Path(__file__).parent / "notes"
DATA_FILE = Path(__file__).parent / "data.json"
CI_AUDIT_FILE = Path(__file__).parents[2] / ".." / "codeflash-agent" / "reports" / "codeflash-ci-audit" / "data.json"
def gh_token() -> str:
token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN", "")
if not token:
import subprocess
result = subprocess.run(["gh", "auth", "token"], capture_output=True, text=True, check=False)
token = result.stdout.strip()
return token
def gh_headers() -> dict[str, str]:
return {"Authorization": f"token {gh_token()}", "Accept": "application/vnd.github+json"}
def fetch_prs(state: str, since: datetime | None = None) -> list[dict]:
prs = []
for repo in REPOS:
url = f"https://api.github.com/repos/{ORG}/{repo}/pulls"
params: dict[str, str] = {"state": state, "per_page": "30", "sort": "updated", "direction": "desc"}
resp = requests.get(url, headers=gh_headers(), params=params, timeout=15)
if resp.status_code != 200:
continue
for pr in resp.json():
updated = datetime.fromisoformat(pr["updated_at"].replace("Z", "+00:00"))
if since and updated < since:
continue
prs.append(
{
"repo": repo,
"number": pr["number"],
"title": pr["title"],
"state": pr["state"],
"author": pr["user"]["login"],
"url": pr["html_url"],
"created_at": pr["created_at"],
"updated_at": pr["updated_at"],
"merged_at": pr.get("merged_at"),
"draft": pr.get("draft", False),
}
)
return prs
def parse_note(path: Path) -> dict:
text = path.read_text(encoding="utf-8")
sections: dict[str, list[str]] = {}
current = None
title = None
for line in text.splitlines():
h1 = re.match(r"^#\s+(.+)", line)
if h1 and not title:
title = h1.group(1).strip()
continue
heading = re.match(r"^##\s+(.+)", line)
if heading:
current = heading.group(1).strip().lower()
sections[current] = []
elif current and line.strip().startswith("- "):
sections[current].append(line.strip().removeprefix("- "))
return {"date": path.stem, "title": title or path.stem, "sections": sections}
def load_notes() -> list[dict]:
if not NOTES_DIR.exists():
return []
notes = []
for f in sorted(NOTES_DIR.glob("*.md"), reverse=True):
notes.append(parse_note(f))
return notes
def main():
now = datetime.now(timezone.utc)
week_ago = now - timedelta(days=7)
open_prs = fetch_prs("open")
closed_prs = fetch_prs("closed", since=week_ago)
merged_prs = [pr for pr in closed_prs if pr["merged_at"]]
notes = load_notes()
ci_audit = None
resolved = CI_AUDIT_FILE.resolve()
if resolved.exists():
ci_audit = json.loads(resolved.read_text(encoding="utf-8"))
data = {
"generated_at": now.isoformat(),
"org": ORG,
"repos": REPOS,
"open_prs": open_prs,
"merged_prs": merged_prs,
"notes": notes,
"summary": {
"total_open": len(open_prs),
"total_merged_7d": len(merged_prs),
"draft_count": sum(1 for pr in open_prs if pr["draft"]),
"repos_with_open_prs": len({pr["repo"] for pr in open_prs}),
},
"ci_audit": ci_audit,
}
DATA_FILE.write_text(json.dumps(data, indent=2), encoding="utf-8")
print(f"Wrote {DATA_FILE} ({len(open_prs)} open, {len(merged_prs)} merged)")
if __name__ == "__main__":
main()

View file

@ -0,0 +1,30 @@
# Kevin — 2026-04-23
## Done
- CI audit across codeflash org: disabled Actions on 200+ forks, built interactive Dash cost report showing ~$12K/yr savings
- Scaffolded codeflash-api FastAPI rewrite (all 9 endpoints), unified sync/async code paths, set up Postgres integration tests with testcontainers, 78% coverage
- Project governance: enabled GitHub Discussions, created parent issue #2079 for 100% test coverage, filed coverage issue on typeagent-py
- Merged 5 PRs on codeflash: PR template + linked-issue policy (#2093), coverage CI with 58% floor (#2094), CODEOWNERS (#2095), 2 dependabot bumps
- Triaged ~28 open PRs, posted contributor follow-ups, closed stale PRs and reopened as issues
- Reimplemented JS function tracer from stale PR #1377 onto current main as PR #2105
- Created PRs #244 (tests for resolve_azure_model_name) and #245 (max_retries bump) on typeagent-py
- Bumped stale action versions across 3 repos (setup-uv, prek-action, gh-action-pypi-publish)
- Fixed 3-month-old VSCode extension build failure from out-of-sync package-lock.json (PR #2617)
- Extended shared ci-python-uv.yml with test-secret-env input, migrated aiservice-test job to use it (PR #2620)
- Initialized tessl (vendored mode) across codeflash, codeflash-internal, and codeflash-agent with weekly tile update workflows
- Created codeflash-ci-bot GitHub App for PR creation (enterprise GITHUB_TOKEN workaround)
- Added org-level ruleset requiring PR branches to be up to date with main
- Ran vulture dead-code audit (428/432 false positives), deleted 4 verified dead items, added vulture as dev dep
- Cleaned up 19 stale local branches and removed associated worktrees
## Blocked
- Need more perms across the org
## Next
- Missing tessl tiles (~20 on internal, ~13 on agent) will resolve as tessl publishes them
- Unpin claude-code-action once Bedrock OIDC regression is fixed
- Re-enable Dependabot to address 24 known vulnerabilities
- Improve comparator coverage (52%, identified as biggest gap)

View file

@ -0,0 +1,12 @@
[project]
name = "codeflash-standups"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"dash[cloud]>=4.1",
"plotly>=6.7",
"requests>=2.31",
]
[project.scripts]
standup = "generate:main"

View file

@ -0,0 +1,63 @@
"""Theme and styling constants for the standup report."""
# ── Colors (Codeflash dark - amber/zinc) ────────────────────────────────────
ACCENT = "#ffd227"
DARK = "#09090b"
CARD_BG = "rgba(16,20,28,0.7)"
CARD_BORDER = "rgba(63,63,70,0.35)"
SLATE = "#e4e4e7"
GRAY = "#a1a1aa"
LIGHT_GRAY = "#71717a"
BG = "#0d1117"
WHITE = "#fafafa"
GREEN = "#4ade80"
LIGHT_GREEN = "rgba(74,222,128,0.12)"
RED = "#f87171"
LIGHT_RED = "rgba(248,113,113,0.12)"
AMBER = "#fbbf24"
BLUE = "#60a5fa"
PURPLE = "#a78bfa"
GRID_BG_IMAGE = (
"linear-gradient(to right, currentColor 1px, transparent 1px),"
"linear-gradient(to bottom, currentColor 1px, transparent 1px)"
)
GRID_BG_SIZE = "48px 48px"
GRID_OVERLAY = {
"position": "fixed",
"top": 0,
"left": 0,
"right": 0,
"bottom": 0,
"backgroundImage": GRID_BG_IMAGE,
"backgroundSize": GRID_BG_SIZE,
"opacity": "0.05",
"pointerEvents": "none",
"zIndex": "0",
}
CARD = {"background": CARD_BG, "borderRadius": "16px", "padding": "28px 32px", "border": f"1px solid {CARD_BORDER}"}
FONT = "'Inter', system-ui, -apple-system, sans-serif"
MONO = "'JetBrains Mono', 'Menlo', monospace"
TABLE_HEADER: dict[str, str] = {
"backgroundColor": "rgba(24,24,27,0.8)",
"color": ACCENT,
"fontWeight": "600",
"fontSize": "13px",
"padding": "12px 16px",
"borderBottom": f"1px solid {CARD_BORDER}",
}
TABLE_CELL: dict[str, str] = {
"textAlign": "left",
"padding": "12px 16px",
"fontSize": "13px",
"fontFamily": FONT,
"border": "none",
"color": SLATE,
}
TABLE_DATA: dict[str, str] = {"backgroundColor": "rgba(24,24,27,0.5)", "color": SLATE}
TABLE_DATA_CONDITIONAL: list[dict[str, object]] = [
{"if": {"row_index": "odd"}, "backgroundColor": "rgba(31,31,35,0.6)"}
]
TABLE_WRAP: dict[str, str] = {"borderRadius": "16px", "overflow": "hidden", "border": f"1px solid {CARD_BORDER}"}