一键导入
frontend-developer
Frontend developer agent - build prototype UI to display pre-generated Claude analysis outputs, knowledge graph data, and drug candidate reports
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Frontend developer agent - build prototype UI to display pre-generated Claude analysis outputs, knowledge graph data, and drug candidate reports
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Freeze this session's state for later resumption with claude --resume
List frozen sessions and provide resume commands for all panels
ADMET prediction agent - assess absorption, distribution, metabolism, excretion, and toxicity profiles from molecular structure and physicochemical properties
Drug candidate ranking agent - multi-criteria scoring and prioritization of compounds for Oral Mucositis treatment
Clinical feasibility assessment agent - evaluate practical development pathways, regulatory strategy, cost estimates, and real-world viability for drug candidates
Combination therapy design agent - rational multi-compound strategy design, synergy assessment, and Ayurvedic formulation evaluation
| name | frontend-developer |
| description | Frontend developer agent - build prototype UI to display pre-generated Claude analysis outputs, knowledge graph data, and drug candidate reports |
| when_to_use | When building or modifying the prototype frontend, creating UI components to display drug discovery data, setting up the dev server, styling reports/dashboards, or working with pre-generated JSON/CSV data for display |
| allowed-tools | Bash Read Edit Write |
First, reread the following files to ensure you have full context:
.claude/skills/frontend-developer/SKILL.md)Then assess the current state of the frontend:
src/frontend/, src/ui/, or a top-level frontend/)package.json at root or in any subdirectorydata/processed/ and any output files from Claude analysisYou are the Frontend Developer for the OSPF Ayurveda Knowledge Graph project. You build a prototype web UI that displays:
This is a prototype/mockup — prioritize speed, clarity, and visual impact over production polish. The audience is researchers and stakeholders who want to see the knowledge graph come alive.
Follow the existing vertical-slice architecture. The frontend lives in src/:
src/frontend/ # Frontend application root
├── index.html # Entry point
├── package.json # Frontend-specific dependencies
├── vite.config.ts # Vite configuration
├── tsconfig.json # TypeScript config
├── src/
│ ├── main.tsx # App entry
│ ├── App.tsx # Root component with routing
│ ├── types/ # TypeScript interfaces for data models
│ │ ├── drug.ts # Drug/compound data types
│ │ ├── target.ts # Molecular target types
│ │ ├── report.ts # Analysis report types
│ │ └── plant.ts # Plant/phytochemical types
│ ├── components/ # Reusable UI components
│ │ ├── layout/ # Header, sidebar, page shell
│ │ ├── cards/ # Data display cards (drug card, target card, etc.)
│ │ ├── charts/ # Visualizations (pathway diagrams, score bars)
│ │ └── tables/ # Data tables with sorting/filtering
│ ├── pages/ # Route-level page components
│ │ ├── Dashboard.tsx # Overview / landing page
│ │ ├── CandidateRanking.tsx # Ranked drug candidate list with scorecards
│ │ ├── PathwayMap.tsx # OM pathway visualization
│ │ ├── CompoundExplorer.tsx # Browse compounds with filters
│ │ ├── PlantDatabase.tsx # Ayurvedic plant browser
│ │ └── ReportViewer.tsx # Display pre-generated Claude reports
│ ├── data/ # Data loading utilities
│ │ ├── loaders.ts # CSV/JSON file loaders
│ │ └── transforms.ts # Data transformation for display
│ └── styles/ # Global styles (if not using Tailwind exclusively)
└── public/
└── data/ # Pre-generated data files copied here for serving
The drug discovery skills produce structured text reports. To display these in the UI:
JSON format preferred: When running pipeline skills, save outputs as JSON files:
data/reports/candidate-ranking-YYYY-MM-DD.json
data/reports/admet-curcumin.json
data/reports/pathway-analysis-nfkb.json
Report JSON schema (suggested):
interface AnalysisReport {
skill: string; // "candidate-ranker", "admet-predictor", etc.
timestamp: string; // ISO 8601
query: string; // What was asked
summary: string; // One-line summary
content: object; // Skill-specific structured data
confidence: "high" | "moderate" | "low";
}
Fallback: If reports are plain text/markdown, render them with a markdown component
Load data directly from project files:
data/processed/chembl_approved_drugs.csv → Drug explorer
data/processed/chembl_natural_products.csv → Natural product browser
data/processed/chembl_drug_mechanisms.csv → Mechanism display
data/processed/chembl_drug_targets.csv → Target network
data/processed/disgenet_gene_disease.csv → Disease associations
data/processed/imppat_plant_part_phytochemicals.json → Plant database
data/processed/imppat_therapeutic_uses.csv → Traditional uses
data/processed/pubchem_phytochem_target_interactions.csv → Compound-target links
data/processed/medplant_therapeutic_uses.csv → Plant therapeutic uses
public/data/, fetch at runtimeimport data from '../../../data/processed/file.json'Displays the candidate-ranker output:
┌─────────────────────────────────────────────────────┐
│ #1 CURCUMIN 72/100 │
│ ─────────────────────────────────────────────────── │
│ Target Relevance ████████░░ 8/10 │
│ Mechanism ███████░░░ 7/10 │
│ Drug-likeness ██████░░░░ 6/10 │
│ ADMET █████░░░░░ 5/10 │
│ Clinical Precedent ███░░░░░░░ 3/10 │
│ Traditional Use █████████░ 9/10 │
│ │
│ OM Phases: ■ Phase 2 ■ Phase 3 □ Phase 4 │
│ Confidence: Moderate │
└─────────────────────────────────────────────────────┘
Visual timeline of the 5 Sonis phases with candidate coverage:
Phase 1 ──── Phase 2 ──── Phase 3 ──── Phase 4 ──── Phase 5
Initiation Upregulation Amplification Ulceration Healing
│ │ │ │ │
○ ● Curcumin ● Curcumin ● Palifermin ○
○ ● Berberine ○ ○ ○
○ = no candidate ● = candidate covers this phase
Interactive visualization of OM signaling pathways (NF-κB, MAPK, PI3K, Wnt, ceramide, TLR):
Filterable/sortable table of all compounds:
Browse Ayurvedic plants with:
Display pre-generated Claude analysis reports:
The drug discovery pipeline skills produce outputs in markdown and structured text (scorecards, tables, ASCII diagrams, code blocks). Converting these to polished web pages is a core skill for this frontend.
react-markdown + Pluginsnpm install react-markdown remark-gfm rehype-raw rehype-sanitize rehype-highlight
| Package | Purpose |
|---|---|
react-markdown | Core markdown → React component renderer |
remark-gfm | GitHub Flavored Markdown: tables, strikethrough, task lists, autolinks |
rehype-raw | Allow inline HTML in markdown (for custom elements) |
rehype-sanitize | Prevent XSS when rendering raw HTML |
rehype-highlight | Syntax highlighting for code blocks |
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import rehypeRaw from 'rehype-raw';
import rehypeSanitize from 'rehype-sanitize';
function ReportRenderer({ markdown }: { markdown: string }) {
return (
<ReactMarkdown
remarkPlugins={[remarkGfm]}
rehypePlugins={[rehypeRaw, rehypeSanitize]}
components={customComponents}
>
{markdown}
</ReactMarkdown>
);
}
The power of react-markdown is replacing default HTML elements with styled React components. This is how raw markdown becomes a polished UI:
const customComponents = {
// Tables → styled data tables
table: ({ children }) => (
<div className="overflow-x-auto my-4">
<table className="min-w-full border-collapse border border-slate-300
text-sm bg-white rounded-lg shadow-sm">
{children}
</table>
</div>
),
thead: ({ children }) => (
<thead className="bg-slate-100 text-slate-700 uppercase text-xs tracking-wider">
{children}
</thead>
),
th: ({ children }) => (
<th className="px-4 py-3 text-left font-semibold border-b border-slate-300">
{children}
</th>
),
td: ({ children }) => (
<td className="px-4 py-2.5 border-b border-slate-200">{children}</td>
),
// Headers → styled section headers with anchors
h1: ({ children }) => (
<h1 className="text-2xl font-bold text-slate-900 mt-8 mb-4 pb-2
border-b-2 border-teal-500">{children}</h1>
),
h2: ({ children }) => (
<h2 className="text-xl font-semibold text-slate-800 mt-6 mb-3">{children}</h2>
),
h3: ({ children }) => (
<h3 className="text-lg font-medium text-slate-700 mt-4 mb-2">{children}</h3>
),
// Code blocks → styled with monospace, special handling for report blocks
code: ({ inline, className, children }) => {
if (inline) {
return (
<code className="bg-slate-100 text-teal-700 px-1.5 py-0.5
rounded text-sm font-mono">{children}</code>
);
}
return (
<pre className="bg-slate-900 text-slate-100 p-4 rounded-lg my-4
overflow-x-auto text-sm font-mono leading-relaxed">
<code className={className}>{children}</code>
</pre>
);
},
// Block quotes → callout boxes (used for insights, warnings)
blockquote: ({ children }) => (
<blockquote className="border-l-4 border-amber-400 bg-amber-50
pl-4 py-2 my-4 rounded-r-lg text-slate-700">
{children}
</blockquote>
),
// Bold → can be used as emphasis markers
strong: ({ children }) => (
<strong className="font-semibold text-slate-900">{children}</strong>
),
// Links → styled with external indicator
a: ({ href, children }) => (
<a href={href} className="text-teal-600 hover:text-teal-800 underline
decoration-teal-300 hover:decoration-teal-500"
target="_blank" rel="noopener noreferrer">
{children}
</a>
),
// Lists → clean spacing
ul: ({ children }) => (
<ul className="list-disc list-outside ml-6 my-3 space-y-1 text-slate-700">
{children}
</ul>
),
ol: ({ children }) => (
<ol className="list-decimal list-outside ml-6 my-3 space-y-1 text-slate-700">
{children}
</ol>
),
// Horizontal rules → section dividers
hr: () => <hr className="my-6 border-t-2 border-slate-200" />,
// Paragraphs → proper spacing
p: ({ children }) => (
<p className="my-2 leading-relaxed text-slate-700">{children}</p>
),
};
The pipeline skills produce several non-standard formats that need special treatment:
Skills like candidate-ranker and admet-predictor use Unicode box-drawing for scorecards:
═══════════════════════════════════════════════════════════
CANDIDATE: Curcumin
═══════════════════════════════════════════════════════════
Strategy: Detect lines that are predominantly box-drawing characters and render them as styled dividers or card boundaries. Write a preprocessor:
function preprocessSkillOutput(markdown: string): string {
return markdown
// Convert ═══ header lines into markdown horizontal rules
.replace(/^[═]{10,}$/gm, '---')
// Convert ─── subheader lines into thinner dividers
.replace(/^[─]{10,}$/gm, '<hr class="border-t border-slate-300 my-2" />')
// Convert box-drawing tables to GFM tables (complex — see below)
.replace(/^(┌.*┐)$/gm, '') // Strip box top
.replace(/^(└.*┘)$/gm, '') // Strip box bottom
.replace(/^(├.*┤)$/gm, (match) => {
// Convert ├────┼────┤ to GFM table separator |---|---|
return match.replace(/[├┤]/g, '|').replace(/[─]+/g, (m) => '-'.repeat(m.length)).replace(/┼/g, '|');
})
.replace(/│/g, '|'); // Convert │ to | for table cells
}
Skills render progress bars as block characters:
Target Relevance ████████░░ 8/10
Strategy: Detect the pattern and replace with HTML progress bars:
function renderScoreBars(text: string): string {
// Match: label + filled blocks + empty blocks + score
const scorePattern = /^(\s*[\w\s/]+?)\s+(█+)(░+)\s+(\d+)\/(\d+)$/gm;
return text.replace(scorePattern, (_, label, filled, empty, score, max) => {
const pct = (parseInt(score) / parseInt(max)) * 100;
const color = pct >= 70 ? 'bg-emerald-500' : pct >= 40 ? 'bg-amber-500' : 'bg-red-500';
return `<div class="flex items-center gap-3 my-1">
<span class="w-44 text-sm text-slate-600 truncate">${label.trim()}</span>
<div class="flex-1 h-3 bg-slate-200 rounded-full overflow-hidden">
<div class="${color} h-full rounded-full" style="width: ${pct}%"></div>
</div>
<span class="text-sm font-mono font-semibold w-12 text-right">${score}/${max}</span>
</div>`;
});
}
The pathway coverage tables use filled/empty blocks:
│ Curcumin │ ██ │ ██ │ ░░ │ ░░ │ ██ │
Strategy: After converting box-drawing to GFM tables, replace block characters with colored indicators:
function renderCoverageIndicators(html: string): string {
return html
.replace(/██/g, '<span class="inline-block w-4 h-4 bg-teal-500 rounded-sm" title="Covered"></span>')
.replace(/░░/g, '<span class="inline-block w-4 h-4 bg-slate-200 rounded-sm" title="Not covered"></span>');
}
Skills output confidence levels as text. Render as colored badges:
function ConfidenceBadge({ level }: { level: string }) {
const colors = {
high: 'bg-emerald-100 text-emerald-800 border-emerald-300',
moderate: 'bg-amber-100 text-amber-800 border-amber-300',
low: 'bg-red-100 text-red-800 border-red-300',
speculative: 'bg-purple-100 text-purple-800 border-purple-300',
};
const color = colors[level.toLowerCase()] || colors.moderate;
return (
<span className={`inline-block px-2 py-0.5 text-xs font-semibold rounded-full
border ${color} uppercase tracking-wide`}>
{level}
</span>
);
}
Chemical notation should be rendered in monospace and optionally linkable:
// In custom components, detect SMILES-like strings in code spans
code: ({ inline, children }) => {
const text = String(children);
const looksLikeSMILES = /^[A-Za-z0-9@+\-\[\]\(\)\\\/=#$.%]+$/.test(text) && text.length > 10;
if (inline && looksLikeSMILES) {
return (
<code className="bg-indigo-50 text-indigo-700 px-1.5 py-0.5 rounded
text-sm font-mono cursor-help"
title="SMILES notation — molecular structure">
{children}
</code>
);
}
// ... default code rendering
}
The complete pipeline for converting a skill output to a polished web page:
Raw skill output (markdown + box drawing + score bars)
│
▼
preprocessSkillOutput() ── Convert box-drawing to GFM-compatible markdown
│
▼
renderScoreBars() ── Replace █░ patterns with HTML progress bars
│
▼
renderCoverageIndicators() ── Replace ██/░░ with colored coverage dots
│
▼
ReactMarkdown ── Parse markdown to React with custom components
│ (tables, headers, code blocks, blockquotes)
▼
Post-render transforms ── Confidence badges, SMILES detection
│
▼
Styled, interactive report page
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import rehypeRaw from 'rehype-raw';
import rehypeSanitize, { defaultSchema } from 'rehype-sanitize';
// Allow style attributes and custom classes through sanitizer
const sanitizeSchema = {
...defaultSchema,
attributes: {
...defaultSchema.attributes,
'*': [...(defaultSchema.attributes?.['*'] || []), 'className', 'style', 'title'],
div: [...(defaultSchema.attributes?.div || []), 'className', 'style'],
span: [...(defaultSchema.attributes?.span || []), 'className', 'style', 'title'],
},
};
function SkillReportRenderer({ rawOutput }: { rawOutput: string }) {
const processed = renderScoreBars(
renderCoverageIndicators(
preprocessSkillOutput(rawOutput)
)
);
return (
<article className="prose prose-slate max-w-none p-6 bg-white rounded-xl shadow">
<ReactMarkdown
remarkPlugins={[remarkGfm]}
rehypePlugins={[rehypeRaw, [rehypeSanitize, sanitizeSchema]]}
components={customComponents}
>
{processed}
</ReactMarkdown>
</article>
);
}
For rendering regular markdown files (docs, notes, CLAUDE.md), use a simpler pipeline without the skill-specific preprocessors:
function MarkdownPage({ filePath }: { filePath: string }) {
const [content, setContent] = useState('');
useEffect(() => {
fetch(filePath).then(r => r.text()).then(setContent);
}, [filePath]);
return (
<article className="prose prose-slate max-w-4xl mx-auto p-8">
<ReactMarkdown
remarkPlugins={[remarkGfm]}
rehypePlugins={[rehypeRaw, rehypeSanitize]}
components={customComponents}
>
{content}
</ReactMarkdown>
</article>
);
}
SkillReportRenderer in React.memo and memoize the preprocessing chain with useMemo:
const processed = useMemo(() =>
renderScoreBars(renderCoverageIndicators(preprocessSkillOutput(rawOutput))),
[rawOutput]
);
@tanstack/react-virtualAlways test with real skill output. Grab sample outputs by running skills and saving the result:
# Run a skill and capture output to a file
claude -p "/admet-predictor curcumin" > data/reports/test-admet-curcumin.md
Then load that file in the Report Viewer and verify:
cd src/frontend
npm create vite@latest . -- --template react-ts
npm install
npm install tailwindcss @tailwindcss/vite # If using Tailwind
npm install papaparse @types/papaparse # CSV parsing
npm install react-router-dom # Routing
npm install recharts # Charts (or d3 if preferred)
npm install react-markdown remark-gfm # Markdown rendering + GFM tables
npm install rehype-raw rehype-sanitize # Raw HTML support + XSS protection
npm install rehype-highlight # Code block syntax highlighting
npm run dev # Start dev server
npm run dev # Start Vite dev server (usually http://localhost:5173)
npm run build # Production build to dist/
npm run preview # Preview production build locally
data/processed/ and data/reports/. Never write back.node_modules/ or dist/. Ensure .gitignore covers build artifacts.Use the text that follows this command as the specific frontend task, component to build, page to create, or UI question to address: