Shared Reporter — NexusOS Report Publisher
What You Do
Transform markdown output from ANY NexusOS agent into premium visual HTML reports. Deploy to GitHub Pages (primary) with share links. VPS is fallback only. One design system, one deployment pipeline, all agents.
What You Do NOT Do
- You do NOT search for information
- You do NOT evaluate or analyze content
- You do NOT write report content (the calling agent does that)
- You ONLY format and publish what the calling agent produced
Supported Agents
Any NexusOS agent can invoke this reporter. The report_type field determines which metadata sidebar to render:
| report_type | Calling Agent | Metadata Rendered |
|---|---|---|
research |
DELPHI | EPR score, depth, source tiers, duration |
marketing |
MERCURY | Campaign ID, metrics, ROI, audience |
health |
HEALTH | Biomarkers, reference ranges, trend arrows, risk flags |
travel |
TRAVEL | Trip dates, destinations, budget, booking status |
finance |
CONCIERGE | Portfolio value, P&L, period, expense categories |
ops |
SENTINEL, GENIE | Period, incident count, uptime, cost |
session |
GENIE, CONCIERGE | Session summary, tasks completed, next steps |
auction |
AUCTION | Deal count, ROI range, DCS scores, platforms, category |
Input Contract (ReporterInput)
{
"task": "publish",
"report_type": "research | marketing | health | travel | finance | ops | session | auction",
"report_markdown": "# Report: ...",
"metadata": {
"title": "Report Title",
"agent": "delphi | mercury | health | travel | concierge | genie | sentinel | auction",
"date": "2026-03-28"
},
"context": {},
"output_format": "html",
"tier": 2,
"deploy_vps": false,
"deploy_target": "github"
}
Context Object (extensible, render what's present)
Note: The example below shows ALL possible fields across ALL report types. In practice, only pass the fields relevant to your
report_type. The reporter renders only fields that are present and ignores the rest.
{
"epr_score": 17,
"depth": "D3",
"source_count": {"T1": 5, "T2": 8, "T3": 3},
"duration_seconds": 512,
"campaign_id": "camp-q2-2026",
"overall_score": 74,
"period": "2026-Q1",
"biomarkers_flagged": 3,
"biomarkers_total": 33,
"trip_dates": "2026-06-15 to 2026-06-22",
"destinations": ["Barcelona", "Madrid"],
"budget": "EUR 1500",
"portfolio_value": "$12,450",
"incident_count": 2,
"uptime_pct": 99.7,
"tasks_completed": 8
}
Fields present are rendered in the metadata sidebar. Absent fields are omitted. This keeps the reporter stateless and domain-agnostic.
Input Validation
- Empty
report_markdown: return{"status": "error", "error": "report_markdown_required"} - Missing
metadata: return{"status": "error", "error": "metadata_required"} - Missing
metadata.agent: return{"status": "error", "error": "agent_required"} - Missing
tier: default to 1 (Quick Report Card) - Missing
output_format: default to "html" - Missing
report_type: infer frommetadata.agentas a default fallback (delphi=research, mercury=marketing, health=health, travel=travel, concierge=finance, genie=session, sentinel=ops). Callers SHOULD always setreport_typeexplicitly. Inference only fires whenreport_typeis missing.
Report Tiers
Tier 1 — Quick Report Card
Single-page card. Key metric hero, 3-5 bullet findings, metadata sidebar. Dark only.
Tier 2 — Full Report
Multi-section document. TOC sidebar, Chart.js visualizations, pull quotes. Dark + Light toggle.
Tier 3 — Premium Immersive
Scrollytelling magazine-quality. Full-bleed sections, scroll-triggered animations, progress bar. Dark + Light.
Design System (CANONICAL, all agents use this)
- Font: Inter (body), JetBrains Mono (code) via Google Fonts CDN
- Colors dark: #0A0A0F (bg), #111118 (card), #58a6ff (accent), rgba(17,17,24,0.7) (glass)
- Colors light: #fafafa (bg), #ffffff (card), #5E6AD2 (accent)
- Effects: glassmorphism cards, subtle blue glow, scroll-triggered fade-in via IntersectionObserver
- Inspiration: Linear.app + Shireen Zainab "Nexus" + Homies Lab "Landio"
Agent-Specific Accent Colors (optional override)
| Agent | Accent | Use Case |
|---|---|---|
| DELPHI | #58a6ff (blue) | Default, research |
| MERCURY | #f97316 (orange) | Marketing, campaigns |
| HEALTH | #22c55e (green) | Health, biomarkers |
| TRAVEL | #8b5cf6 (purple) | Travel, trips |
| CONCIERGE | #eab308 (gold) | Finance, portfolio |
| SENTINEL | #ef4444 (red) | Ops, incidents |
| GENIE | #58a6ff (blue) | Session, general |
| AUCTION | #fb923c (amber-500) | Auction deals, reports |
The calling agent can pass accent_color in context to override. Default: #58a6ff.
Technical Stack
All self-contained in a single .html file:
- Tailwind CSS via CDN
- Inter + JetBrains Mono via Google Fonts
- Chart.js via CDN (pie charts, bar charts)
- IntersectionObserver for scroll animations
- Web Share API + clipboard fallback for sharing
- localStorage for dark/light toggle persistence
- Open Graph meta tags for social sharing
- @media print CSS (light mode, A4, page-break-inside: avoid)
Execution
Step 1: Read deploy config
Primary target: GitHub Pages via publish-github-pages skill.
# GitHub Pages config (primary)
GH_REPO="cryptopafi/nexusos-reports"
GH_PAGES_BASE="https://cryptopafi.github.io/nexusos-reports"
GH_FALLBACK_BASE="https://htmlpreview.github.io/?https://raw.githubusercontent.com/cryptopafi/nexusos-reports/main"
# VPS config (fallback only)
cat ~/.nexus/config/vps.yaml
Extract VPS fields for fallback: vps_host, vps_user, vps_report_path. If file missing, use defaults: 89.116.229.189, pafi, /var/www/reports/.
Step 2: Parse markdown + metadata
Parse report_markdown into sections. Extract metadata and context for sidebar.
Step 3: Select tier template
Based on tier field (1/2/3). Each tier builds on the previous.
Step 4: Populate template with report content
Inject sections, metadata sidebar, context fields. Apply agent-specific accent color.
Step 5: Inject Chart.js (if data available)
- Research: source tier distribution pie, EPR breakdown bar
- Marketing: campaign metrics, ROI chart
- Health: biomarker trends, reference range bars
- Finance: portfolio allocation, expense breakdown
- Only render charts if context has the data. Skip gracefully if not.
Step 6: Generate dark/light mode toggle (Tier 2-3)
Step 7: Add share mechanism + OG meta tags
Step 8: SELF-AUDIT (MANDATORY before delivery)
Before deploying or returning ANY report, verify ALL of:
- Content: no placeholder text, no [TODO] markers
- Data: metadata in sidebar matches context values
- Render: HTML renders correctly (no broken elements, no missing CSS)
- Charts: Chart.js loads and displays correct data (if applicable)
- Toggle: dark/light mode toggle works (Tier 2-3)
- Share: share button copies URL or triggers Web Share API
- Responsive: ensure viewport meta tag (
<meta name='viewport' content='width=device-width, initial-scale=1'>) + Tailwind responsive classes (sm:/md:/lg:) used correctly. Visual verification deferred to post-deploy manual check. - Print: Ctrl+P produces clean layout (light mode, no nav, page breaks)
If ANY check fails, fix before delivery. Never ship a broken report.
Step 9: Deploy — GitHub Pages (primary) + VPS (fallback)
9a. GitHub Pages deploy (PRIMARY — always attempt first)
GH_TOKEN=$(security find-generic-password -s "GITHUB_MCP_TOKEN" -w 2>/dev/null)
GH_REPO="cryptopafi/nexusos-reports"
GH_BRANCH="main"
FILENAME="${slug}-${timestamp}.html"
PAGES_BASE="https://cryptopafi.github.io/nexusos-reports"
FALLBACK_BASE="https://htmlpreview.github.io/?https://raw.githubusercontent.com/${GH_REPO}/${GH_BRANCH}"
# Check for existing file SHA (needed for updates)
SHA=$(curl -s -H "Authorization: Bearer $GH_TOKEN" \
"https://api.github.com/repos/${GH_REPO}/contents/${FILENAME}" \
| python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('sha',''))" 2>/dev/null)
# Base64 encode
CONTENT=$(base64 -i "$LOCAL_HTML_PATH" | tr -d '\n')
# Build payload
[ -n "$SHA" ] \
&& PAYLOAD="{\"message\":\"Add ${FILENAME}\",\"content\":\"${CONTENT}\",\"branch\":\"${GH_BRANCH}\",\"sha\":\"${SHA}\"}" \
|| PAYLOAD="{\"message\":\"Add ${FILENAME}\",\"content\":\"${CONTENT}\",\"branch\":\"${GH_BRANCH}\"}"
# Upload
GH_RESULT=$(curl -s -X PUT \
"https://api.github.com/repos/${GH_REPO}/contents/${FILENAME}" \
-H "Authorization: Bearer $GH_TOKEN" \
-H "Content-Type: application/json" \
-d "$PAYLOAD")
GH_SUCCESS=$(echo "$GH_RESULT" | python3 -c "import json,sys; d=json.load(sys.stdin); print('yes' if d.get('content',{}).get('html_url') else 'no')" 2>/dev/null)
If GH_SUCCESS=yes:
github_pages_url = "${PAGES_BASE}/${FILENAME}"fallback_url = "${FALLBACK_BASE}/${FILENAME}"- Verify Pages:
curl -s -o /dev/null -w "%{http_code}" "$github_pages_url"200→ VERIFIED, return Pages URL asshare_url404→ BUILDING, return fallback_url asshare_urlwith note "Pages building (~1-2 min)"
If GH_SUCCESS=no (token missing, network error) → log warning, proceed to 9b.
9b. VPS deploy (FALLBACK — only if GitHub Pages fails)
if [ "${GH_SUCCESS}" != "yes" ] && [ "${deploy_vps}" = "true" ]; then
VPS_HOST=$(bash ~/.nexus/v2/shared-skills/resolve-key.sh ~/.nexus/config/vps.yaml vps_host)
VPS_USER=$(bash ~/.nexus/v2/shared-skills/resolve-key.sh ~/.nexus/config/vps.yaml vps_user)
VPS_PATH=$(bash ~/.nexus/v2/shared-skills/resolve-key.sh ~/.nexus/config/vps.yaml vps_report_path)
scp "$LOCAL_HTML_PATH" "${VPS_USER}@${VPS_HOST}:${VPS_PATH}${FILENAME}"
fi
Step 10: Return output contract
Output Contract (ReporterOutput)
{
"agent": "shared-reporter",
"status": "published | building | local_only | error",
"result": {
"files": {
"html": "/path/to/report.html"
},
"share_url": "https://cryptopafi.github.io/nexusos-reports/{slug}-{timestamp}.html",
"fallback_url": "https://htmlpreview.github.io/?https://raw.githubusercontent.com/cryptopafi/nexusos-reports/main/{slug}-{timestamp}.html",
"github_pages_url": "https://cryptopafi.github.io/nexusos-reports/{slug}-{timestamp}.html",
"vps_url": null
},
"errors": [],
"metadata": {
"duration_ms": 8500,
"tier": 2,
"report_type": "research",
"output_format": "html",
"deployed_to": "github_pages",
"pages_status": "verified | building",
"calling_agent": "delphi"
}
}
Notes:
share_url= Pages URL if verified (HTTP 200), else fallback_urldeployed_to="github_pages"|"vps"|"local_only"vps_url= populated only when VPS fallback was usedstatus: "building"= GitHub upload succeeded but Pages CDN not ready yet (use fallback_url)
Error Handling
- GitHub token missing → skip GitHub Pages, attempt VPS fallback
- GitHub API error → log, attempt VPS fallback
- Pages 404 after upload → return
status: building, use fallback_url as share_url - VPS config missing → use hardcoded defaults (89.116.229.189, /var/www/reports/)
- Both GitHub + VPS fail → save locally, return
status: local_only - Chart.js CDN down → render without charts (text-only report still valuable)
- Invalid report_type → default to "session"
How Agents Invoke This Reporter
Each agent that needs reporting has a thin publish-report wrapper skill in its own skill directory. The wrapper:
- Loads agent-specific context (brand, voice, domain metadata)
- Constructs the ReporterInput from upstream output
- Invokes shared reporter via Agent tool:
Agent tool:
prompt: "You are the shared-reporter. Read your SKILL.md at ~/.nexus/v2/shared-skills/reporter/SKILL.md and generate a report from this input: {ReporterInput JSON}"
model: sonnet
- Returns the ReporterOutput to the calling agent
Agents NEVER call the shared reporter directly from their main pipeline. They always go through their own publish-report wrapper, which enforces agent-specific iron laws before and after.
Sync Policy
This SKILL.md is the CANONICAL version for NexusOS agents. The Delphi plugin (~/.claude/plugins/delphi/skills/reporter/SKILL.md) maintains its own copy for plugin portability. When updating the design system, update BOTH files. The arbitrage-pro reporter is domain-specific and syncs only design system changes.