agentsclimarketplace

Igce builder cr

Skill 1102tools/federal-contracting-skills/skills/igce-builder-cr

Free Claude Skills for federal contracting: IGCE builders (FFP, T&M, cost-reimbursement), SOW/PWS generator, market research reports, and live API tools for USASpending, GSA CALC+, BLS OEWS, Per Diem, Federal Register, eCFR, Regulations.gov. Built for GS-1102 contract specialists and small businesses.

Install
npx -y skills add 1102tools/federal-contracting-skills --skill igce-builder-cr

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 22 stars22 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Build IGCEs for Cost-Reimbursement (CPFF/CPAF/CPIF) federal contracts using layered cost pool buildup with fee structure analysis. Orchestrates BLS OEWS, GSA CALC+, and GSA Per Diem skills. Supports SOW/PWS decomposition into labor categories and rate validation against CALC+ market data. Trigger for: cost reimbursement IGCE, CPFF estimate, CPAF estimate, CPIF estimate, cost-plus estimate, BAA cost estimate, CR IGCE, cost reimbursement cost estimate, fixed fee estimate, award fee estimate, incentive fee estimate, fee structure analysis. Also trigger for cost pool buildup, fee rate analysis, share ratio, or CR scenario analysis. Do NOT use for FFP contracts or wrap rate buildup (use IGCE Builder FFP). Do NOT use for Labor Hour or T&M (use IGCE Builder LH/T&M). Do NOT use for grant budgets under 2 CFR 200 (use Grant Budget Builder). Requires BLS OEWS API, GSA CALC+ Ceiling Rates API, and GSA Per Diem Rates API skills.

SKILL.md

55.6 KB, as published. Nobody here has run it

IGCE Builder: Cost-Reimbursement (CPFF / CPAF / CPIF)

Overview

This skill produces Independent Government Cost Estimates for cost-reimbursement contracts. CR contracts reimburse the contractor for allowable costs incurred plus a fee. The cost buildup is structurally similar to FFP (layered cost pools: fringe, overhead, G&A), but instead of profit-as-markup, CR contracts use a negotiated fee that varies by subtype. The IGCE estimates what those allowable costs should be and what fee structure is appropriate.

CR contracts are common outcomes from BAAs (FAR 35.016), R&D contracts, and complex requirements where the government assumes cost risk but controls it through auditable cost pools and negotiated fee structures.

Required MCP servers:

  1. bls-oews -- market wage data by occupation and geography. Key tools: get_wage_data, igce_wage_benchmark, list_common_metros, list_common_soc_codes.
  2. gsa-calc -- awarded GSA MAS ceiling hourly rates. Key tools: suggest_contains, exact_search, keyword_search, igce_benchmark, price_reasonableness_check.
  3. gsa-perdiem -- federal CONUS travel lodging and M&IE. Key tools: lookup_city_perdiem, estimate_travel_cost, get_mie_breakdown.

Regulatory basis: FAR 15.402 (cost/pricing data). FAR 15.404-1(a) (cost analysis). FAR 15.404-4 (profit/fee analysis). FAR 16.301 through 16.307 (cost-reimbursement contracts). 10 USC 3322(a) (statutory fee caps).

Operating Principle (ai-boundaries)

This skill assembles data and formats documents from reasoning the contracting officer supplies. It does NOT originate evaluative conclusions. Specifically:

  • The skill pulls BLS wages, CALC+ ceiling rates, and Per Diem rates, and formats them into a workbook.
  • The skill does NOT determine whether a rate is "fair and reasonable" under FAR 15.404-1. That determination is the CO's.
  • The skill does NOT assert premiums (TS/SCI, OCONUS, SCIF, specialty labor) that are outside BLS/CALC+/Per Diem data. If a premium is needed and the data does not support it, the skill names the gap and hands the decision back to the CO.
  • The skill does NOT draft a price reasonableness memo, a responsibility determination, or any FAR-citing signature document unless the CO has already supplied the rationale and conclusion, in which case the skill formats the CO's text into the template.
  • Narrative prose (chat summaries, Methodology sheet, Rate Validation status) avoids evaluative verbs: "defensible," "reasonable," "acceptable," "competitive," "outlier." Replace with neutral positioning: "at P77 of CALC+ pool (n=X)," "within BLS P90 cost-plus-fee equivalent," "above P50 by Y%, document stacked factors in Methodology."

Stacked factors refers to the component sources of a rate premium. Typical examples: metro wage differential, seniority tier premium, clearance requirement premium, lab/SCIF overhead, thin CALC+ corpus (directional only), MAS ceiling vs CR cost-plus-fee separation, BLS vintage aging. Name the specific factors that apply, not the word "stacked" alone.

If you find yourself writing a conclusion about whether a number is right or wrong, stop. Present the data and let the CO conclude.

Pre-flight: MCP dependency check

Runs before Workflow Selection. Required on every skill trigger.

This skill needs three MCP servers: bls-oews, gsa-calc, gsa-perdiem. Do not proceed to any workflow until both checks below pass.

Check 1: MCP presence. Verify all three are available in the current session by looking for one known tool from each:

  • bls-oews (check for mcp__bls-oews__detect_latest_year)
  • gsa-calc (check for mcp__gsa-calc__suggest_contains)
  • gsa-perdiem (check for mcp__gsa-perdiem__get_mie_breakdown)

If any are missing, respond with:

This skill requires the bls-oews, gsa-calc, and gsa-perdiem MCP servers. Missing: [list]. Install and configure them in your MCP client before using this skill.

Check 2: API key presence. Two of the three need API keys. Verify by lightweight ping:

  • mcp__bls-oews__detect_latest_year (needs a BLS API key)
  • mcp__gsa-perdiem__get_mie_breakdown (needs an api.data.gov key)
  • gsa-calc needs no key, skip

If either ping returns an auth error or missing-key error, respond with:

[bls-oews | gsa-perdiem] is installed but its API key is not set. This MCP needs a free API key (BLS for bls-oews, api.data.gov for gsa-perdiem). Register the key with the provider and add it to the MCP's configuration, then restart your MCP client.

Only proceed to Workflow Selection after both checks pass. Do not try to work around missing MCPs by calling APIs directly; the skill relies on MCP-guaranteed behaviors (MSA renumbering lookups, JSON path normalization, first/last day M&IE math).

Workflow Selection

Workflow A: Full CR IGCE Build (Default)

User needs a complete cost-reimbursement estimate. Execute Steps 1 through 9. Triggers: "cost reimbursement IGCE," "CPFF estimate," "CPAF estimate," "CPIF estimate," "cost-plus estimate," "BAA cost estimate."

Workflow A+: SOW/PWS-Driven CR Build

User provides a requirement document instead of structured labor inputs. Execute Step 0 first, validate, then Steps 1-9. Triggers: "build a CR IGCE from this SOW," "price this BAA requirement," or when user provides requirement text and specifies cost-reimbursement.

Detection: If the user mentions a BAA and does not specify contract type, suggest CR as the most likely fit and confirm before proceeding.

Workflow B: CR Rate Positioning (Data Only, No Determination)

User has proposed rates and wants to see where they sit against market data. The skill returns the data and the CO decides reasonableness. The skill does not produce a "fair and reasonable" determination, a signed memo, or advisory text telling the CO how to negotiate.

Triggers: "is this CR rate reasonable," "validate these cost pool rates," "check this cost proposal."

Step 0 / GATE (MANDATORY FIRST — runs before any other Workflow B step).

Before any analysis, scan the user's prompt for these tokens (case-insensitive): "memo", "determination", "fair and reasonable", "price reasonableness", "reasonableness memo", "draft the memo", "for the file", "contract file", "document this", "memorandum".

If ANY of those tokens appear, the ENTIRE first response must be the refusal template below, emitted verbatim. No rate analysis. No CALC+ pull. No BLS pull. No "let me start with the analysis" preamble. No offer to continue with the memo if the user provides more info in the same response. Emit the template. Stop. Wait for the user's explicit choice.

Refusal template (emit verbatim):

I can pull positioning data that shows where each proposed rate sits against CALC+ ceiling rates and BLS market wages. I cannot draft a price reasonableness memo, write a "fair and reasonable" determination, or recommend negotiation positions. Those are Contracting Officer decisions under FAR 15.404-1, not skill outputs.

Tell me which you want:

Option A — Positioning data only. I produce a table: per-LCAT proposed rate, CALC+ P25/P50/P75/P90 with sample size, BLS metro burdened equivalent. No verdict. No recommendation. You draw the conclusion.

