NOFO Processor Skill (General)
Purpose
This skill enables Claude to create AI-powered grant solicitation analysis tools that extract key information from NOFOs (Notices of Funding Opportunity), RFAs, program announcements, and other funding opportunity documents. The tool generates proposal preparation timelines, flags policy conflicts with institutional requirements, and produces actionable checklists for grants management workflows.
This is a generalized skill designed to work with any research institution. It requires gathering institution-specific rates and policies during setup.
When to Use This Skill
- •User requests a tool to analyze grant solicitations or funding opportunities
- •User needs to extract deadlines, requirements, or budget information from NOFOs
- •User wants to generate proposal preparation timelines
- •User needs to compare sponsor policies against institutional policies
- •User requests a grants management or proposal planning tool
Institution Configuration (Required)
Before building the tool, gather the following information from the user's institution. This data is typically available from the institution's Office of Sponsored Programs, Controller's Office, or Research Administration website.
1. F&A (Indirect Cost) Rates
Prompt the user to provide their institution's federally negotiated F&A rates:
Please provide your institution's current F&A (indirect cost) rates: 1. On-campus Research rate: ___% (base: MTDC/TDC) 2. Off-campus Research rate: ___% (base: MTDC/TDC) 3. Instruction rate: ___% (base: MTDC/TDC) 4. Other Sponsored Activities rate: ___% (base: MTDC/TDC) 5. Industry/Commercial rates (if different): ___% 6. Clinical Trials rate (if applicable): ___% Rate Agreement effective dates: From ___ to ___ Where to find this: - Your institution's Controller's Office or Cost Accounting website - Office of Sponsored Programs rate information page - Search "[Institution Name] F&A rates" or "indirect cost rates"
2. Fringe Benefit Rates
Prompt the user to provide fringe benefit rates by employee category:
Please provide your institution's current fringe benefit rates: Federal/On-Campus Rates: - Faculty: ___% - Staff: ___% - Graduate Students (GSR/GRA): ___% - Postdoctoral Researchers: ___% - Temporary/Hourly: ___% - Student Workers: ___% Non-Federal Rates (if different): [same categories] Effective fiscal year: FY____ Where to find this: - Controller's Office or Budget Office website - Proposal preparation guidelines - Search "[Institution Name] fringe benefit rates"
3. Key Policy Thresholds
Prompt the user for institutional policy thresholds:
Please provide your institution's current policy thresholds: 1. Equipment capitalization threshold: $______ (Items above this are classified as equipment vs. supplies) 2. Subaward F&A threshold: First $______ per subaward included in MTDC (Federal standard is $25,000; some institutions have different rates) 3. Cost sharing policy: [ ] Discouraged unless required [ ] Allowed with approval [ ] Other: _______________ 4. Off-campus rate criteria: When does off-campus F&A rate apply? _______________ Where to find this: - Sponsored Programs policy manual - Proposal preparation guidelines - Federal rate agreement documentation
4. Workflow Stages and Timing
Gather the institution's internal proposal workflow:
Please describe your institution's proposal preparation workflow: Stage 1: _____________ (Days before deadline: ___) Stage 2: _____________ (Days before deadline: ___) Stage 3: _____________ (Days before deadline: ___) [Continue as needed...] Internal submission deadline: ___ days before sponsor deadline Final review/approval: ___ days before sponsor deadline Key milestones: - PI certification required: [ ] Yes [ ] No - Due: ___ days before - Department approval required: [ ] Yes [ ] No - Due: ___ days before - Dean/College approval required: [ ] Yes [ ] No - Due: ___ days before
5. Key Contacts
Gather institutional contacts for the checklist output:
Please provide key contacts for grant submissions: Office of Sponsored Programs: - General email: _______________ - Phone: _______________ - Website: _______________ - NIH-specific contact (if any): _______________ - NSF-specific contact (if any): _______________ Research Compliance: - IRB (Human Subjects): _______________ - IACUC (Animal Research): _______________ - IBC (Biosafety): _______________ - Export Control: _______________ Budget/Rates: - Controller's Office: _______________ - Cost Accounting: _______________ Other relevant offices: _______________
Core Capabilities
1. Dual Input Methods
The tool should support both:
- •PDF Upload: Convert PDF to base64 and send to Claude API for analysis
- •URL Input: Fetch web-based solicitations via web_fetch and analyze content
2. Intelligent Information Extraction
Extract the following structured data from solicitations:
{
"title": "Full title of the solicitation",
"sponsor": "Funding agency name",
"program": "Program or mechanism name",
"deadlines": [
{"type": "Letter of Intent", "date": "YYYY-MM-DD", "notes": "optional notes"},
{"type": "Full Proposal", "date": "YYYY-MM-DD", "notes": "optional notes"}
],
"eligibility": {
"institution_types": ["R1 universities", "non-profits"],
"pi_requirements": "PI eligibility requirements",
"geographic_restrictions": "Any geographic restrictions or none",
"other": "Any other eligibility notes"
},
"budget": {
"max_total": "Maximum total budget",
"max_per_year": "Maximum per year",
"indirect_cost_policy": "F&A policy details",
"cost_sharing_required": "Yes/No and details",
"restrictions": ["Budget restrictions or special rules"]
},
"required_documents": ["List of all required documents and forms"],
"page_limits": [
{"document": "Document name", "limit": "Page limit"}
],
"compliance_requirements": ["IRB", "IACUC", "Data Management Plan"],
"special_requirements": ["Other important requirements"],
"policy_flags": ["Policy conflicts with institutional rates"],
"recommended_resources": ["Recommended contacts and resources"],
"helpful_hints": ["Tips for preparing a strong proposal"]
}
3. Institutional Policy Integration Template
Store the gathered institutional data in a configuration object:
const INSTITUTION_CONFIG = {
name: "Institution Name",
faRates: {
onCampusResearch: { rate: 0.00, base: "MTDC" },
offCampusResearch: { rate: 0.00, base: "MTDC" },
instruction: { rate: 0.00, base: "MTDC" },
otherSponsored: { rate: 0.00, base: "MTDC" },
industryResearch: { rate: 0.00, base: "MTDC" },
clinicalTrials: { rate: 0.00, base: "TDC" },
effectiveDate: "YYYY-MM-DD",
expirationDate: "YYYY-MM-DD"
},
fringeRates: {
faculty: 0.00,
staff: 0.00,
graduateStudents: 0.00,
postdocs: 0.00,
temporary: 0.00,
studentWorkers: 0.00,
fiscalYear: "FY20XX"
},
policies: {
equipmentThreshold: 5000,
subawardMTDCThreshold: 25000,
costSharingPolicy: "Discouraged unless required",
offCampusCriteria: "When rent charged directly to project"
},
workflow: [
{ stage: 1, name: "Initial Notification", daysOffset: 0 },
{ stage: 2, name: "Solicitation Review", daysOffset: -30 },
// ... additional stages
],
contacts: {
osp: { email: "", phone: "", website: "" },
irb: { email: "", website: "" },
iacuc: { email: "", website: "" },
controller: { email: "", website: "" }
}
};
4. Timeline Generation
Generate proposal preparation timelines using business day calculations based on the institution's workflow:
// Business day subtraction function
const subtractBusinessDays = (date, days) => {
const result = new Date(date);
let remaining = Math.abs(days);
const direction = days < 0 ? -1 : 1;
while (remaining > 0) {
result.setDate(result.getDate() + direction);
if (result.getDay() !== 0 && result.getDay() !== 6) {
remaining--;
}
}
return result;
};
// Generate timeline from institution config
const generateTimeline = (deadlineDate, workflowStages) => {
const today = new Date();
today.setHours(0, 0, 0, 0);
const milestones = workflowStages.map(stage => ({
stage: stage.name,
date: subtractBusinessDays(deadlineDate, Math.abs(stage.daysOffset)),
daysOffset: stage.daysOffset
}));
// Filter to show only future milestones
const futureMilestones = milestones.filter(m => m.date >= today);
// Always add "Today" as starting point
return [
{ stage: 'Initial Notification (Today)', date: today, isStart: true },
...futureMilestones
].sort((a, b) => a.date - b.date);
};
Timeline Logic:
- •Calculate dates by subtracting business days (exclude weekends)
- •Show only stages from today forward for compressed timelines
- •Display warnings when timeline is compressed
- •Support multiple deadline selection for sponsors with multiple windows
5. Policy Conflict Detection
Automatically flag when sponsor requirements conflict with institutional policies:
const detectPolicyConflicts = (sponsorPolicy, institutionConfig) => {
const flags = [];
// F&A rate conflicts
if (sponsorPolicy.faCap && sponsorPolicy.faCap < institutionConfig.faRates.onCampusResearch.rate * 100) {
flags.push(`Sponsor caps F&A at ${sponsorPolicy.faCap}% - below institutional rate of ${institutionConfig.faRates.onCampusResearch.rate * 100}%`);
}
// F&A base conflicts
if (sponsorPolicy.faBase && sponsorPolicy.faBase !== institutionConfig.faRates.onCampusResearch.base) {
flags.push(`Sponsor uses ${sponsorPolicy.faBase} base - institutional rate is ${institutionConfig.faRates.onCampusResearch.base}-based`);
}
// Cost sharing conflicts
if (sponsorPolicy.voluntaryCostSharing && institutionConfig.policies.costSharingPolicy.includes("Discouraged")) {
flags.push("Sponsor mentions voluntary cost sharing - check institutional policy before committing");
}
// Equipment threshold conflicts
if (sponsorPolicy.equipmentThreshold && sponsorPolicy.equipmentThreshold !== institutionConfig.policies.equipmentThreshold) {
flags.push(`Sponsor equipment threshold ($${sponsorPolicy.equipmentThreshold}) differs from institutional threshold ($${institutionConfig.policies.equipmentThreshold})`);
}
// Subaward threshold conflicts
if (sponsorPolicy.subawardThreshold && sponsorPolicy.subawardThreshold !== institutionConfig.policies.subawardMTDCThreshold) {
flags.push(`Sponsor subaward F&A threshold differs from institutional policy`);
}
return flags;
};
6. Export Capabilities
Generate exportable checklists including:
- •All deadlines with dates and notes
- •Required documents checklist
- •Compliance requirements
- •Budget considerations with institutional rates
- •Workflow stage checklist
- •Institutional contacts
- •Current rate reference
const generateChecklistText = (data, institutionConfig) => {
let text = `GRANT PROPOSAL CHECKLIST\n`;
text += `${data.title}\n`;
text += `Sponsor: ${data.sponsor}\n`;
text += `Institution: ${institutionConfig.name}\n`;
text += `Generated: ${new Date().toLocaleDateString()}\n`;
text += `\n${'='.repeat(80)}\n\n`;
// Policy Flags
if (data.policy_flags?.length > 0) {
text += `⚠️ POLICY CONSIDERATIONS:\n`;
data.policy_flags.forEach(flag => {
text += ` ! ${flag}\n`;
});
text += `\n`;
}
// Deadlines
text += `DEADLINES:\n`;
data.deadlines.forEach(d => {
text += ` [ ] ${d.type}: ${d.date}${d.notes ? ` (${d.notes})` : ''}\n`;
});
text += `\n`;
// Budget Considerations
text += `BUDGET CONSIDERATIONS:\n`;
text += ` [ ] Review budget maximum: ${data.budget.max_total}\n`;
text += ` [ ] Confirm F&A policy: ${data.budget.indirect_cost_policy}\n`;
text += ` [ ] Cost sharing: ${data.budget.cost_sharing_required}\n`;
text += ` [ ] Verify institutional F&A rate applies (${institutionConfig.faRates.onCampusResearch.rate * 100}% on-campus research)\n`;
text += ` [ ] Use current fringe rates\n`;
text += `\n`;
// Required Documents
text += `REQUIRED DOCUMENTS:\n`;
data.required_documents.forEach(doc => {
text += ` [ ] ${doc}\n`;
});
text += `\n`;
// Compliance
if (data.compliance_requirements?.length > 0) {
text += `COMPLIANCE REQUIREMENTS:\n`;
data.compliance_requirements.forEach(req => {
text += ` [ ] ${req}\n`;
});
text += `\n`;
}
// Workflow Stages
text += `WORKFLOW STAGES:\n`;
institutionConfig.workflow.forEach(stage => {
text += ` [ ] Stage ${stage.stage}: ${stage.name}\n`;
});
text += `\n`;
// Key Contacts
text += `KEY CONTACTS:\n`;
if (institutionConfig.contacts.osp.email) {
text += ` OSP: ${institutionConfig.contacts.osp.email} | ${institutionConfig.contacts.osp.phone}\n`;
}
if (institutionConfig.contacts.irb.website) {
text += ` IRB: ${institutionConfig.contacts.irb.website}\n`;
}
if (institutionConfig.contacts.iacuc.website) {
text += ` IACUC: ${institutionConfig.contacts.iacuc.website}\n`;
}
if (institutionConfig.contacts.controller.website) {
text += ` Controller/Rates: ${institutionConfig.contacts.controller.website}\n`;
}
text += `\n`;
// Current Rates Reference
text += `CURRENT INSTITUTIONAL RATES (${institutionConfig.fringeRates.fiscalYear}):\n`;
text += ` F&A: ${institutionConfig.faRates.onCampusResearch.rate * 100}% on-campus research (${institutionConfig.faRates.onCampusResearch.base})\n`;
text += ` Fringe: Faculty ${institutionConfig.fringeRates.faculty * 100}%, Staff ${institutionConfig.fringeRates.staff * 100}%, GSR ${institutionConfig.fringeRates.graduateStudents * 100}%\n`;
text += ` Equipment threshold: $${institutionConfig.policies.equipmentThreshold.toLocaleString()}\n`;
text += ` Subaward MTDC threshold: First $${institutionConfig.policies.subawardMTDCThreshold.toLocaleString()} per subaward\n`;
return text;
};
Implementation Architecture
React Component Structure
import React, { useState } from 'react';
import { Upload, FileText, Calendar, DollarSign, CheckSquare,
AlertTriangle, Download, Copy, Edit, Settings } from 'lucide-react';
export default function NOFOProcessor() {
const [file, setFile] = useState(null);
const [url, setUrl] = useState('');
const [inputType, setInputType] = useState('pdf');
const [processing, setProcessing] = useState(false);
const [results, setResults] = useState(null);
const [error, setError] = useState(null);
const [editing, setEditing] = useState(false);
const [editedResults, setEditedResults] = useState(null);
const [selectedDeadlineIndex, setSelectedDeadlineIndex] = useState(0);
const [institutionConfig, setInstitutionConfig] = useState(null);
const [showConfigModal, setShowConfigModal] = useState(false);
// ... implementation
}
API Integration Pattern
const analyzeContent = async (type, data, institutionConfig) => {
const analysisPrompt = buildAnalysisPrompt(institutionConfig);
let messageContent;
if (type === 'pdf') {
messageContent = [
{
type: 'document',
source: { type: 'base64', media_type: 'application/pdf', data: data }
},
{ type: 'text', text: analysisPrompt }
];
} else {
messageContent = [
{ type: 'text', text: `Fetch and analyze: ${data}\n\n${analysisPrompt}` }
];
}
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'claude-sonnet-4-20250514',
max_tokens: 4000,
messages: [{ role: 'user', content: messageContent }]
})
});
const responseData = await response.json();
let cleanedText = responseData.content[0].text.trim();
cleanedText = cleanedText.replace(/```json\n?/g, '').replace(/```\n?$/g, '');
return JSON.parse(cleanedText);
};
const buildAnalysisPrompt = (config) => {
return `Analyze this grant solicitation and extract information.
INSTITUTIONAL CONTEXT:
Institution: ${config.name}
Current F&A Rates:
- On-campus Research: ${config.faRates.onCampusResearch.rate * 100}% ${config.faRates.onCampusResearch.base}
- Off-campus: ${config.faRates.offCampusResearch.rate * 100}% ${config.faRates.offCampusResearch.base}
- Instruction: ${config.faRates.instruction.rate * 100}% ${config.faRates.instruction.base}
Fringe Benefit Rates (${config.fringeRates.fiscalYear}):
- Faculty: ${config.fringeRates.faculty * 100}%
- Staff: ${config.fringeRates.staff * 100}%
- Graduate Students: ${config.fringeRates.graduateStudents * 100}%
Key Policies:
- Equipment threshold: $${config.policies.equipmentThreshold}
- Subaward F&A: First $${config.policies.subawardMTDCThreshold} per subaward
- Cost sharing: ${config.policies.costSharingPolicy}
IMPORTANT: Check if sponsor's F&A policy conflicts with institutional rates.
Respond ONLY with valid JSON (no markdown, no preamble):
{
"title": "Full title of the solicitation",
"sponsor": "Funding agency name",
"program": "Program or mechanism name",
"deadlines": [
{"type": "Type", "date": "YYYY-MM-DD", "notes": "optional"}
],
"eligibility": {
"institution_types": [],
"pi_requirements": "",
"geographic_restrictions": "",
"other": ""
},
"budget": {
"max_total": "",
"max_per_year": "",
"indirect_cost_policy": "",
"cost_sharing_required": "",
"restrictions": []
},
"required_documents": [],
"page_limits": [{"document": "", "limit": ""}],
"compliance_requirements": [],
"special_requirements": [],
"policy_flags": [],
"recommended_resources": [],
"helpful_hints": []
}`;
};
PDF Handling
const processPDF = async (file) => {
const base64Data = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result.split(',')[1]);
reader.onerror = reject;
reader.readAsDataURL(file);
});
return analyzeContent('pdf', base64Data, institutionConfig);
};
Clipboard Operations with Fallback
const copyToClipboard = (text) => {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text)
.then(() => alert('Copied!'))
.catch(() => fallbackCopy(text));
} else {
fallbackCopy(text);
}
};
const fallbackCopy = (text) => {
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
};
UI Components
Essential Sections
- •Institution Configuration: Setup modal/section for rates and policies
- •Input Section: Toggle between PDF upload and URL input
- •Processing Indicator: Animated spinner with status message
- •Policy Conflict Warnings: Highlighted alerts at top
- •Visual Timeline: Chronological display of stages with dates
- •Organized Results: Cards for each extraction category
- •Edit Mode: Editable fields for all extracted data
- •Multiple Deadline Selection: Radio buttons for timeline target
- •Export Actions: Copy and Download buttons
Configuration UI Component
const InstitutionConfigModal = ({ config, onSave, onClose }) => (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg p-6 max-w-2xl max-h-[90vh] overflow-y-auto">
<h2 className="text-xl font-bold mb-4">Institution Configuration</h2>
<div className="space-y-4">
<div>
<label className="block font-semibold mb-1">Institution Name</label>
<input type="text" className="w-full border rounded p-2" />
</div>
<div className="border-t pt-4">
<h3 className="font-semibold mb-2">F&A Rates</h3>
{/* Rate input fields */}
</div>
<div className="border-t pt-4">
<h3 className="font-semibold mb-2">Fringe Benefit Rates</h3>
{/* Fringe rate input fields */}
</div>
<div className="border-t pt-4">
<h3 className="font-semibold mb-2">Policy Thresholds</h3>
{/* Policy threshold input fields */}
</div>
<div className="border-t pt-4">
<h3 className="font-semibold mb-2">Key Contacts</h3>
{/* Contact input fields */}
</div>
</div>
<div className="flex justify-end gap-2 mt-6">
<button onClick={onClose} className="px-4 py-2 border rounded">Cancel</button>
<button onClick={onSave} className="px-4 py-2 bg-blue-600 text-white rounded">Save</button>
</div>
</div>
</div>
);
Tailwind CSS Classes
// Warning box for policy conflicts <div className="bg-amber-50 border border-amber-300 rounded-lg p-4"> // Timeline milestone <div className="flex items-center gap-3 p-3 bg-blue-50 rounded-lg"> // Section card <div className="bg-white rounded-lg shadow-lg p-6 mb-6"> // Action button <button className="flex items-center gap-2 bg-indigo-600 text-white py-2 px-4 rounded-lg hover:bg-indigo-700"> // Configuration button <button className="flex items-center gap-2 bg-gray-600 text-white py-2 px-4 rounded-lg hover:bg-gray-700"> <Settings className="w-4 h-4" /> Configure Institution </button>
Finding Institutional Rate Information
Common Sources for F&A Rates
- •Institution's Controller's Office website - Search "[Institution] indirect cost rates" or "F&A rates"
- •Office of Sponsored Programs - Often has proposal preparation guides with current rates
- •Federal Rate Agreement - The actual negotiated agreement document
- •Research Administration website - May have rate sheets or budget preparation tools
Common Sources for Fringe Rates
- •Budget Office - Often publishes annual fringe rate tables
- •HR/Benefits Office - May have rate breakdowns by employee category
- •Proposal Preparation Guidelines - Usually include current fringe rates
- •Controller's Office - Cost accounting section
Common Sources for Policies
- •Sponsored Programs Policy Manual - Comprehensive policy documentation
- •Proposal Preparation Checklist - Institution-specific requirements
- •Pre-Award Handbook - Detailed guidance documents
- •Research Compliance Office - For IRB, IACUC, IBC policies
Federal Defaults (If Institution Rates Unknown)
If institutional rates are not available, these federal defaults can be used as placeholders:
- •Equipment threshold: $5,000 (federal standard, though many institutions use $5,000-$10,000)
- •Subaward MTDC threshold: $25,000 (federal standard)
- •F&A rates vary significantly; 50% is a rough median for research universities
Testing Considerations
- •Test with native digital PDFs (not scanned images)
- •Verify date parsing handles various formats
- •Check timeline generation for edge cases (past deadlines, very short timelines)
- •Validate JSON parsing with various response formats
- •Test clipboard operations across browsers
- •Verify configuration persistence (if using browser storage)
Limitations
- •Cannot read tables in scanned/image-based PDFs
- •Requires publicly accessible URLs for web fetch
- •No persistent storage between sessions (unless implemented)
- •Manual verification always recommended
- •Does not submit proposals or write content
- •Institutional rates must be manually configured
Customization Checklist
When implementing for a specific institution:
- • Gather all F&A rates and effective dates
- • Collect fringe benefit rates by employee category
- • Document equipment capitalization threshold
- • Confirm subaward MTDC threshold
- • Define cost sharing policy
- • Map internal workflow stages and timing
- • Collect key contact information
- • Identify any institution-specific requirements
Version Information
- •Skill Version: 1.0 (General)
- •Last Updated: January 2026
- •Compatibility: Any research institution