nsf-budget-justification-udm¶
nsf-budget-justification-udm1.0.01.0.0Tags: nsf budget-justification drafting udm research-administration proposal-preparation
Audience: pre-award-staff, proposal-developers, ingest-pipelines
Manifestations in repo: prompt.md · skill/SKILL.md
Drafts an NSF-format budget justification narrative from a structured budget object. Output is the eight canonical NSF sections (A..H) as an ordered array of section objects — one per section, each with a key, a fixed title, and content in narrative markdown. All eight sections are always emitted; zero-value categories produce a single-sentence content.
Input and output contracts: see schema.json (#/$defs/input and #/$defs/output)
Inputs¶
A JSON object with:
project_title,project_summary— optional context used for phrasing.project_years— integer, the number of project years. All year-indexed arrays in the input have this length.personnel— prime-institution personnel entries.senior: trueroutes to Section A;senior: falseroutes to Section B.budget_summary.categories— annual totals in USD for NSF categoriesAthroughG.indirect_cost— negotiated F&A rate, base description, optional off-campus rate, optional rate-agreement citation and notes (including step changes across project years).- Optional detail:
equipment_items,travel_detail,participant_support_detail,subawards,other_direct_costs_detail.
Subrecipient personnel belong in subawards, not personnel; they appear in the narrative under Section G's Subawards sub-subheading rather than A or B.
Outputs¶
A JSON array of exactly eight objects, in A..H order. Fixed titles (use verbatim — downstream tooling keys on them):
key |
title |
What it covers |
|---|---|---|
A |
Senior Personnel |
Each senior person: role, effort, base salary, escalation, responsibilities |
B |
Other Personnel |
Postdocs, graduate students, undergraduates, hourly staff |
C |
Fringe Benefits |
Rate(s) applied by personnel category, institutional basis |
D |
Equipment |
Items ≥ $5,000 with useful life > 1 year, one per item |
E |
Travel |
Domestic and international purposes, destinations, who travels |
F |
Participant Support Costs |
Stipends, travel, subsistence, fees for non-employee participants |
G |
Other Direct Costs |
Materials, publication, consultant, computer services, subawards, other |
H |
Indirect Costs |
Rate, base, agreement citation, step changes |
Each object carries key, title, and content. content is narrative markdown and may include sub-subheadings (especially in Section G). See schema.json for the authoritative definition.
NSF policy grounding¶
The prompt encodes these NSF rules so the narrative is policy-consistent:
- Senior vs. Other Personnel — Senior = PI, co-PIs, faculty, and others with intellectual direction per PAPPG. Postdocs, graduate students, undergraduates, hourly staff are Other regardless of salary.
- Equipment threshold — Acquisition cost ≥ $5,000 AND useful life > 1 year. Below-threshold items are materials and supplies (Section G).
- Participant support non-substitution — Indirect costs are not charged on Section F, and rebudgeting out of F requires NSF approval. Narrative states this explicitly.
- Subawards under G — Each subrecipient gets a sub-subheading: institution, scope, year-by-year amounts. The justification does not restate MTDC arithmetic.
- Indirect cost narrative — State the rate, base description, agreement citation, and step changes. Do not recompute totals.
First in a family¶
This is the first component in an anticipated family of sponsor-specific budget-justification drafters. Planned siblings (tracked as separate follow-up issues):
nih-budget-justification-udm— NIH modular vs. detailed budget justifications, NIH-specific category treatment.doe-budget-justification-udm— DoE Office of Science / ARPA-E budget justification conventions.- Foundation variants as needed.
The output shape (eight NSF sections) is NSF-specific; siblings define their own sponsor-specific section schemes. The input schema pattern (personnel + per-category per-year totals + indirect cost + optional detail) is likely reusable, and may be factored into a shared $defs file in a future refactor once two or more sibling components exist.
Manifestations¶
prompt.md— canonical, LLM-agnostic promptskill/SKILL.md— Claude Skill form
Schema¶
schema.json is a JSON Schema (draft 2020-12) with two named definitions:
#/$defs/input— validate structured budgets against this before invoking the component#/$defs/output— validate generated narratives against this
Relationship to other components¶
| Component | Role |
|---|---|
sponsor-doc-defaults-udm |
Upstream (indirect): names the budget_justification document as a required NSF deliverable |
solicitation-doc-modifications-udm |
Upstream (indirect): may tighten page limits or require specific subheadings in the justification |
nsf-budget-justification-udm (this) |
Produces the justification narrative from a structured budget |
proposal-completeness-review-udm |
Downstream (future): reviews the produced justification against the merged requirements |
Evals¶
See evals/ for reference inputs and known-good outputs. The initial set covers a realistic multi-year NSF budget that exercises senior personnel, equipment, travel, subawards, and participant support in a single case.
Provenance¶
Designed 2026-04-19 in response to issue #4. The eight-section output shape follows NSF's Chapter II budget-justification convention (A Senior Personnel through H Indirect Costs, omitting the informational totals rows J / K / L / M which do not require narrative justification).
Contract scope¶
-
Output format:
json_array -
Contract scope:
repo_local_sponsor_specific_contract -
Validation surfaces:
json_schema_entrypoints,golden_eval_cases -
Schema entrypoints:
#/$defs/input,#/$defs/output -
Notes: Sponsor-specific repo-local contract. The schema defines both the input budget object and the output eight-section NSF narrative array; it is not a shared UDM schema.
-
Machine-readable catalog entry:
component_catalog.json
Triad integration¶
-
UDM alignment:
repo_local_sponsor_specific_contract— The component can feed UDM-backed proposal workflows, but its section structure is an NSF-specific drafting contract maintained locally here. -
Evaluation datasets: no shared
evaluation-data-setscatalog entry recorded yet; current references are repo-local eval artifacts. -
Harness notes: Validate inputs against #/$defs/input and outputs against #/$defs/output. Current reference coverage is repo-local synthetic eval data rather than a shared evaluation-data-sets entry.
-
Related component:
sponsor-doc-defaults-udm(downstream_of_requirement_discovery) — Sponsor defaults identify budget_justification as a required deliverable. -
Related component:
solicitation-doc-modifications-udm(downstream_of_requirement_overrides) — Solicitation overrides may tighten page limits or add justification-specific instructions.
Prompt body¶
Source: prompt.md.
Show prompt
NSF Budget Justification — UDM¶
Purpose: Draft an NSF-format budget justification from a structured budget object. Output is the eight canonical NSF sections (A..H) as narrative markdown.
Expected input: A JSON object matching
#/$defs/inputinschema.json.Expected output: A JSON array of exactly eight section objects matching
#/$defs/outputinschema.json. No prose, no markdown outside the JSON.
Prompt¶
You are a research-administration drafting engine. Given a structured NSF budget object, produce a budget justification narrative as an ordered array of eight section objects — one per canonical NSF section A through H. Emit all eight, always, in order. When a category has no funds requested in any year, the section's content is a single sentence stating that no funds are requested in that category.
Produce one JSON array matching the output contract — no preamble, no commentary, no markdown outside the JSON. If the runtime requires a fenced block, wrap the array in a single ```json ... ``` block and emit nothing else.
Input¶
A JSON object with these fields (see #/$defs/input in schema.json for the authoritative shape):
-
project_title(optional),project_summary(optional) — context for phrasing. -
project_years— integer, the number of project years. -
personnel— array of personnel entries.senior: trueentries go under Section A;senior: falseentries go under Section B. -
budget_summary.categories— per-category arrays of annual totals (keysAthroughG). -
indirect_cost— negotiated rate(s), base description, and any step-change notes. -
Optional detail fields:
equipment_items,travel_detail,participant_support_detail,subawards,other_direct_costs_detail.
Year-indexed arrays are length-equal to project_years. Index 0 is Year 1.
Output¶
A JSON array of eight objects, in order, each with:
-
key— one of"A".."H". -
title— the NSF section title (see fixed titles below). -
content— the narrative markdown for that section.
The eight sections and fixed titles:
| key | title | Scope |
| --- | --- | --- |
| A | Senior Personnel | Each senior person: role, effort in person-months (or percent), base salary, escalation, and what they will do on the project. |
| B | Other Personnel | Postdocs, graduate students, undergraduates, hourly staff. Same detail shape as A. |
| C | Fringe Benefits | Rate(s) applied by personnel category; cite the institutional rate basis. |
| D | Equipment | Each item ≥ $5,000 with useful life > 1 year: what, when, why, and why existing equipment is insufficient. |
| E | Travel | Domestic and international purposes with destinations, who travels, and what they will do. |
| F | Participant Support Costs | Stipends, travel, subsistence, fees for non-employee participants in training / conference / workshop activities. |
| G | Other Direct Costs | Materials and Supplies, Publication Costs, Consultant Services, Computer Services, Subawards, Other — each as a sub-subheading when present. |
| H | Indirect Costs | Rate(s), base description, rate agreement reference, and any step changes across the project period. |
Use these titles verbatim — downstream tooling keys on them.
NSF policy grounding¶
-
Senior vs. Other Personnel. Senior personnel are those meeting the PAPPG definition (PI, co-PIs, faculty, and others with responsibility for the intellectual direction of the project). Postdocs, graduate students, undergraduates, and hourly staff are Other Personnel regardless of salary level.
-
Equipment threshold. An item is equipment when its acquisition cost is at least $5,000 and its useful life exceeds one year. Items below the threshold are materials and supplies and belong in Section G.
-
Participant Support Costs. Funds for participants (not employees) in connection with training, conferences, or symposia. Indirect costs are not applied to participant support; rebudgeting participant support into other categories requires NSF approval. Narrative should make this non-substitutability explicit.
-
Subawards. Subawards live in Section G (Other Direct Costs) with a sub-subheading for each subrecipient: institution, scope, and amount by year. When a subaward exceeds $25,000 in total, only the first $25,000 is included in the MTDC base for F&A at the prime; the narrative need not restate MTDC arithmetic but should reference the indirect-cost base description.
-
Indirect cost base. State the rate, the base (typically MTDC), and cite the negotiated rate agreement. Note any step changes across project years explicitly.
Per-section expectations¶
Section A — Senior Personnel. For each senior: true personnel entry, write one compact paragraph covering: name (if provided), role, effort (restate the unit and value — e.g., "1.0 academic month and 0.5 summer months"), base Year 1 salary, escalation assumption, and a brief statement of responsibilities drawn from project_summary when available. When multiple senior personnel share a role, a single paragraph listing each is acceptable; prefer one paragraph per person when detail warrants it.
Section B — Other Personnel. For each senior: false entry, a compact paragraph: role, effort (percent appointment is common here), base Year 1 salary, escalation, and a sentence on responsibilities. Graduate students should note whether stipend and tuition are both requested (tuition belongs in Section G under "Other").
Section C — Fringe Benefits. State the institutional fringe rates applied by personnel category (faculty, postdoc, graduate student, undergraduate, hourly). When indirect_cost.notes or similar carries a rate-agreement reference, cite it here too. Do not invent rates the input does not provide — when the input is silent on fringe rates, say "Fringe benefits are charged at institutional rates applicable to each personnel category" and refer the reader to the budget itself for the numeric totals.
Section D — Equipment. When equipment_items is provided, write one paragraph per item using justification_hint as seed material: what the item is, which year it is acquired, the cost, why the item is required for the proposed work, and a sentence explaining why existing departmental or shared-facility equipment is insufficient. When equipment_items is absent but budget_summary.categories.D has non-zero entries, write a single paragraph summarizing the equipment line from the totals and note that item-level detail is unavailable. When all Section D years are zero, emit a single-sentence content: "No equipment is requested."
Section E — Travel. Use travel_detail.domestic_purposes and international_purposes as the narrative spine. When travel_detail is absent, write a short paragraph referencing the year-by-year totals and stating typical purposes (conference dissemination, field work, collaboration meetings) without fabricating specific trips.
Section F — Participant Support Costs. When participant_support_detail is provided, structure the narrative as: the program_purpose (what the participants will do), then a bulleted or tabular breakdown of the line_items (category, count, amount per participant, description). Always include a sentence stating that indirect costs are not charged on participant support and that rebudgeting requires NSF approval. When all Section F years are zero, emit: "No participant support costs are requested."
Section G — Other Direct Costs. Organize content by NSF's G sub-categories using markdown sub-subheadings:
### Materials and Supplies
### Publication Costs
### Consultant Services
### Computer Services
### Subawards
### Other
Include only sub-subheadings that are non-zero or that have input detail. For Subawards, one sub-subheading per entry in subawards, each describing institution, scope, and year-by-year amounts. For each non-subaward sub-category, use other_direct_costs_detail.<field> when provided; otherwise summarize from the G totals and explicitly note that item-level detail was not provided. Tuition remission for graduate students, when budgeted, belongs under a sub-subheading such as "Tuition Remission" (or "Other — Tuition Remission").
Section H — Indirect Costs. State the rate_percent, the base_description, any off_campus_rate_percent, and any rate_agreement_citation. When notes describes a step change (e.g., "rate increases from 52% to 54.5% in Year 3"), include that verbatim from the input. Do not compute indirect-cost totals — the budget itself carries the numbers; the justification's job is to explain which rate applies and why.
Quality standards¶
-
No fabricated numbers. Every dollar figure and percentage in the narrative must trace to the input. When the input omits a detail the narrative needs (a fringe rate, an equipment item description), say so in the narrative and defer to the budget form rather than guessing.
-
Always eight sections, in order. Sections with zero totals still appear, with single-sentence content.
-
Use the fixed titles verbatim — exactly as listed in the table above.
-
Personnel responsibilities grounded in
project_summary. Whenproject_summaryis absent, role-generic phrasing is acceptable; do not invent scope. -
NSF-specific framing. Use NSF's terminology (Modified Total Direct Costs, participant support, senior personnel) rather than generic grant-writing language.
-
Schema conformance. Output validates against
#/$defs/outputinschema.json.
Produce the JSON array now.
Output schema¶
Source: schema.json.
Show schema.json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/AI4RA/prompt-library/components/nsf-budget-justification-udm/schema.json",
"title": "NSF Budget Justification \u2014 UDM Input and Output Contracts",
"description": "Defines both the input (structured NSF budget object) and the output (ordered array of eight section narratives) for the nsf-budget-justification-udm component. Validate input data against #/$defs/input and generated narratives against #/$defs/output.",
"version": "1.0.0",
"$defs": {
"input": {
"type": "object",
"additionalProperties": false,
"required": [
"project_years",
"personnel",
"budget_summary",
"indirect_cost"
],
"properties": {
"project_title": {
"type": [
"string",
"null"
],
"description": "Short title of the proposed project. Optional \u2014 used only for contextual phrasing in the narrative."
},
"project_summary": {
"type": [
"string",
"null"
],
"description": "One-paragraph summary of the proposed work. Optional \u2014 used to ground references to personnel roles and scope."
},
"project_years": {
"type": "integer",
"minimum": 1,
"maximum": 10,
"description": "Number of project years. All year-indexed arrays in this input must have length equal to this value."
},
"personnel": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/personnelEntry"
},
"description": "All prime-institution personnel requested in the budget. Senior personnel (section A) and Other Personnel (section B) are distinguished by the 'senior' flag. Subrecipient personnel belong in 'subawards', not here."
},
"budget_summary": {
"$ref": "#/$defs/budgetSummary"
},
"indirect_cost": {
"$ref": "#/$defs/indirectCost"
},
"equipment_items": {
"type": [
"array",
"null"
],
"items": {
"$ref": "#/$defs/equipmentItem"
},
"description": "Per-item detail for Section D. Null or empty when section D is zero. An item is equipment under NSF when its acquisition cost is at least $5,000 and its useful life exceeds one year."
},
"travel_detail": {
"anyOf": [
{
"$ref": "#/$defs/travelDetail"
},
{
"type": "null"
}
],
"description": "Optional purpose-level detail for Section E. When null, the narrative describes travel in summary terms from the budget_summary line."
},
"participant_support_detail": {
"anyOf": [
{
"$ref": "#/$defs/participantSupportDetail"
},
{
"type": "null"
}
],
"description": "Optional per-line detail for Section F. Null or omitted when section F is zero."
},
"subawards": {
"type": [
"array",
"null"
],
"items": {
"$ref": "#/$defs/subaward"
},
"description": "Subrecipient organizations funded under this proposal. Each subaward's amount_by_year contributes to Section G (Other Direct Costs) in budget_summary."
},
"other_direct_costs_detail": {
"anyOf": [
{
"$ref": "#/$defs/otherDirectCostsDetail"
},
{
"type": "null"
}
],
"description": "Optional per-sub-line detail for Section G (Materials and Supplies, Publication Costs, Consultant Services, Computer Services, Other). Narrative can fall back to the summary line when null."
}
}
},
"output": {
"type": "array",
"minItems": 8,
"maxItems": 8,
"description": "Ordered tuple of the eight canonical NSF budget-justification sections. All eight are always emitted, in A..H order. When a category is zero the corresponding content is a single sentence stating no funds are requested.",
"prefixItems": [
{
"$ref": "#/$defs/sectionA"
},
{
"$ref": "#/$defs/sectionB"
},
{
"$ref": "#/$defs/sectionC"
},
{
"$ref": "#/$defs/sectionD"
},
{
"$ref": "#/$defs/sectionE"
},
{
"$ref": "#/$defs/sectionF"
},
{
"$ref": "#/$defs/sectionG"
},
{
"$ref": "#/$defs/sectionH"
}
],
"items": false
},
"personnelEntry": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"role",
"senior",
"effort",
"base_salary"
],
"properties": {
"name": {
"type": "string",
"minLength": 1,
"description": "Full name, or a placeholder like 'Graduate Student 1' when the person has not been identified."
},
"role": {
"type": "string",
"minLength": 1,
"description": "Role on the project (e.g., 'Principal Investigator', 'Co-PI', 'Postdoctoral Researcher', 'Graduate Student', 'Undergraduate Research Assistant')."
},
"senior": {
"type": "boolean",
"description": "True when the person is reported under NSF Section A (Senior Personnel). False for Section B (Other Personnel \u2014 postdocs, graduate students, undergraduates, hourly staff)."
},
"effort": {
"$ref": "#/$defs/effort"
},
"base_salary": {
"type": "number",
"minimum": 0,
"description": "Annual base salary in Year 1, in USD. For hourly staff, the annualized equivalent."
},
"escalation_percent": {
"type": [
"number",
"null"
],
"minimum": 0,
"description": "Year-over-year salary escalation percent. Null to fall back to the institution's standard assumption (narrative should say 'per institutional escalation')."
},
"funding_source": {
"type": [
"string",
"null"
],
"description": "Free-text note about when the effort is charged (e.g., 'summer months', 'academic year', 'calendar year') when the effort structure does not already make this explicit."
}
}
},
"effort": {
"type": "object",
"additionalProperties": false,
"required": [
"unit",
"value"
],
"properties": {
"unit": {
"enum": [
"academic_months",
"summer_months",
"calendar_months",
"percent"
],
"description": "NSF senior personnel effort is typically reported in person-months (academic, summer, or calendar). Other personnel effort is often stated as a percent appointment."
},
"value": {
"type": "number",
"minimum": 0,
"description": "Numeric effort in the unit given. E.g., 1 academic month, 1 summer month, or 50 percent."
}
}
},
"budgetSummary": {
"type": "object",
"additionalProperties": false,
"required": [
"categories"
],
"properties": {
"categories": {
"type": "object",
"additionalProperties": false,
"required": [
"A",
"B",
"C",
"D",
"E",
"F",
"G"
],
"properties": {
"A": {
"$ref": "#/$defs/yearAmounts",
"description": "Senior Personnel totals by year, in USD."
},
"B": {
"$ref": "#/$defs/yearAmounts",
"description": "Other Personnel totals by year, in USD."
},
"C": {
"$ref": "#/$defs/yearAmounts",
"description": "Fringe Benefits totals by year, in USD."
},
"D": {
"$ref": "#/$defs/yearAmounts",
"description": "Equipment totals by year, in USD."
},
"E": {
"$ref": "#/$defs/yearAmounts",
"description": "Travel totals by year, in USD."
},
"F": {
"$ref": "#/$defs/yearAmounts",
"description": "Participant Support Costs totals by year, in USD."
},
"G": {
"$ref": "#/$defs/yearAmounts",
"description": "Other Direct Costs totals by year, in USD (includes subawards, materials, publication, consultant, computer services, and other per NSF convention)."
}
}
}
}
},
"yearAmounts": {
"type": "array",
"minItems": 1,
"items": {
"type": "number",
"minimum": 0
},
"description": "Amount in USD for each project year. Index 0 is Year 1. Array length must equal project_years."
},
"indirectCost": {
"type": "object",
"additionalProperties": false,
"required": [
"rate_percent",
"base_description"
],
"properties": {
"rate_percent": {
"type": "number",
"minimum": 0,
"description": "Primary negotiated F&A rate as a percentage (e.g., 54.5)."
},
"base_description": {
"type": "string",
"minLength": 1,
"description": "Short description of the base, e.g., 'Modified Total Direct Costs (MTDC) excluding equipment, participant support, and the portion of each subaward in excess of $25,000'."
},
"off_campus_rate_percent": {
"type": [
"number",
"null"
],
"minimum": 0,
"description": "Off-campus rate when a distinct rate applies; null otherwise."
},
"rate_agreement_citation": {
"type": [
"string",
"null"
],
"description": "Short reference to the rate agreement, e.g., 'DHHS-negotiated rate agreement dated 2025-06-01'."
},
"notes": {
"type": [
"string",
"null"
],
"description": "Short notes the narrative should carry (e.g., 'Rate steps from 52% to 54.5% in Year 3 per the current agreement')."
}
}
},
"equipmentItem": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"year",
"amount",
"justification_hint"
],
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"year": {
"type": "integer",
"minimum": 1
},
"amount": {
"type": "number",
"minimum": 5000
},
"justification_hint": {
"type": "string",
"minLength": 1,
"description": "Short phrase the drafter expands into one or two sentences on why the item is required and why existing equipment is insufficient."
}
}
},
"travelDetail": {
"type": "object",
"additionalProperties": false,
"properties": {
"domestic_purposes": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"description": "Short phrases describing the purpose of each domestic trip (e.g., 'PI and one graduate student to attend the annual AGU meeting to present project results')."
},
"international_purposes": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
}
}
},
"participantSupportDetail": {
"type": "object",
"additionalProperties": false,
"required": [
"line_items"
],
"properties": {
"program_purpose": {
"type": [
"string",
"null"
],
"description": "The event or activity the participants take part in (e.g., 'two-week summer research experience for six undergraduate students')."
},
"line_items": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/participantSupportLineItem"
}
}
}
},
"participantSupportLineItem": {
"type": "object",
"additionalProperties": false,
"required": [
"category",
"count",
"amount_per",
"description"
],
"properties": {
"category": {
"enum": [
"stipend",
"travel",
"subsistence",
"fee",
"other"
],
"description": "NSF participant-support categories. 'fee' covers registration or training fees. 'other' should be accompanied by a clear description."
},
"count": {
"type": "integer",
"minimum": 1
},
"amount_per": {
"type": "number",
"minimum": 0
},
"description": {
"type": "string",
"minLength": 1
}
}
},
"subaward": {
"type": "object",
"additionalProperties": false,
"required": [
"institution",
"scope",
"amount_by_year"
],
"properties": {
"institution": {
"type": "string",
"minLength": 1
},
"pi_name": {
"type": [
"string",
"null"
]
},
"scope": {
"type": "string",
"minLength": 1,
"description": "One to two sentences describing the subrecipient's scope of work and why that scope belongs at the subrecipient rather than the prime."
},
"amount_by_year": {
"$ref": "#/$defs/yearAmounts"
}
}
},
"otherDirectCostsDetail": {
"type": "object",
"additionalProperties": false,
"properties": {
"materials_and_supplies": {
"type": [
"string",
"null"
]
},
"publication_costs": {
"type": [
"string",
"null"
]
},
"consultant_services": {
"type": [
"string",
"null"
]
},
"computer_services": {
"type": [
"string",
"null"
]
},
"other": {
"type": [
"string",
"null"
]
}
}
},
"sectionObjectBase": {
"type": "object",
"additionalProperties": false,
"required": [
"key",
"title",
"content"
],
"properties": {
"key": {
"type": "string"
},
"title": {
"type": "string",
"minLength": 1
},
"content": {
"type": "string",
"minLength": 1,
"description": "Narrative markdown. May include subheadings and lists. When the category total is zero in every year, content is a single sentence stating no funds are requested in this category."
}
}
},
"sectionA": {
"allOf": [
{
"$ref": "#/$defs/sectionObjectBase"
},
{
"properties": {
"key": {
"const": "A"
},
"title": {
"const": "Senior Personnel"
}
}
}
]
},
"sectionB": {
"allOf": [
{
"$ref": "#/$defs/sectionObjectBase"
},
{
"properties": {
"key": {
"const": "B"
},
"title": {
"const": "Other Personnel"
}
}
}
]
},
"sectionC": {
"allOf": [
{
"$ref": "#/$defs/sectionObjectBase"
},
{
"properties": {
"key": {
"const": "C"
},
"title": {
"const": "Fringe Benefits"
}
}
}
]
},
"sectionD": {
"allOf": [
{
"$ref": "#/$defs/sectionObjectBase"
},
{
"properties": {
"key": {
"const": "D"
},
"title": {
"const": "Equipment"
}
}
}
]
},
"sectionE": {
"allOf": [
{
"$ref": "#/$defs/sectionObjectBase"
},
{
"properties": {
"key": {
"const": "E"
},
"title": {
"const": "Travel"
}
}
}
]
},
"sectionF": {
"allOf": [
{
"$ref": "#/$defs/sectionObjectBase"
},
{
"properties": {
"key": {
"const": "F"
},
"title": {
"const": "Participant Support Costs"
}
}
}
]
},
"sectionG": {
"allOf": [
{
"$ref": "#/$defs/sectionObjectBase"
},
{
"properties": {
"key": {
"const": "G"
},
"title": {
"const": "Other Direct Costs"
}
}
}
]
},
"sectionH": {
"allOf": [
{
"$ref": "#/$defs/sectionObjectBase"
},
{
"properties": {
"key": {
"const": "H"
},
"title": {
"const": "Indirect Costs"
}
}
}
]
}
}
}
Evals¶
Reference cases¶
Golden cases under evals/cases/.
multi-year-field-science— Three-year NSF field-science proposal with full category coverage (artifacts: input, expected)
Changelog¶
Source: CHANGELOG.md.
All notable changes to this component. Versions follow semver: MAJOR for output-contract breaks (schema changes that drop or rename sections or required fields), MINOR for backward-compatible additions (new optional input detail fields, new manifestations), PATCH for wording or clarity with no behavior change expected.
The schema.json version is kept in lockstep with the component version. The eight-section output shape is NSF-specific; sibling sponsor-specific budget-justification components will ship as separate components with their own schemas.
[1.0.0] — 2026-04-19¶
- Initial version.
- JSON Schema (
schema.json) defining both input and output contracts: #/$defs/input— structured NSF budget object with personnel detail, per-category per-year totals, indirect cost, and optional equipment / travel / participant support / subaward / other-direct-costs detail.#/$defs/output— fixed-length array of eight section objects (A..H) with enforcedkeyandtitlevalues at each position.- Canonical prompt (
prompt.md) encoding NSF policy grounding: senior-vs-other personnel definitions, $5,000 equipment threshold with useful-life > 1 year, participant-support non-substitution rule, subawards-under-Section-G convention, and the indirect-cost narrative scope. - Claude Skill manifestation (
skill/SKILL.md). - One golden eval case (
multi-year-field-science): a three-year NSF proposal exercising senior personnel, other personnel (postdoc + graduate students + undergraduate), an equipment line in Year 1, domestic travel, a three-year REU-style participant-support program, a subaward, and a step-change indirect-cost note.