Option B — Memo template fill. You provide your rationale (what supports or doesn't support each rate) and your determination (fair and reasonable / not fair and reasonable / declining to determine). I drop your text verbatim into the memo template, add the benchmark tables underneath, mark it DRAFT. I will not originate determinations, recommend negotiation positions, or add hedging language.

Which option?

Proceed to Steps 1-5 only after:

  • User explicitly selects Option A, OR
  • User provides Option B inputs (rationale text + determination text)

Hard prohibitions at ALL times (Option A or Option B):

  • Do NOT write "the rate is fair and reasonable" or "not fair and reasonable" unless quoting the user's Option B text verbatim.
  • Do NOT label rates "competitive," "aggressive," "outlier requiring justification," "premium warrants clarification," or any equivalent evaluative phrase. Use positional language only ("at P77," "above P50 by X%," "below P25").
  • Do NOT recommend negotiation positions, evaluation notices, or counter-offer dollar figures.
  • Do NOT write "Summary of findings" or "Determination" sections that draw conclusions the user has not supplied.

Workflow B steps (run only after Step 0 gate clears):

  1. Collect the vendor's proposed labor categories, fully burdened rates (or cost pool breakdown), and any scope context (metro, fee type, experience tier).

  2. For each LCAT, call mcp__gsa-calc__price_reasonableness_check(labor_category, proposed_rate, experience_min, education_level). The MCP returns count, min/max, median, IQR bounds, z-score, and percentile position. If sample size is below ~25 records, label the pool "directional only, not statistical validation."

  3. For senior LCATs, also run the dual-pool flow (title-match + experience-match) and present both medians side-by-side.

  4. If metro context matters, pull BLS OEWS for that metro via mcp__bls-oews__get_wage_data and present the P50/P75/P90 with the cost pool buildup at default fringe / overhead / G&A rates. This shows how the rate sits against local market labor independent of the CALC+ nationwide pool.

  5. Present a neutral positioning summary using non-evaluative language:

    • "Rate sits at CALC+ P77 (n=7, thin-corpus directional only)."
    • "Above P50 by X%; stacked factors: [metro, seniority tier, aging, cost pool assumption]."
    • "Below P25; pool composition or LCAT alignment may warrant CO review."
    • "CR cost + fee often runs below CALC+ median because CALC+ reflects MAS ceiling (profit embedded) while CR separates cost and fee. CO sets the relevant comparison band."
  6. Stop. Do not write "the rate is fair and reasonable." Do not recommend negotiation positions. Do not suggest "push back only if..." text. Do not label rates "competitive," "aggressive," "outlier requiring justification."

  7. Memo output (Option B path only). If the user selected Option B at the Step 0 gate and supplied rationale + determination text, fill the memo template: benchmark tables from Steps 2-4, the user's rationale text verbatim in the findings section, the user's determination text verbatim in the Determination section. Do NOT paraphrase, do NOT add hedging, do NOT originate any conclusion text. Mark DRAFT. Use [Contracting Officer Name] and [Agency] placeholders. If Option A was selected, skip this step entirely.

Information to Collect

Ask for everything in a single pass. Provide defaults where noted. If any Required Input is ambiguous or missing for Workflow A (e.g., labor count without discipline, location without metro, fee type not specified), use AskUserQuestion to collect before pulling data. Do not guess.

Required Inputs

InputDescriptionExample
Labor categoriesJob titles or SOC codesResearch Scientist, Data Analyst, PM
Performance locationCity/state or metro areaBethesda, MD
StaffingHeadcount per labor category3 researchers, 1 analyst, 1 PM
Hours per yearProductive hours per person (default: 1,880)1,880
Period of performanceBase year + option yearsBase + 2 OYs
Fee typeCPFF, CPAF, or CPIFCPFF
Contract start dateFor wage aging2026-10-01

Optional Inputs (Defaults Applied If Not Provided)

InputDefaultNotes
Fringe rate32%FICA + health + retirement + PTO + workers' comp
Overhead rate80%Applied to labor + fringe
G&A rate12%Applied to subtotal
FCCM rate0%FAR 31.205-10 / CAS 414 Facilities Capital Cost of Money; applied to (Subtotal + G&A) as imputed cost. Default 0%. Populate only when CO supplies rate from contractor CASB Disclosure Statement Form CMF.
CO-supplied DCAA ratesDefaultsOverride rule: If the contracting officer supplies DCAA-audited indirect rates (from an approved Forward Pricing Rate Agreement or a current disclosure statement review), USE THOSE RATES instead of the 32/80/12 defaults. Document the source in Methodology Section 4 ("Cost Pool Basis: CO-supplied DCAA rates per FPRA dated [date]"). Do not revert to defaults when CO-audited rates are available; audited rates are the stronger basis.
Fee percentage (CPFF)8%Fixed fee as % of estimated cost
Base fee (CPAF)3%Minimum fee regardless of performance
Award fee pool (CPAF)7%Max additional fee based on evaluation
Target fee (CPIF)8%Fee at target cost
Share ratio (CPIF)80/20 gov/contractorApplied to over/underruns
Min fee (CPIF)3%Floor on fee
Max fee (CPIF)12%Ceiling on fee
Escalation rate2.5%/yrApplied to labor and travel
Shift coverageBusiness hours (8x5) defaultSpecify 24x7 / 16x7 / 12x5 if applicable; Step 0.5 computes FTE
Travel destinationsNoneCity/state per destination
Travel frequencyNoneTrips/year per destination
Travel durationNoneNights per trip (0 = day trip)
Number of travelersAll staffTravelers per trip
Travel monthsMax monthly rateSpecific months if known
FY for per diemCurrent federal FYCompute at build time (Oct-Sep cycle)
Duty station / originPerformance locationFor City Pair airfare lookup
NAICS codeNoneInclude in output if provided
PSC codeNoneInclude in output if provided
Partial startFull year (12 months)Specify months if base year is partial

Cost Pool Rate Guidance

Provide this when the user is unsure:

ComponentLowMidHighNotes
Fringe25%32%40%Higher for generous benefits, union shops
Overhead60%80%120%Higher for SCIF/cleared, large firms, R&D labs
G&A8%12%18%Higher for large corporate structures
FCCM0%0%0.5%FAR 31.205-10 / CAS 414; most small and mid firms don't book it. Populate only with CO-supplied rate. Layered after G&A, applied to (Subtotal + G&A).

Fee Structure Reference

TypeFAR RefMechanismDefaultWhen Used
CPFF16.306Fixed fee set at award, unchanged by actual costs8%Most common CR. R&D, studies, analysis. Must select form: Completion (d)(1) or Term (d)(2).
CPAF16.305Base fee (0-3%) plus award pool (5-10%) earned on performance3% base + 7% poolPerformance-driven with periodic evaluation
CPIF16.304Target fee adjusted by share ratio; bounded by min/max8% target, 80/20 shareComplex work with cost uncertainty but measurable efficiency

Statutory fee caps: R&D contracts: 15% of estimated cost (10 USC 3322(a)). Non-R&D: no statutory cap but 10% is the practical ceiling per agency policy. BAA R&D awards typically settle in the 6-10% band; statutory caps are ceilings, not targets.

CPFF Completion Form vs Term Form (FAR 16.306(d)(1) and (d)(2)). Every CPFF IGCE must declare the form. The two are materially different contract structures:

  • Completion Form (16.306(d)(1)): scope defined by a definite goal or end product. Contractor must complete and deliver the specified end product before the full fixed fee is earned. Use for CPFF where the deliverable is bounded: a report, a prototype, a validated analytical model, a concluded investigation.
  • Term Form (16.306(d)(2)): scope described in general terms; contractor obligated to devote a specified level of effort over a stated PoP. Fee is earned across the LOE period regardless of technical outcome. Use for CPFF R&D where technical success is uncertain (BAAs, exploratory research, advisory services, studies without a predetermined end state).

Record the form selection in the Stage B parameter collection and print it explicitly in Sheet 6 Methodology. For R&D with uncertain outcome, Term Form is the default. Never cite "FAR 16.306" alone without the (d)(1) or (d)(2) subparagraph.

Constants Reference

ConstantValueSource
Standard work year2,080 hours40 hrs x 52 weeks; converts annual wages to hourly
Default productive hours1,880 hours/year2,080 minus holidays and avg leave
Annual coverage hours (24x7)8,760 hours24 x 365; divide by 2,080 × availability for FTE
BLS wage cap (annual)$239,200May 2024 OEWS reporting ceiling
BLS wage cap (hourly)$115.00May 2024 OEWS reporting ceiling
OEWS data year2024May 2024 estimates
GSA mileage rate$0.70/mileCY2025 GSA POV rate
First/last day M&IE75% of full dayFTR 301-11.101
City Pair fare sourceGSA City Pair Programcpsearch.fas.gsa.gov; use YCA fare

Orchestration Sequence

Step 0: Requirements Decomposition (Workflow A+ Only)

Converts an unstructured SOW/PWS into structured pricing inputs.

Process:

  1. Sufficiency check. Scan for six priceable elements: labor categories, staffing levels, performance location, period of performance, deliverables, and travel. Flag anything missing. Hard stop if performance location is absent. If 3+ elements missing and document under 500 words, ask user whether to proceed with assumptions or get clarification.

  2. Task decomposition. Parse into discrete task areas with description, skill discipline, complexity, and recurring vs. finite classification.

  3. Domain triage. Identify agency domain (DoD / IC / DOE / civilian IT / research / medical) BEFORE SOC mapping. Domain signals which SOC block applies: DOE → 17-2xxx physical engineering; IC/DoD cyber → 15-1212; civilian IT → 15-125x software/systems; research → 19-1xxx / 15-2xxx; medical → 29-xxxx.

  4. Labor category mapping. Map tasks to SOC codes using Step 1 heuristics with domain triage result. When a task spans disciplines, map to multiple categories.

  5. Staffing estimation. Estimate FTEs per category based on scope indicators. If 24x7 coverage is required, invoke Step 0.5. Present as ranges when ambiguous.

  6. Present decomposition table for user validation.

  7. User validation gate (CRITICAL) - two stages, not one. Skip Stage A/B gate when user provides structured inputs: LCATs with discipline, location with metro, FTE counts, and PoP all specified. If any of those four are ambiguous or missing, run the gate. Do not conflate "confirm the decomposition" with "pick build parameters." Run them separately:

    Stage A - Decomposition validation. After presenting the decomposition table, ask the user to confirm or amend it. Use AskUserQuestion with options like "Decomposition looks right, proceed" / "Modify LCAT X" / "Add LCAT Y" / "Adjust FTE estimates." Response MUST END after this question. Wait for explicit confirmation before continuing.

    Stage B - Build parameters. Only after the decomposition is confirmed, ask the remaining parameter questions in a separate AskUserQuestion call: fee type ("Cost-reimbursement contracts require a fee structure. Based on [rationale], I recommend CPFF. Should I proceed with CPFF, or do you need CPAF or CPIF?"), if CPFF selected, also ask Completion Form (FAR 16.306(d)(1)) vs Term Form (FAR 16.306(d)(2)) with a decision heuristic: "Is the scope defined by a completable deliverable (end item, final report concluding a specific investigation) or by a level of effort over time (research program, exploratory R&D, advisory services)?" For R&D with uncertain outcome, Term Form is the default. Then: cost pool rates (note whether user has CO-supplied DCAA rates), FCCM rate if applicable, metro confirmation, contract start, NAICS/PSC, shift coverage density if 24x7, and any pass-through ODCs that should NOT bear fee (software licenses, GFE-equivalent hardware). Response MUST END after this question.

    DO NOT self-approve either stage. DO NOT skip Stage A to go straight to parameters. Proceeding to Step 1+ before Stage B is also answered is a skill violation. The user must affirmatively validate BOTH the decomposition and the parameters before build work begins.

Step 0.5: Shift Coverage Staffing (If 24x7 or Multi-Shift)

If the requirement specifies 24x7 coverage, around-the-clock SOC, NOSC, help desk, or continuous monitoring, headcount must be grossed up from productive hours to coverage hours.

Single-seat 24x7 (one analyst always on duty): 4.2 FTE.

Derivation: one shift covers 2,080 hrs/yr at ~95% availability. Four shifts cover 8,760 annual hours with 50% blended availability (leave, training, overlap, turnover). Industry convention.

annual_coverage_hours = 24 * 365 = 8,760
productive_hours_per_fte = 2,080
single_seat_fte = 4.2 FTE   # industry convention

Double-seat 24x7 (two analysts always on duty): 8.4 FTE.

12x5 coverage (business hours, weekdays only): 60 hrs/wk × 52 = 3,120 annual hrs. 3,120 / 1,880 = 1.66 FTE single-seat, ~2 FTE with overlap.

16x7 coverage (extended hours, every day): 16 × 365 = 5,840 annual hrs. 5,840 / 1,880 × availability = ~3.1 FTE single-seat.

Document the FTE math in Sheet 6 Methodology. Do NOT quietly use 3 FTE for 24x7 coverage: that understaffs by 28%.

Step 1: Map Labor Categories to SOC Codes

Map user job titles to SOC codes. Apply domain triage from Step 0 first.

IT and Professional Services (most common):

Common TitleSOC CodeBLS Title
Program Manager (general ops)11-1021General and Operations Managers
Program Manager (IT)11-3021Computer and Information Systems Managers
Program Manager (engineering)11-9041Architectural and Engineering Managers
Project Manager13-1082Project Management Specialists
Management Analyst13-1111Management Analysts
Systems Engineer / Analyst (IT)15-1211Computer Systems Analysts
Software Developer15-1252Software Developers
Cybersecurity / InfoSec15-1212Information Security Analysts
Network Architect15-1241Computer Network Architects
DBA15-1242Database Administrators
Sysadmin15-1244Network and Computer Systems Administrators
QA Tester15-1253Software QA Analysts and Testers
Help Desk15-1232Computer User Support Specialists
Data Scientist15-2051Data Scientists
Technical Writer27-3042Technical Writers

Physical / DOE / Defense Engineering (use these for hardware, labs, weapons systems, DOE M&O, physical infrastructure):

Common TitleSOC CodeBLS Title
Aerospace Engineer17-2011Aerospace Engineers
Biomedical Engineer17-2031Biomedical Engineers
Chemical Engineer17-2041Chemical Engineers
Civil Engineer17-2051Civil Engineers
Electrical Engineer17-2071Electrical Engineers
Electronics Engineer17-2072Electronics Engineers, Except Computer
Environmental Engineer17-2081Environmental Engineers
Industrial Engineer17-2112Industrial Engineers
Mechanical Engineer17-2141Mechanical Engineers
Nuclear Engineer17-2161Nuclear Engineers
Petroleum Engineer17-2171Petroleum Engineers
Engineers, All Other (fallback)17-2199Engineers, All Other

Use 17-2199 when the role doesn't cleanly fit one engineering discipline (RF, antenna, radar, systems integration specialties). Pull alongside a specific engineering SOC for comparison.

Research / Science (BAAs, R&D contracts):

Common TitleSOC CodeBLS Title
Research Scientist (life sci)19-1099Life Scientists, All Other
Biochemist / Biophysicist19-1021Biochemists and Biophysicists
Microbiologist19-1022Microbiologists
Epidemiologist19-1041Epidemiologists
Medical Scientist (PhD biomedical, NIH/pharma)19-1042Medical Scientists, Except Epidemiologists
Physicist19-2012Physicists
Chemist19-2031Chemists
Statistician15-2041Statisticians
Mathematician15-2021Mathematicians

When mapping is ambiguous, query multiple SOC codes and present the range. PM mapping is context-dependent: do NOT default to 11-3021 for non-IT programs.

Step 2: Pull BLS Wage Data

Use the BLS OEWS API skill. For each labor category, query datatypes 04 (annual mean), 11-15 (10th through 90th percentiles) at the performance location.

BLS series ID component breakdown (25 chars total):

prefix(4) + area(7) + industry(6) + SOC(6) + datatype(2) = 25
OEU  M  +  0047900 +  000000  +  151212 +  13  = OEUM004790000000015121213
  • Prefix OEUM = metro; OEUS = state; OEUN = national
  • Area must be 7 chars (pad with leading zeros)
  • SOC must be exactly 6 chars (no trailing zeros: 151212 not 15121200)
  • Industry 000000 for cross-industry

Use metro-level prefix (OEUM) when available. Fall back to state (OEUS), then national (OEUN). Present the full wage distribution. If the target metro is not in list_common_metros, resolve the MSA code via https://www.bls.gov/oes/current/msa_def.htm and pass the 7-char code directly to get_wage_data. Do not fall back to state-level wages without first checking the MSA directory.

Seniority modeling via percentiles: When an LCAT is explicitly Junior / Mid / Senior, map to wage percentiles rather than pulling three separate SOCs:

  • Junior → P25 (datatype 12)
  • Mid → P50 median (datatype 13)
  • Senior → P75 (datatype 14)

Pull all 5 percentiles (P10/P25/P50/P75/P90) for any multi-level LCAT. Cite which percentile was used per LCAT in methodology.

Silent-wrong-answer traps:

  • MSA renumbering (2024 OMB Bulletin 23-01). If a metro query returns NO_DATA across EVERY SOC (not just one), the metro was renumbered, not suppressed. Cleveland moved from 17460 to 17410. Dayton may also have moved. Verify against the current BLS MSA list: https://www.bls.gov/oes/current/oessrci.htm. Do NOT fall back to state assuming occupation suppression until you've checked the code.
  • Wrong trailing zeros. 151212 is the 6-char SOC. 15121200 is a Standard SOC 8-digit format that will fail the 25-char series ID assertion AFTER several queries have already constructed.

If BLS returns "-" with footnote code 5, the wage exceeds the $239,200 cap. Use the cap as a lower bound and flag in the narrative. If the chosen percentile lands within 10% of the cap (≥ $215,280 annual / ≥ $103.50 hourly), note in Methodology that the local market may exceed the stated value and flag for CO review.

BLS flat-tail detection. If P75 equals P90 in the BLS return AND neither hits the $239,200 cap, the local top-tail is sample-constrained (single dominant employer, thin high-end pool). Flag in Methodology: "Local P75/P90 collapsed; top-tail data sparse, local market may run higher than stated."

Step 2B: Age BLS Wages to Contract Start Date

BLS OEWS data has a ~2-year lag (May 2024 estimates released April 2025). If the contract Period of Performance starts after the data reference period, the base wages must be aged forward to avoid understating costs.

months_gap = months between BLS data vintage (May 2024) and contract PoP start date
aging_factor = (1 + escalation_rate) ^ (months_gap / 12)
aged_annual_wage = annual_median * aging_factor

Example: if the contract start is 29 months after the BLS data vintage, at 2.5% escalation the aging_factor = 1.025^(29/12) = ~1.061. A $100,000 BLS median becomes $106,100 before cost pool buildup.

Aging factor must be a cell-referenced formula in the workbook, NOT hardcoded. Use the assumption block rows to hold BLS_vintage, contract_start, months_gap, and aging_factor. If the user changes the contract start assumption, the whole sheet must recompute correctly. See Step 8 assumption block layout.

Use the aged wage as the basis for all subsequent calculations. Document the aging adjustment in the Methodology sheet: "BLS OEWS wages (data vintage: [BLS_vintage]) aged forward [X] months to [contract start] at [escalation rate]%/yr to account for data lag."

If the user does not provide a contract start date, ask for one. If unknown, default to 6 months from today and note the assumption.

The escalation applied in Step 7 across option years starts AFTER this aging adjustment. Step 2B ages the base wage to the contract start; Step 7 escalates from that adjusted base across the period of performance. These are not double-counted.

Step 3: Cost Pool Buildup

Build the estimated cost layer by layer for each labor category:

1. Direct Labor Rate    = aged_annual_wage / 2080
2. Fringe               = Direct Labor * fringe_rate
3. Labor + Fringe       = Direct Labor + Fringe
4. Overhead             = Labor_Fringe * overhead_rate
5. Subtotal             = Labor_Fringe + Overhead
6. G&A                  = Subtotal * ga_rate
7. FCCM (optional)      = (Subtotal + G&A) * fccm_rate      # FAR 31.205-10, CAS 414; default 0%
8. Total Estimated Cost = Subtotal + G&A + FCCM

Fee-Bearing Cost vs Non-Fee Cost (CRITICAL for CR fee math). Fee on cost-reimbursement contracts applies only to cost elements the contractor is executing with their own staff and management. Pass-through ODCs (software licenses, third-party hardware reimbursed at cost, GFE-equivalent material, travel at government rates) typically do NOT bear fee:

Fee-Bearing Cost = Labor + Fringe + Overhead + G&A + FCCM + Travel    # contractor execution
Non-Fee Cost     = Pass-through ODCs, licenses, hardware at cost
Total Estimated Cost = Fee-Bearing Cost + Non-Fee Cost

Fee                    = Fee-Bearing Cost * fee_rate    # NOT Total Cost * fee_rate
Total Estimated Price  = Total Estimated Cost + Fee

Applying fee to Total Estimated Cost including pass-through ODCs silently over-fees the contract. Sheet 1 Summary MUST label the two cost pools separately and compute fee only on Fee-Bearing. If the user intends an ODC to bear fee (contractor-developed deliverable, for example), they can move it to the Fee-Bearing block explicitly with a methodology note.

Fee calculation by type below. Replace total_estimated_cost with fee_bearing_cost in every fee formula.

CPFF fee:

fixed_fee = total_estimated_cost * cpff_fee_rate
total_price = total_estimated_cost + fixed_fee

Fee is fixed at award. Does not change with actual costs.

CPAF fee:

base_fee = total_estimated_cost * cpaf_base_rate
award_fee_pool = total_estimated_cost * cpaf_pool_rate
estimated_fee = base_fee + (award_fee_pool * 0.85)   # assume 85% earned
total_price = total_estimated_cost + estimated_fee

For IGCE purposes, assume 85% of award fee pool earned (common convention). Note in methodology. Show 3 fee scenarios in the Summary or Scenario sheet, not just target: (1) Base only, 3% (worst earned), (2) Base + assumed earned pool, 3% + 7%×85% = 8.95% (target), (3) Base + full pool, 3% + 7% = 10% (ceiling). Single-point 85%-earned hides the range from the CO.

CPIF fee:

target_cost = total_estimated_cost
target_fee = target_cost * cpif_target_rate

# At target cost
fee_at_target = target_fee

# 10% overrun scenario
overrun_cost = target_cost * 1.10
fee_at_overrun = target_fee - (overrun_cost - target_cost) * contractor_share_over
fee_at_overrun = max(fee_at_overrun, target_cost * cpif_min_fee)

# 10% underrun scenario
underrun_cost = target_cost * 0.90
fee_at_underrun = target_fee + (target_cost - underrun_cost) * contractor_share_under
fee_at_underrun = min(fee_at_underrun, target_cost * cpif_max_fee)

Real CPIF agreements often asymmetric (e.g., 80/20 over, 50/50 under). Expose both share directions separately in the assumption block: contractor_share_over and contractor_share_under as two variables, not a single share_ratio. Run ±10% variance for baseline. Also run ±25% or variance wide enough that fee_at_overrun hits the min bound or fee_at_underrun hits the max bound. Document bound-crossings explicitly in Methodology so the CO sees when share ratio stops applying.

Three-scenario approach: Vary each cost pool component:

ComponentLowMidHigh
Fringe25%32%40%
Overhead60%80%120%
G&A8%12%18%

Fee is calculated on each scenario's total cost. For CPIF, this produces a 3x3 matrix: 3 cost scenarios x 3 fee outcomes (underrun/target/overrun).

Step 4: Cross-Reference Against CALC+

Use the GSA CALC+ Ceiling Rates API skill.

CRITICAL: Use the correct query signature or you will get silent wrong answers.

Endpoint: https://calc.gsa.gov/api/v3/api/ceilingrates/ Parameter: keyword= (NOT q=; q= returns the full 265K-record corpus silently) Default for Workflow A rate validation: use mcp__gsa-calc__igce_benchmark. Call keyword_search only when you need the example-rate or labor-category buckets. igce_benchmark returns trimmed stats (count, min/max/mean, P10-P90) without the 50KB+ labor_category/current_price aggregation buckets that blow up response size. page_size=0 is no longer accepted by the MCP. Use page_size=1 minimum when aggregation stats are needed; prefer mcp__gsa-calc__igce_benchmark for stats-only access (no corpus, trimmed return shape).

Match the vendor's tier in the keyword, not the aggregate title. For 'Mid Software Developer' query Software Developer II not Software Developer — the aggregate pool mixes interns through Senior levels and can falsely flag rates as +70% divergent when the tier-matched pool is +11%.

Example:

GET https://calc.gsa.gov/api/v3/api/ceilingrates/?keyword=Research+Scientist&page_size=1

CRITICAL JSON paths:

aggs = response_json["aggregations"]
count    = aggs["wage_stats"]["count"]
min_rate = aggs["wage_stats"]["min"]
max_rate = aggs["wage_stats"]["max"]
avg_rate = aggs["wage_stats"]["avg"]
median   = aggs["histogram_percentiles"]["values"]["50.0"]   # CORRECT median
p25      = aggs["histogram_percentiles"]["values"]["25.0"]
p75      = aggs["histogram_percentiles"]["values"]["75.0"]

WARNING: Do NOT read wage_stats or histogram_percentiles from the top level. They live under aggregations.*. Do NOT read from wage_percentiles (empty when page_size=1). Always use histogram_percentiles.

Dual-pool analysis for senior LCATs: When title-match alone returns N<10, add a second query with experience-anchored keyword:

  • Pool A (title-match): keyword=Senior+Research+Scientist
  • Pool B (experience-match): keyword=Research+Scientist+10+years

Report both counts and medians. Use Pool A primary if N≥10; otherwise blend or cite Pool B as sanity layer.

Rate validation band for CR (burdened cost + fee vs CALC+ median):

DivergenceInterpretationAction
0 to ±10%Expected rangeAccept without explanation
±10 to ±25%Cite fee structure or cost pool varianceDocument in narrative
> ±25%Position outside ±25% band; document stacked factors in MethodologyFlag in Status column

CR burdened rates often diverge from CALC+ more than LH/TM because CALC+ reflects MAS ceiling rates (which include contractor profit), while CR has separate cost + fee. A CR cost + fee slightly below CALC+ median is normal. Far above CALC+ median suggests inflated cost pools.

Step 5: Pull Per Diem Rates (If Travel Required)

Use the GSA Per Diem Rates API skill. Query monthly lodging and M&IE for each destination.

Installation → GSA locality crosswalk. GSA keys per diem by civilian locality, not by military installation or research lab. Looking up "Fort Meade" or "Pentagon" directly returns empty. Translate the installation to its GSA locality BEFORE calling the MCP:

DoD installationGSA localityMetro
Fort Meade, MDAnnapolis / Anne Arundel County, MDBaltimore
Fort Belvoir, VAFairfax / Alexandria, VADC
Pentagon, VAArlington, VA (use DC rate)DC
Joint Base Andrews, MDDistrict of ColumbiaDC
NSA Bethesda / Walter Reed, MDDistrict of Columbia (composite)DC
Fort Liberty (Bragg), NCFayetteville, NCFayetteville
Peterson SFB / Schriever SFB / Fort Carson, COColorado Springs, COColorado Springs
Wright-Patterson AFB, OHDayton, OHDayton
Eglin AFB, FLFort Walton Beach, FLPensacola-Crestview
JB San Antonio / Randolph / Lackland, TXSan Antonio, TXSan Antonio
Hanscom AFB, MABedford / Boston, MABoston
Redstone Arsenal, ALHuntsville, ALHuntsville
Offutt AFB, NEOmaha / Bellevue, NEOmaha
Cape Canaveral / Patrick SFB, FLCocoa Beach / Cape Canaveral, FLPalm Bay-Melbourne
JB Lewis-McChord, WATacoma / Pierce County, WASeattle-Tacoma
Oak Ridge National Lab / Y-12, TNKnoxville, TNKnoxville
Los Alamos National Lab, NMSanta Fe / Los Alamos County, NMSanta Fe
Hanford / PNNL, WARichland, WAKennewick-Richland
Sandia National Labs, NMAlbuquerque, NMAlbuquerque
Lawrence Livermore National Lab, CALivermore / Oakland, CAOakland-Fremont
Idaho National Lab, IDIdaho Falls, IDIdaho Falls
White Sands Missile Range, NMLas Cruces, NMEl Paso
NAWS China Lake, CARidgecrest / Kern County, CABakersfield
Edwards AFB, CALancaster / Palmdale, CALos Angeles
Dugway Proving Ground, UTSalt Lake City metro (std rate)Salt Lake City
Nellis AFB / Creech AFB, NVLas Vegas, NVLas Vegas
Point Mugu / NBVC, CAOxnard / Ventura County, CAOxnard

If the installation is not on this list, query mcp__gsa-perdiem__lookup_city_perdiem with the nearest civilian city and cross-check the result's county field.

Same-metro TDY proximity check. If performance_location MSA equals travel_destination MSA (same metro, <50 mi), overnight lodging per diem may not qualify under FTR 301-7.103. Flag in Methodology: "Same-MSA travel; if this is not overnight TDY, zero the lodging line and use mileage only."

City Pair airfare (optional): When origin and destination known, look up YCA fares at cpsearch.fas.gsa.gov. Skip if origin unknown, OCONUS, local travel, or user provides own airfare.

Per-trip cost by trip length:

Standard multi-night trip (2+ nights):

lodging_per_trip = nightly_rate * nights
travel_days = nights + 1
full_day_mie = mie_rate * max(0, travel_days - 2)
partial_day_mie = mie_rate * 0.75 * 2
mie_per_trip = full_day_mie + partial_day_mie
trip_total = lodging_per_trip + mie_per_trip

1-night trip:

lodging_per_trip = nightly_rate * 1
mie_per_trip = mie_rate * 0.75 * 2   # both days partial
trip_total = lodging_per_trip + mie_per_trip

0-night day trip (same-day return):

lodging_per_trip = 0                 # no overnight stay
mie_per_trip = mie_rate * 0.75       # single partial day only
trip_total = mie_per_trip

The MCP mcp__gsa-perdiem__get_mie_breakdown returns mie_first_last_day already discounted to 75%. Use that value directly. Do NOT multiply by 0.75 again or you ship 25% low M&IE on day trips. Formula on MCP output: mie_per_trip = mie_first_last_day for 0-night trips.

annual_travel = trip_total * trips_per_year * travelers

If the contract PoP start is within 6 months of the next federal fiscal year, query both FYs; if the target FY is not yet published (FY{N+1} publishes mid-August {N}), use current FY as conservative baseline and note in methodology: 'refresh on FY{N+1} publication.'

No travel case: When no travel, include the sheet with a single 'Travel Not Applicable' text block. Do not skip the sheet — Sheet 1 Travel row still needs a cell reference target. Sheet 1 Travel row = 0 literal.

Step 6: Handle Multi-Location Weighting

Option A (default blend): Use highest median across locations per category. Use when user does not specify per-location headcount.

Option B (weighted): weighted_wage = (wage_A * pct_A) + (wage_B * pct_B). Use when user provides split percentages.

Option C (separate lines, DEFAULT when headcount per location is explicit): Dedicated staff per location get separate rows. Do NOT prompt for Option A/B/C when user gave headcount like "3 FTE at Bethesda, 2 FTE at San Diego": go straight to Option C.

Step 7: Calculate Estimated Costs by Period and Apply Escalation

Per-period calculation:

period_labor_cost = sum(burdened_rate * productive_hours * headcount) per category
period_travel = travel costs from Step 5
period_total_cost = period_labor_cost + period_travel
period_fee = period_total_cost * fee_rate (varies by CR subtype)
period_total_price = period_total_cost + period_fee

Partial-year proration:

prorated_hours = productive_hours * (months_in_period / 12)
prorated_travel = annual_travel * (months_in_period / 12)

Escalation across option years: year_N_cost = base_year_cost * (1 + escalation_rate) ^ N

Escalation applies to labor and travel. Fee rate stays constant as a percentage; dollar fee grows with escalated cost.

Three-scenario math: Vary cost pool components (fringe/overhead/G&A) at low/mid/high. Fee calculated on each scenario's total cost.

For CPIF, each cost scenario shows three fee outcomes (underrun/target/overrun), producing a 3x3 matrix:

              | Low Cost  | Mid Cost  | High Cost
Underrun Fee  | $X        | $X        | $X
Target Fee    | $X        | $X        | $X
Overrun Fee   | $X        | $X        | $X

Travel is identical across all scenarios.

Step 8: Produce the CR IGCE Workbook

Generate a multi-sheet .xlsx workbook using openpyxl. Use Excel formulas for all calculations. Run recalc script (python /mnt/skills/public/xlsx/scripts/recalc.py <file>) before presenting.

Environment-specific recalc handling:

  • claude.ai web chat: rerun python /mnt/skills/public/xlsx/scripts/recalc.py <file>.
  • Claude Code CLI (no LibreOffice): the recalc script is unavailable. Instead, compute the expected grand total in Python against the raw inputs and cost pool buildup:
expected = sum(
    total_price_per_fte * fte * scenario_months / 12
    for lcat in lcats
    for total_price_per_fte in [lcat.total_estimated_price_annual_per_fte]
)

Verify the computed total lands within 1% of your Python-side expected total. If yes, dimensional correctness is confirmed; Excel/Numbers will recalculate cell formulas on open. If no, the aging-factor cross-reference or cost-pool block-indexing shift is likely the cause.

  • macOS Claude Desktop with Numbers installed: Numbers auto-recalculates on file open; no script needed.

Workbook structure (7 sheets, or 6 if no travel):

Sheet 1: IGCE Summary. Labor categories as rows, periods as columns. Shows Total Estimated Cost, Fee (labeled by type: "Fixed Fee," "Estimated Award Fee," or "Target Fee"), and Total Estimated Price. Travel rows below labor. Placeholder rows for Airfare, Ground Transportation, ODCs as numeric 0 (NOT text "TBD") to prevent #VALUE! errors in SUM formulas. Grand total with SUM formulas.

Assumption cell layout (Sheet 1, rows 1-13):

A1: "IGCE Assumptions (Cost-Reimbursement)"   (bold, merged A1:B1)
A2: "Fringe Rate"                              B2: 0.32     (blue, pct)
A3: "Overhead Rate"                            B3: 0.80     (blue, pct)
A4: "G&A Rate"                                 B4: 0.12     (blue, pct)
A5: "Fee Type"                                 B5: "CPFF"   (blue)
A6: "Fee Rate"                                 B6: 0.08     (blue, pct)
A7: "Escalation Rate"                          B7: 0.025    (blue, pct)
A8: "Productive Hours/Year"                    B8: 1880     (blue)
A9: "Base Year Months"                         B9: 12       (blue; <12 for partial)
A10: "BLS Vintage"                             B10: =DATE(2024,5,1)          (blue, real date)
A11: "Contract Start"                          B11: =DATE(2026,10,1)         (blue, real date, user-editable)
A12: "Months Gap"                              B12: =DATEDIF(B10,B11,"m")    (formula)
A13: "Aging Factor"                            B13: =(1+B7)^(B12/12)         (formula)
A14: (blank row separator)
A15: header row for data table

For CPAF: replace B6 with "Base Fee Rate" and add separate rows for Award Fee Pool Rate (0.07) and Assumed Earned % (0.85). For CPIF: replace B6 with "Target Fee Rate" and add rows for Share Ratio (Over), Share Ratio (Under), Min Fee, Max Fee.

Sheet 2: Cost Buildup. One block per labor category showing BLS base through Total Price. Block size varies by fee type: CPFF = 20 rows, CPAF = 22 rows (adds Base Fee Rate + Award Pool Rate + Assumed Earned %), CPIF = 24 rows (adds Target Fee Rate + Share Ratio Over + Share Ratio Under + Min Fee + Max Fee). Block N starts at row 1 + (N-1) × block_size. Assumption block row ranges: CPFF rows 2-14, CPAF rows 2-16, CPIF rows 2-18.

Block layout formula: row(N) = 1 + (N-1) * 20 where N is the LCAT index.

  • BLS Base Annual Wage at offset +1 (raw BLS pull, hardcoded)
  • Aged Annual Wage at offset +2 (= BLS Base × aging factor)
  • Direct Labor Rate Hourly at offset +3
  • Total Estimated Cost at offset +13
  • Total Estimated Price at offset +18
  • Implied Multiplier at offset +19 (Total Price / Direct Labor)

The Aged Annual Wage gets its own row so the aging math is visible on the sheet; a reviewer can see BLS Base and Aged side by side.

Row 2: A="BLS Base Annual Wage"       B=[raw BLS median, hardcoded]
Row 3: A="Aged Annual Wage"           B==B2*$B$13               (formula, refs aging factor)
Row 4: A="Direct Labor Rate (Hourly)" B==B3/2080                (formula)
Row 6: A="Fringe Rate"                B==$B$2                   (formula, refs assumption)
Row 7: A="Fringe Amount"              B==B4*B6                  (formula)
Row 8: A="Labor + Fringe"             B==B4+B7                  (formula)
Row 9: A="Overhead Rate"              B==$B$3                   (formula, refs assumption)
Row 10: A="Overhead Amount"           B==B8*B9                  (formula)
Row 11: A="Subtotal"                  B==B8+B10                 (formula)
Row 12: A="G&A Rate"                  B==$B$4                   (formula, refs assumption)
Row 13: A="G&A Amount"                B==B11*B12                (formula)
Row 14: A="Total Estimated Cost"      B==B11+B13                (formula)

Fee Analysis:
Row 16: A="Fee Type"                  B==$B$5                   (formula)
Row 17: A="Fee Rate"                  B==$B$6                   (formula, refs assumption)
Row 18: A="Fee Amount"                B==B14*B17                (formula)
Row 19: A="Total Estimated Price"     B==B14+B18                (formula, bold)
Row 20: A="Implied Multiplier"        B==B19/B4                 (formula, 0.00"x")

Sheet 2 blocks compute hourly rates. Sheet 1 Summary multiplies by productive hours × FTE × period duration for annual figures. Formula: Sheet 1 annual = 'Cost Buildup'!FBR_cell * $B$6 * FTE * ($B$7/12).

For CPAF: rows 16-20 expand to base fee, award pool, assumed earned %, calculated fee, total price. For CPIF: rows 16-22 expand to target fee, overrun/underrun scenarios with share ratio, min/max bounds.

Annotation text gotcha: Annotation cells (column C or D methodology notes) cannot START with = + - @ or Excel tries to parse as a formula. Prefix with apostrophe ('=2,080 hours/year) or lead with a non-operator character ("Note: 2,080 hours/year"). Applies anywhere a cell value starts with those four characters.

Sheet 3: Scenario Analysis. Three cost columns (low/mid/high) with fee calculated on each. Display component rates at top. For CPIF: expand to 3x3 matrix (cost scenarios x fee outcomes). Summary row with range.

Sheet 4: Rate Validation. BLS burdened cost (mid) + fee vs. CALC+ distribution.

Row 1: "Rate Validation (CR)"
Row 3: Headers: Category | BLS Cost+Fee (mid) | CALC+ 25th | CALC+ 50th | CALC+ 75th | CALC+ Count | Divergence vs Median | Status
Row 4+: one row per category
  Divergence = (Cost_Fee - CALC_50th) / CALC_50th
  Status =
    IF(ABS(Divergence) <= 0.10, "Expected range",
    IF(ABS(Divergence) <= 0.25, "Cite fee structure or cost pool variance",
    "Position outside +-25% band; document stacked factors in Methodology"))

Dual-pool columns when title-match N<10: add "Pool A (Title)" and "Pool B (Experience)" median columns, cite N for each.

Sheet 5: Travel Detail. Formula-driven per destination. When no travel, include the sheet with a single 'Travel Not Applicable' text block. Do not skip the sheet; Sheet 1 Travel row still needs a cell reference target.

Multi-destination parameterization. For M destinations, block N starts at row 1 + (N-1) * 17 with a 16-row content layout and 1-row separator. In-block row indices shift by (N-1) * 17. Do NOT hard-code one city: if the user provides "2 trips/yr to Huntsville + 4 trips/yr to San Diego," build two blocks with distinct labeled headers ("Travel Cost Detail: Huntsville, AL" and "Travel Cost Detail: San Diego, CA") and have Sheet 1 Travel rows SUM across destinations:

Annual travel (Sheet 1) = SUM across destinations of annual_travel_cost cell
                        = SUM('Travel Detail'!$B$14, 'Travel Detail'!$B$31, ...)

Single-destination single-block layout (block 1):

Row 3: A="Fiscal Year"           B=<current federal FY>          (blue)
Row 4: A="Nightly Lodging Rate"  B=[max monthly]                 (blue)
Row 5: A="M&IE Daily Rate"       B=[rate]                        (blue)
Row 6: A="First/Last Day M&IE"   B==B5*0.75                      (formula)
Row 7: A="Nights per Trip"       B=[nights, 0 for day trip]       (blue)
Row 8: A="Travel Days"           B==IF(B7=0,1,B7+1)              (formula)
Row 9: A="Lodging per Trip"      B==B4*B7                        (formula, 0 when nights=0)
Row 10: A="M&IE per Trip"        B==IF(B7=0,B6,B5*MAX(0,B8-2)+B6*2)  (formula)
Row 11: A="Trip Total"           B==B9+B10                       (formula)
Row 12: A="Trips per Year"       B=[trips]                       (blue)
Row 13: A="Travelers"            B=[count]                       (blue)
Row 14: A="Annual Travel Cost"   B==B11*B12*B13                  (formula, bold)

Sheet 6: Methodology. CR-specific narrative. Target length: 8-12 sections, 2-4 sentences each, readable in 3 minutes. Longer than 14 sections usually means restating data that already lives in Sheet 1-4. Include: cost pool buildup with each pool explained, shift coverage FTE math if 24x7, fee type selection rationale and FAR reference, fee-specific notes (CPFF: fee fixed regardless of cost outcome; CPAF: assumed earned % and evaluation basis; CPIF: target cost/fee, share ratios, min/max), statutory fee caps (10 USC 3322(a) for R&D), FAR 16.301-16.307 references, data sources with dates, BLS vintage + aging adjustment, escalation basis, travel methodology (including 0-night day trips if applicable), exclusions, NAICS/PSC if provided.

Sheet 7: Raw Data. All API query parameters and responses. Record summary tables (count, percentiles, series IDs, query parameters) — NOT raw JSON dumps. A reviewer should reproduce the query from the parameters, not wade through 50KB of aggregation buckets.

Formatting standards:

  • Blue font (RGB 0,0,255) for all user-adjustable inputs
  • Black font for formula cells
  • Currency: $#,##0 with negatives in parentheses
  • Percentage: 0.0%
  • Bold headers with light gray fill
  • Freeze panes below assumption block (below row 14)
  • Auto-size column widths
  • Multiplier display: 0.00"x"

When base year is partial, prorate labor and travel using $B$9. Full option years ignore $B$9.

Never output as .md or HTML unless explicitly requested.

Step 9: Present the File

Environment-specific delivery:

  • claude.ai web chat: copy to /mnt/user-data/outputs/<name>.xlsx and call present_files([...]).
  • Claude Code CLI: write to $PWD or user-supplied path. Print the absolute path. On macOS also run open <path>; on Linux xdg-open <path>; on Windows start "" <path>. Do NOT try /mnt/user-data/outputs/ — does not exist outside claude.ai.
  • macOS Claude Desktop with Numbers: write path, run open <path>. Numbers auto-recalculates on open.
  • macOS Claude Code CLI with Excel or Numbers installed: write to $PWD, then run open <path>. The system default handler triggers recalc on open; no Python-side expected-total check is needed.

Do NOT skip delivery. A workbook in the sandbox that isn't surfaced looks like a silent failure.

Edge Cases

BAA without contract type specified: Suggest CPFF as default (most common for R&D BAAs under FAR 35.016). Confirm with user.

Fee exceeds statutory cap: If calculated fee exceeds 15% for R&D or 10% practical ceiling, flag and reduce to cap. Note in methodology.

CPIF share ratio edge cases: If fee calculation hits min or max bound, the share ratio no longer applies in that range. Contractor's fee is capped.

Silent-wrong-answer traps:

  • q= parameter on CALC+ returns the full 265K-record corpus silently. Always use keyword= or search=.
  • wage_stats read from top level returns None. Always read from aggregations.wage_stats.
  • MSA code renumbering (Cleveland 17460 → 17410) returns NO_DATA silently. Verify code if all datatypes return empty.
  • BLS SOC with trailing zeros (151212 vs 15121200) fails the 25-char assertion AFTER you've already constructed several queries. Use exactly 6-char SOC.
  • Annotation text starting with = + - @ triggers Excel formula parse. Escape with apostrophe or lead with text.
  • ODC / placeholder cells set to text "TBD" break SUM formulas. Use numeric 0 literal.

What This Skill Does NOT Cover

Include as placeholder rows or methodology notes:

  • Airfare: Use City Pair YCA fares when origin/destination known; otherwise numeric 0 placeholder
  • Ground transportation: Rental cars, mileage ($0.70/mile), taxi, rideshare
  • ODCs: Equipment, licenses, materials (user must provide; placeholders as numeric 0)
  • Subcontractor costs: Requires separate estimate or vendor input
  • DCAA proposal audits: This skill does not perform the audit; it uses CO-supplied audited rates when provided. See "CO-supplied DCAA rates" in Optional Inputs for the override rule.
  • OCONUS travel: Per diem covers CONUS only; State Dept rates for OCONUS
  • FFP contracts: Use IGCE Builder FFP
  • T&M/LH contracts: Use IGCE Builder LH/T&M
  • Grant budgets: Use Grant Budget Builder

Quick Start Examples

CPFF: "CPFF IGCE for an R&D contract, 3 researchers in Bethesda, base plus 2 OYs" → map SOC, pull Bethesda BLS with P25/P50/P75, build cost pools with cell-referenced aging, calculate 8% fixed fee, validate against CALC+, 7-sheet xlsx.

BAA: "We're issuing a BAA for AI research, need a cost estimate" → confirm CR (CPFF default for BAAs), ask for labor details, run full workflow. Note FAR 35.016 in methodology.

CPIF with 24x7 coverage: "CPIF IGCE with 80/20 share ratio for continuous systems monitoring in Cleveland, base plus 2 OYs" → Step 0.5 → 4.2 FTE single-seat; pull Cleveland 0017410; build cost pools; produce 3x3 matrix (low/mid/high cost × underrun/target/overrun fee) bounded by min/max fee.

Rate validation: "Contractor proposes $195/hr cost + fee on a CPFF contract. Reasonable?" → Workflow B. Pull CALC+, run BLS cost pool buildup, position within ±10 / ±25 / outside bands (no determination).


MIT © James Jenrette / 1102tools. Source: github.com/1102tools/federal-contracting-skills

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.