{"openapi":"3.1.0","info":{"title":"calc.engineer API","version":"1.0.0","description":"Unified engineering calculator API. Every tool is available via REST and MCP.","contact":{"url":"https://calc.engineer"}},"servers":[{"url":"https://calc.engineer"}],"paths":{"/api":{"get":{"summary":"Tool catalog","operationId":"getToolCatalog","tags":["catalog"],"responses":{"200":{"description":"Array of tool metadata","content":{"application/json":{"schema":{"type":"array"}}}}}}},"/api/docs":{"get":{"summary":"OpenAPI specification","operationId":"getOpenApiSpec","tags":["docs"],"responses":{"200":{"description":"OpenAPI 3.1.0 specification","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/keys":{"post":{"summary":"Issue an API key","operationId":"issueApiKey","tags":["auth"],"description":"Get a free API key (5,000 calls/day, 24h TTL). Send Authorization: Bearer <jwt> to get a paid-tier key (unlimited, 30d TTL).","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","description":"Optional label for the key (max 64 chars)"}}}}}},"responses":{"201":{"description":"API key issued","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"API key (ce_<hex>)"},"tier":{"type":"string","enum":["free","developer","network","agent"]},"rate_limit":{"type":"string"},"expires_in":{"type":"string"},"usage":{"type":"string"},"label":{"type":"string","nullable":true}}}}}},"429":{"description":"Key issuance rate limit (5/hour/IP for free tier)"}}},"get":{"summary":"List your active API keys","operationId":"listApiKeys","tags":["auth"],"description":"List all active (non-revoked, non-expired) API keys for the authenticated user. Requires JWT auth.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Active API keys","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"type":"object","properties":{"key_prefix":{"type":"string"},"tier":{"type":"string"},"label":{"type":"string","nullable":true},"created_at":{"type":"string"},"expires_at":{"type":"string"},"last_used_at":{"type":"string","nullable":true},"request_count":{"type":"integer"}}}},"count":{"type":"integer"}}}}}},"401":{"description":"JWT auth required"}}}},"/api/keys/{prefix}":{"delete":{"summary":"Revoke an API key","operationId":"revokeApiKey","tags":["auth"],"description":"Soft-delete an API key by prefix. Requires JWT auth.","security":[{"bearerAuth":[]}],"parameters":[{"name":"prefix","in":"path","required":true,"schema":{"type":"string"},"description":"Key prefix (first 12 chars, e.g. ce_a1b2c3d4)"}],"responses":{"200":{"description":"Key revoked"},"401":{"description":"JWT auth required"},"404":{"description":"Key not found or already revoked"}}}},"/api/fspl":{"get":{"summary":"Metadata for fspl","operationId":"get_fspl","tags":["rf"],"responses":{"200":{"description":"Metadata for fspl","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate free-space path loss (FSPL) in decibels using the ITU-R P.525 standard formula. Given a frequency in MHz and distance in kilometres, returns the expected signal attenuation in an ideal line-of-sight radio link with no obstacles, reflections, or atmospheric absorption. Also computes the RF wavelength. Use this to estimate baseline path loss before adding fade margins, antenna gains, or environmental corrections. Feeds directly into link_budget for full end-to-end analysis.","operationId":"compute_fspl","tags":["rf"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"freq_mhz":{"description":"Carrier frequency in megahertz (MHz)","type":"number"},"dist_km":{"description":"Distance between transmitter and receiver in kilometres","type":"number"}},"required":["freq_mhz","dist_km"]}}}},"responses":{"200":{"description":"Computed result for fspl","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"fspl_db":{"description":"Free-space path loss in decibels (dB)","type":"number"},"wavelength_m":{"description":"RF wavelength in metres","type":"number"}},"required":["fspl_db","wavelength_m"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/link_budget":{"get":{"summary":"Metadata for link_budget","operationId":"get_link_budget","tags":["rf"],"responses":{"200":{"description":"Metadata for link_budget","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Compute a full RF link budget from transmitter power, frequency, distance, and antenna gains. Calculates EIRP, free-space path loss (ITU-R P.525), received power at the receiver, and link margin relative to an optional receiver sensitivity threshold. Use this to determine whether a wireless link closes with adequate margin. Accepts output from noise_figure_cascade and feeds into snr_margin for full receive-chain analysis.","operationId":"compute_link_budget","tags":["rf"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tx_dbm":{"description":"Transmitter output power in dBm","type":"number"},"freq_mhz":{"description":"Carrier frequency in megahertz (MHz)","type":"number"},"dist_km":{"description":"Link distance in kilometres","type":"number"},"tx_gain_dbi":{"type":"number","default":2.15,"description":"Transmit antenna gain in dBi (default 2.15 for a half-wave dipole)"},"rx_gain_dbi":{"type":"number","default":2.15,"description":"Receive antenna gain in dBi (default 2.15 for a half-wave dipole)"},"rx_sensitivity_dbm":{"type":"number","description":"Receiver sensitivity in dBm; when provided, link margin is calculated"}},"required":["tx_dbm","freq_mhz","dist_km"]}}}},"responses":{"200":{"description":"Computed result for link_budget","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"fspl_db":{"description":"Free-space path loss in dB","type":"number"},"eirp_dbm":{"description":"Effective isotropic radiated power in dBm","type":"number"},"rx_power_dbm":{"description":"Received signal power in dBm","type":"number"},"margin_db":{"type":"number","nullable":true,"description":"Link margin in dB (null when sensitivity is not provided)"},"wavelength_m":{"description":"RF wavelength in metres","type":"number"}},"required":["fspl_db","eirp_dbm","rx_power_dbm","margin_db","wavelength_m"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/dipole":{"get":{"summary":"Metadata for dipole","operationId":"get_dipole","tags":["rf"],"responses":{"200":{"description":"Metadata for dipole","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate physical dimensions of a dipole antenna for a given frequency. Returns half-wave or quarter-wave element length in metres, feet, and inches. A half-wave dipole is the most common resonant antenna with approximately 2.15 dBi gain. A quarter-wave monopole (ground plane antenna) is half the length and is widely used in handheld radios and vehicle-mounted systems. Use this before building or purchasing an antenna to verify element length for your operating frequency.","operationId":"compute_dipole","tags":["rf"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"freq_mhz":{"description":"Operating frequency in megahertz (MHz)","type":"number"},"type":{"type":"string","enum":["half_wave","quarter_wave"],"default":"half_wave","description":"Antenna type: half_wave dipole or quarter_wave monopole"}},"required":["freq_mhz"]}}}},"responses":{"200":{"description":"Computed result for dipole","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"length_m":{"description":"Element length in metres","type":"number"},"length_ft":{"description":"Element length in feet","type":"number"},"length_in":{"description":"Element length in inches","type":"number"},"wavelength_m":{"description":"Full wavelength in metres","type":"number"}},"required":["length_m","length_ft","length_in","wavelength_m"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/microstrip":{"get":{"summary":"Metadata for microstrip","operationId":"get_microstrip","tags":["rf"],"responses":{"200":{"description":"Metadata for microstrip","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate PCB microstrip trace width for a target characteristic impedance using the Hammerstad-Jensen closed-form equations. Given target impedance (Z0), substrate dielectric constant (er), substrate height, and copper weight, returns the required trace width and effective dielectric constant. Optionally computes effective wavelength at a given frequency. Essential for RF PCB layout to achieve controlled impedance traces (e.g. 50 ohm for SMA connectors). References IPC-2141.","operationId":"compute_microstrip","tags":["rf"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"z0_ohm":{"type":"number","default":50,"description":"Target characteristic impedance in ohms (default 50)"},"er":{"type":"number","default":4.6,"description":"Substrate relative dielectric constant (default 4.6 for FR-4)"},"height_mm":{"description":"Substrate height (dielectric thickness) in millimetres","type":"number"},"copper_oz":{"type":"number","default":1,"description":"Copper weight in oz/ft2 (1 oz = 0.035 mm thickness)"},"freq_mhz":{"type":"number","description":"Optional frequency in MHz for effective wavelength calculation"}},"required":["height_mm"]}}}},"responses":{"200":{"description":"Computed result for microstrip","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"width_mm":{"description":"Required trace width in millimetres","type":"number"},"er_eff":{"description":"Effective dielectric constant of the microstrip","type":"number"},"wavelength_eff_mm":{"type":"number","nullable":true,"description":"Effective wavelength in millimetres at the given frequency (null if freq not provided)"}},"required":["width_mm","er_eff","wavelength_eff_mm"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/dbm_convert":{"get":{"summary":"Metadata for dbm_convert","operationId":"get_dbm_convert","tags":["rf"],"responses":{"200":{"description":"Metadata for dbm_convert","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Convert a power level in dBm to milliwatts, watts, dBW, and RMS voltage across a given impedance. dBm is the standard unit for RF power referenced to 1 milliwatt. This tool is essential when interfacing datasheets (which use dBm) with circuit analysis (which uses volts and watts). Default impedance is 50 ohms, matching most RF systems. Use this to quickly verify power amplifier output, receiver sensitivity, or regulatory EIRP limits.","operationId":"compute_dbm_convert","tags":["rf"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dbm":{"description":"Power level in dBm (decibels relative to 1 milliwatt)","type":"number"},"impedance_ohm":{"type":"number","default":50,"description":"Load impedance in ohms for Vrms calculation (default 50)"}},"required":["dbm"]}}}},"responses":{"200":{"description":"Computed result for dbm_convert","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"mw":{"description":"Power in milliwatts","type":"number"},"watts":{"description":"Power in watts","type":"number"},"vrms":{"description":"RMS voltage across the load impedance in volts","type":"number"},"dbw":{"description":"Power in dBW (decibels relative to 1 watt)","type":"number"}},"required":["mw","watts","vrms","dbw"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/noise_figure_cascade":{"get":{"summary":"Metadata for noise_figure_cascade","operationId":"get_noise_figure_cascade","tags":["rf"],"responses":{"200":{"description":"Metadata for noise_figure_cascade","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate the cascaded noise figure of a multi-stage receiver chain using the Friis formula. Each stage has a noise figure and gain in dB. The first stage dominates overall system noise, which is why low-noise amplifiers (LNAs) are placed at the front of the chain. Returns total cascaded noise figure, total gain, and equivalent noise temperature. Feeds into link_budget for complete receive-chain sensitivity analysis.","operationId":"compute_noise_figure_cascade","tags":["rf"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"stages":{"description":"Ordered array of receiver chain stages, each with nf_db and gain_db","type":"array","items":{"type":"object","properties":{"nf_db":{"description":"Noise figure of the stage in dB","type":"number"},"gain_db":{"description":"Gain of the stage in dB","type":"number"}},"required":["nf_db","gain_db"]}}},"required":["stages"]}}}},"responses":{"200":{"description":"Computed result for noise_figure_cascade","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"total_nf_db":{"description":"Total cascaded noise figure in dB","type":"number"},"total_gain_db":{"description":"Total gain of the chain in dB","type":"number"},"noise_temp_k":{"description":"Equivalent noise temperature in kelvin (T0 = 290 K)","type":"number"}},"required":["total_nf_db","total_gain_db","noise_temp_k"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/vswr":{"get":{"summary":"Metadata for vswr","operationId":"get_vswr","tags":["rf"],"responses":{"200":{"description":"Metadata for vswr","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Convert between VSWR, return loss, and reflection coefficient — provide any one parameter and get all related impedance-mismatch metrics. Computes VSWR (voltage standing wave ratio), return loss in dB, reflection coefficient (gamma), mismatch loss, and percentage of power reflected vs transmitted. Essential for antenna matching, transmission line analysis, and RF system budgeting. Feeds into link_budget for system-level mismatch accounting.","operationId":"compute_vswr","tags":["rf"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"vswr":{"type":"number","description":"Voltage standing wave ratio (>= 1.0, where 1.0 is perfect match)"},"return_loss_db":{"type":"number","description":"Return loss in decibels (positive value, higher is better match)"},"reflection_coefficient":{"type":"number","description":"Reflection coefficient magnitude (gamma), 0 to 1"}},"required":[]}}}},"responses":{"200":{"description":"Computed result for vswr","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"vswr":{"description":"Voltage standing wave ratio","type":"number"},"return_loss_db":{"description":"Return loss in decibels (positive)","type":"number"},"reflection_coefficient":{"description":"Reflection coefficient magnitude (gamma)","type":"number"},"mismatch_loss_db":{"description":"Mismatch loss in decibels","type":"number"},"power_reflected_pct":{"description":"Percentage of power reflected back toward source","type":"number"},"power_transmitted_pct":{"description":"Percentage of power delivered to load","type":"number"}},"required":["vswr","return_loss_db","reflection_coefficient","mismatch_loss_db","power_reflected_pct","power_transmitted_pct"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/attenuator_pi":{"get":{"summary":"Metadata for attenuator_pi","operationId":"get_attenuator_pi","tags":["rf"],"responses":{"200":{"description":"Metadata for attenuator_pi","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Design a Pi-topology resistive attenuator pad. Given a desired attenuation in dB and characteristic impedance (default 50 ohm), computes the three resistor values for a symmetrical Pi-pad network. The Pi attenuator uses two shunt resistors (R1, R3) and one series resistor (R2). Commonly used in RF signal chains to reduce signal level while maintaining impedance match. Compare with attenuator_tee for T-pad topology.","operationId":"compute_attenuator_pi","tags":["rf"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"attenuation_db":{"description":"Desired attenuation in decibels (positive value)","type":"number"},"z0_ohm":{"type":"number","default":50,"description":"Characteristic impedance in ohms (default 50)"}},"required":["attenuation_db"]}}}},"responses":{"200":{"description":"Computed result for attenuator_pi","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"r1_ohm":{"description":"Shunt resistor R1 (input side) in ohms","type":"number"},"r2_ohm":{"description":"Series resistor R2 (middle) in ohms","type":"number"},"r3_ohm":{"description":"Shunt resistor R3 (output side) in ohms","type":"number"},"topology":{"description":"Attenuator topology identifier","type":"string"}},"required":["r1_ohm","r2_ohm","r3_ohm","topology"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/attenuator_tee":{"get":{"summary":"Metadata for attenuator_tee","operationId":"get_attenuator_tee","tags":["rf"],"responses":{"200":{"description":"Metadata for attenuator_tee","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Design a Tee-topology resistive attenuator pad. Given a desired attenuation in dB and characteristic impedance (default 50 ohm), computes the three resistor values for a symmetrical T-pad network. The Tee attenuator uses two series resistors (R1, R3) and one shunt resistor (R2). Commonly used in RF signal chains to reduce signal level while maintaining impedance match. Compare with attenuator_pi for Pi-pad topology.","operationId":"compute_attenuator_tee","tags":["rf"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"attenuation_db":{"description":"Desired attenuation in decibels (positive value)","type":"number"},"z0_ohm":{"type":"number","default":50,"description":"Characteristic impedance in ohms (default 50)"}},"required":["attenuation_db"]}}}},"responses":{"200":{"description":"Computed result for attenuator_tee","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"r1_ohm":{"description":"Series resistor R1 (input side) in ohms","type":"number"},"r2_ohm":{"description":"Shunt resistor R2 (middle) in ohms","type":"number"},"r3_ohm":{"description":"Series resistor R3 (output side) in ohms","type":"number"},"topology":{"description":"Attenuator topology identifier","type":"string"}},"required":["r1_ohm","r2_ohm","r3_ohm","topology"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/fresnel_zone":{"get":{"summary":"Metadata for fresnel_zone","operationId":"get_fresnel_zone","tags":["rf"],"responses":{"200":{"description":"Metadata for fresnel_zone","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate the Fresnel zone radius at the midpoint of a radio link. Given frequency in MHz, link distance in kilometres, and zone number (1-5), returns the Fresnel zone radius in metres and feet, plus the 60% clearance threshold used in practical link engineering. The first Fresnel zone defines the region where most RF energy travels; obstructions within 60% of this radius cause significant signal degradation. Feeds into link_budget for path clearance analysis.","operationId":"compute_fresnel_zone","tags":["rf"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"freq_mhz":{"description":"Operating frequency in megahertz (MHz)","type":"number"},"dist_km":{"description":"Total link distance in kilometres","type":"number"},"zone_number":{"type":"number","default":1,"description":"Fresnel zone number (1-5, default 1)"}},"required":["freq_mhz","dist_km"]}}}},"responses":{"200":{"description":"Computed result for fresnel_zone","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"radius_m":{"description":"Fresnel zone radius at midpoint in metres","type":"number"},"radius_ft":{"description":"Fresnel zone radius at midpoint in feet","type":"number"},"clearance_60pct_m":{"description":"60% Fresnel zone clearance (practical minimum) in metres","type":"number"},"wavelength_m":{"description":"RF wavelength in metres","type":"number"}},"required":["radius_m","radius_ft","clearance_60pct_m","wavelength_m"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/wavelength_freq":{"get":{"summary":"Metadata for wavelength_freq","operationId":"get_wavelength_freq","tags":["rf"],"responses":{"200":{"description":"Metadata for wavelength_freq","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Convert between radio frequency and wavelength. Provide either frequency in MHz or wavelength in metres, and get the full set of equivalent values: frequency in MHz and GHz, wavelength in metres, centimetres, millimetres, and feet. Essential for antenna dimensioning, waveguide selection, and quick band identification. The fundamental relationship is lambda = c / f where c is the speed of light (299 792 458 m/s).","operationId":"compute_wavelength_freq","tags":["rf"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"freq_mhz":{"type":"number","description":"Frequency in megahertz (MHz)"},"wavelength_m":{"type":"number","description":"Wavelength in metres"}},"required":[]}}}},"responses":{"200":{"description":"Computed result for wavelength_freq","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"freq_mhz":{"description":"Frequency in megahertz (MHz)","type":"number"},"freq_ghz":{"description":"Frequency in gigahertz (GHz)","type":"number"},"wavelength_m":{"description":"Wavelength in metres","type":"number"},"wavelength_cm":{"description":"Wavelength in centimetres","type":"number"},"wavelength_mm":{"description":"Wavelength in millimetres","type":"number"},"wavelength_ft":{"description":"Wavelength in feet","type":"number"}},"required":["freq_mhz","freq_ghz","wavelength_m","wavelength_cm","wavelength_mm","wavelength_ft"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/spice_template":{"get":{"summary":"Metadata for spice_template","operationId":"get_spice_template","tags":["rf"],"responses":{"200":{"description":"Metadata for spice_template","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Generate a complete SPICE netlist from a parameterized template. Supports common circuit topologies: low-pass RC filter, voltage divider, common emitter amplifier. Returns a ready-to-simulate netlist string that can be passed directly to spice_simulate. Use this when an agent needs to construct a circuit from high-level parameters without writing raw SPICE syntax. Feeds into spice_simulate for AC/DC/transient analysis.","operationId":"compute_spice_template","tags":["rf"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"template":{"description":"Circuit template name","type":"string","enum":["low_pass_rc","voltage_divider","common_emitter","rc_highpass","rlc_bandpass","opamp_inverting","diode_rectifier","wien_bridge"]},"params":{"description":"Template-specific parameters (e.g. r_ohms, c_farads, v_source)","type":"object","additionalProperties":{"type":"number"}},"analysis":{"type":"string","enum":["ac","dc","tran"],"default":"ac","description":"SPICE analysis type to include in netlist"}},"required":["template","params"]}}}},"responses":{"200":{"description":"Computed result for spice_template","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"netlist":{"description":"Complete SPICE netlist ready for simulation","type":"string"},"template_name":{"description":"Template used","type":"string"},"component_count":{"description":"Number of components in the generated circuit","type":"number"},"analysis_type":{"description":"Analysis type included in the netlist","type":"string"}},"required":["netlist","template_name","component_count","analysis_type"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/spice_simulate":{"get":{"summary":"Metadata for spice_simulate","operationId":"get_spice_simulate","tags":["rf"],"responses":{"200":{"description":"Metadata for spice_simulate","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Run a SPICE circuit simulation directly in the worker. Accepts a standard SPICE netlist and performs operating-point (.op), DC sweep (.dc), AC frequency sweep (.ac), or transient (.tran) analysis using a built-in modified-nodal-analysis engine with Newton-Raphson nonlinear solving. Supports R, L, C, V, I sources (DC/AC/SIN/PULSE), diodes, BJTs (Ebers-Moll), MOSFETs (Shichman-Hodges level 1), controlled sources (E/G), .param expressions, .subckt/X hierarchical subcircuits, .measure and .four (Fourier/THD), and a built-in parts library (reference 2n3904/2n2222/1n4148/1n5819/2n7000/tl072/lm358/led_red etc. by name and the model is auto-injected), up to 150 components. Returns voltage vectors for all circuit nodes (magnitude + phase for AC). Use spice_template to generate netlists from parameterized templates.","operationId":"compute_spice_simulate","tags":["rf"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"netlist":{"description":"SPICE netlist (ngspice-compatible). Must include at least one analysis command (.ac, .dc, .tran, .op) and end with .end","type":"string"},"analysis":{"type":"string","enum":["ac","dc","tran","op"],"description":"Override analysis type (auto-detected from netlist if omitted)"},"temperature_c":{"type":"number","default":27,"description":"Simulation temperature in Celsius"},"options":{"type":"object","additionalProperties":{},"description":"Additional ngspice .options (e.g. { reltol: 0.001 })"},"certify":{"type":"boolean","description":"If true, attach an a-posteriori existence certificate for the DC operating point (Newton–Kantorovich: proves a true solution exists within a computed radius, or refuses). Adds ~one extra back-solve."},"tolerances":{"type":"object","additionalProperties":{"type":"number"},"description":"Component-tolerance box, e.g. {\"R1\":0.05,\"V1\":0.02} (fractional). With output_node, returns a certified min/max interval for that node over all component variations. R/V/I elements only."},"output_node":{"type":"string","description":"Node whose voltage is certified over the tolerance box (required with tolerances)."}},"required":["netlist"]}}}},"responses":{"200":{"description":"Computed result for spice_simulate","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"vectors":{"description":"Named voltage/current vectors keyed by node name","type":"object","additionalProperties":{"type":"array","items":{"type":"number"}}},"nodes":{"description":"List of circuit node names","type":"array","items":{"type":"string"}},"analysis_type":{"description":"Analysis type that was performed","type":"string"},"runtime_ms":{"description":"Simulation wall-clock time in milliseconds","type":"number"},"warnings":{"description":"Any ngspice warnings generated during simulation","type":"array","items":{"type":"string"}},"component_count":{"description":"Number of components in the netlist","type":"number"},"certificate":{"description":"Present when certify=true: {certified, rho, eta, h, ...} existence certificate for the DC operating point"},"tolerance_certificate":{"description":"Present when tolerances+output_node given: {certified, interval, nominal, ...} certified output range over the component-tolerance box"},"measures":{"description":"Present when the netlist has .measure cards: {name: value}"},"fourier":{"description":"Present when the netlist has .four cards: Fourier harmonics + THD per node"}},"required":["vectors","nodes","analysis_type","runtime_ms","warnings","component_count"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/lora_airtime":{"get":{"summary":"Metadata for lora_airtime","operationId":"get_lora_airtime","tags":["mesh"],"responses":{"200":{"description":"Metadata for lora_airtime","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates LoRa packet time-on-air using the Semtech AN1200.13 formula. Computes symbol duration, preamble time, payload symbol count, effective data rate, and the minimum transmission interval for 1% duty cycle compliance. Essential for capacity planning in LoRaWAN and Meshtastic mesh networks. Accepts spreading factor (SF7-SF12), bandwidth (125/250/500 kHz), coding rate (4/5-4/8), payload size, header mode, CRC, and optional low data rate optimization. Feeds airtime_ms to channel_utilization for mesh load analysis.","operationId":"compute_lora_airtime","tags":["mesh"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sf":{"type":"number","default":10,"description":"LoRa spreading factor (7-12). Higher SF = longer range but slower data rate."},"bw_khz":{"default":125,"description":"LoRa channel bandwidth in kHz. Common values: 125, 250, or 500."},"cr":{"type":"number","default":5,"description":"LoRa coding rate denominator (5-8). Represents 4/5 through 4/8 FEC ratio."},"payload_bytes":{"description":"Application payload size in bytes (0-255).","type":"number"},"preamble_symbols":{"type":"number","default":8,"description":"Number of preamble symbols. LoRaWAN uses 8; raw LoRa may vary."},"explicit_header":{"type":"boolean","default":true,"description":"Whether to use explicit header mode. True for LoRaWAN; false for implicit header."},"crc":{"type":"boolean","default":true,"description":"Whether CRC is appended to payload. Recommended true for reliability."},"low_data_rate_optimize":{"type":"boolean","description":"Enable low data rate optimization. Auto-calculated if omitted: enabled for SF >= 11 at BW 125 kHz."}},"required":["payload_bytes"]}}}},"responses":{"200":{"description":"Computed result for lora_airtime","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"airtime_ms":{"description":"Total packet time-on-air in milliseconds.","type":"number"},"symbol_time_ms":{"description":"Duration of a single LoRa symbol in milliseconds.","type":"number"},"preamble_time_ms":{"description":"Preamble duration in milliseconds (includes 4.25 sync symbols).","type":"number"},"payload_symbols":{"description":"Number of symbols used for the payload + header portion.","type":"number"},"data_rate_bps":{"description":"Effective data rate in bits per second.","type":"number"},"duty_cycle_1pct_interval_s":{"description":"Minimum interval between transmissions in seconds to respect 1% duty cycle regulation.","type":"number"}},"required":["airtime_ms","symbol_time_ms","preamble_time_ms","payload_symbols","data_rate_bps","duty_cycle_1pct_interval_s"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/snr_margin":{"get":{"summary":"Metadata for snr_margin","operationId":"get_snr_margin","tags":["mesh"],"responses":{"200":{"description":"Metadata for snr_margin","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Computes LoRa link SNR margin by comparing received power against the noise floor and the spreading-factor-dependent demodulation threshold from the Semtech SX1276 datasheet. Calculates receiver noise floor from thermal noise (-174 dBm/Hz), channel bandwidth, and receiver noise figure. Returns margin in dB and a boolean link-OK indicator. Use to validate whether a LoRa or Meshtastic link will reliably decode packets. Accepts rx_power from link_budget tool output for end-to-end chain analysis.","operationId":"compute_snr_margin","tags":["mesh"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rx_power_dbm":{"description":"Received signal power in dBm (e.g., -110). Typically from a link budget calculation or field measurement.","type":"number"},"sf":{"type":"number","default":10,"description":"LoRa spreading factor (7-12). Higher SF tolerates lower SNR."},"bw_khz":{"default":125,"description":"LoRa channel bandwidth in kHz. Affects noise floor."},"noise_figure_db":{"type":"number","default":6,"description":"Receiver noise figure in dB. Typical LoRa radio NF is 6 dB (SX1276)."}},"required":["rx_power_dbm"]}}}},"responses":{"200":{"description":"Computed result for snr_margin","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"margin_db":{"description":"SNR margin above demodulation threshold in dB. Positive = link OK, negative = link failure.","type":"number"},"noise_floor_dbm":{"description":"Receiver noise floor in dBm, computed from bandwidth and noise figure.","type":"number"},"required_snr_db":{"description":"Minimum SNR required for successful LoRa demodulation at the given SF.","type":"number"},"link_ok":{"description":"True if margin_db > 0 (signal exceeds demodulation threshold).","type":"boolean"}},"required":["margin_db","noise_floor_dbm","required_snr_db","link_ok"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/channel_utilization":{"get":{"summary":"Metadata for channel_utilization","operationId":"get_channel_utilization","tags":["mesh"],"responses":{"200":{"description":"Metadata for channel_utilization","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Estimates Meshtastic or LoRa mesh channel utilization percentage based on node count, message rate, and per-packet airtime. Determines how much of the shared radio channel is occupied and computes the maximum number of nodes before exceeding a configurable duty cycle limit (default 10%). Returns utilization percentage, headroom, and total packet count. Chain from lora_airtime to get airtime_ms input. Essential for Meshtastic mesh deployment planning to avoid channel congestion and packet collisions.","operationId":"compute_channel_utilization","tags":["mesh"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nodes":{"description":"Number of active nodes in the mesh network.","type":"number"},"messages_per_hour_per_node":{"type":"number","default":2,"description":"Average messages transmitted per hour per node. Includes position beacons and user messages."},"airtime_ms":{"description":"Time-on-air per packet in milliseconds. Obtain from lora_airtime tool.","type":"number"},"max_duty_cycle_pct":{"type":"number","default":10,"description":"Maximum acceptable channel utilization percentage. Default 10% is a common Meshtastic guideline."}},"required":["nodes","airtime_ms"]}}}},"responses":{"200":{"description":"Computed result for channel_utilization","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"utilization_pct":{"description":"Current channel utilization as a percentage of total airtime.","type":"number"},"max_nodes_at_limit":{"description":"Maximum number of nodes before exceeding the duty cycle limit.","type":"number"},"headroom_pct":{"description":"Remaining headroom before hitting the duty cycle limit (can be negative if over limit).","type":"number"},"packets_per_hour":{"description":"Total packets per hour across all nodes.","type":"number"}},"required":["utilization_pct","max_nodes_at_limit","headroom_pct","packets_per_hour"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/lora_range_estimate":{"get":{"summary":"Metadata for lora_range_estimate","operationId":"get_lora_range_estimate","tags":["mesh"],"responses":{"200":{"description":"Metadata for lora_range_estimate","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Estimates LoRa maximum communication range by computing the free-space path loss (FSPL) link budget and applying terrain-dependent correction factors. Calculates total link budget from transmit power, antenna gains, and receiver sensitivity, then solves the FSPL equation for distance after subtracting terrain losses (0 dB open to 50 dB indoor). Returns estimated range in km, link margin at 1 km, and effective path loss. Useful for Meshtastic deployment planning and coverage mapping. Terrain corrections are empirical estimates; real-world range varies with elevation, foliage, and weather.","operationId":"compute_lora_range_estimate","tags":["mesh"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tx_dbm":{"type":"number","default":20,"description":"Transmit power in dBm. Typical LoRa: 14-30 dBm depending on region and module."},"freq_mhz":{"type":"number","default":915,"description":"Carrier frequency in MHz. Common: 868 (EU), 915 (US/AU), 433 (Asia)."},"tx_gain_dbi":{"type":"number","default":2.15,"description":"Transmit antenna gain in dBi. 2.15 dBi = half-wave dipole."},"rx_gain_dbi":{"type":"number","default":2.15,"description":"Receive antenna gain in dBi. 2.15 dBi = half-wave dipole."},"rx_sensitivity_dbm":{"type":"number","default":-130,"description":"Receiver sensitivity in dBm. Typical LoRa SF10/BW125: -130 dBm. Varies by SF and bandwidth."},"terrain":{"type":"string","enum":["open","suburban","urban","dense_urban","indoor"],"default":"suburban","description":"Terrain type for path loss correction. open: line-of-sight, suburban: light buildings, urban: moderate buildings, dense_urban: city center, indoor: inside buildings."}},"required":[]}}}},"responses":{"200":{"description":"Computed result for lora_range_estimate","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"max_range_km":{"description":"Estimated maximum range in kilometers accounting for terrain correction.","type":"number"},"margin_at_1km_db":{"description":"Link margin at 1 km distance in dB. Positive means signal above sensitivity.","type":"number"},"effective_path_loss_db":{"description":"Maximum allowable path loss in dB (link budget minus terrain correction).","type":"number"}},"required":["max_range_km","margin_at_1km_db","effective_path_loss_db"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/lora_sensitivity":{"get":{"summary":"Metadata for lora_sensitivity","operationId":"get_lora_sensitivity","tags":["mesh"],"responses":{"200":{"description":"Metadata for lora_sensitivity","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates LoRa receiver sensitivity from spreading factor, bandwidth, and noise figure using the Semtech SX1276 datasheet SNR thresholds. Computes the noise floor from thermal noise density (-174 dBm/Hz), channel bandwidth, and receiver noise figure, then adds the spreading-factor-dependent minimum demodulation SNR. Returns sensitivity in dBm, noise floor, required SNR, and thermal noise reference. Essential for link budget planning in LoRaWAN and Meshtastic networks. Feeds sensitivity_dbm to link_budget and lora_range_estimate for end-to-end coverage analysis.","operationId":"compute_lora_sensitivity","tags":["mesh"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sf":{"type":"number","default":10,"description":"LoRa spreading factor (7-12). Higher SF = better sensitivity but slower data rate."},"bw_khz":{"default":125,"description":"LoRa channel bandwidth in kHz. Lower bandwidth = better sensitivity."},"noise_figure_db":{"type":"number","default":6,"description":"Receiver noise figure in dB. Typical LoRa radio NF is 6 dB (SX1276)."}},"required":[]}}}},"responses":{"200":{"description":"Computed result for lora_sensitivity","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"sensitivity_dbm":{"description":"Receiver sensitivity in dBm. The minimum signal power for successful demodulation.","type":"number"},"noise_floor_dbm":{"description":"Receiver noise floor in dBm, computed from thermal noise, bandwidth, and noise figure.","type":"number"},"required_snr_db":{"description":"Minimum SNR required for LoRa demodulation at the given spreading factor.","type":"number"},"thermal_noise_dbm":{"description":"Thermal noise power density at room temperature: -174 dBm/Hz.","type":"number"}},"required":["sensitivity_dbm","noise_floor_dbm","required_snr_db","thermal_noise_dbm"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/duty_cycle_budget":{"get":{"summary":"Metadata for duty_cycle_budget","operationId":"get_duty_cycle_budget","tags":["mesh"],"responses":{"200":{"description":"Metadata for duty_cycle_budget","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates LoRa duty cycle budget for EU868, US915, AS923, and AU915 regulatory regions. Computes maximum messages per hour, minimum transmission interval, and effective data rate under regional duty cycle constraints. EU868 and AS923 enforce 1% duty cycle (ETSI); US915 has no duty cycle limit but a 400 ms dwell time per channel (FCC); AU915 has no duty cycle limit. Flags dwell-time-limited regions where packet airtime must not exceed the dwell time. Chain from lora_airtime to get airtime_ms input for end-to-end regulatory compliance analysis.","operationId":"compute_duty_cycle_budget","tags":["mesh"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"airtime_ms":{"description":"Packet time-on-air in milliseconds. Obtain from the lora_airtime tool.","type":"number"},"region":{"type":"string","enum":["EU868","US915","AS923","AU915"],"default":"EU868","description":"LoRa regulatory region. EU868: 1% duty cycle (ETSI). US915: no duty cycle but 400 ms dwell time (FCC). AS923: 1% duty cycle (varies by country). AU915: no duty cycle limit."}},"required":["airtime_ms"]}}}},"responses":{"200":{"description":"Computed result for duty_cycle_budget","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"max_messages_per_hour":{"description":"Maximum messages per hour allowed under the regional duty cycle constraint.","type":"number"},"min_interval_s":{"description":"Minimum interval between transmissions in seconds to comply with duty cycle regulation.","type":"number"},"duty_cycle_pct":{"description":"Applicable duty cycle limit as a percentage. 100 means no duty cycle restriction.","type":"number"},"dwell_time_limited":{"description":"True if the region enforces a per-transmission dwell time limit (e.g., US915 400 ms).","type":"boolean"},"effective_data_rate_bps":{"description":"Effective throughput in bits per second considering duty cycle. For duty-cycle-limited regions, this reflects actual achievable throughput.","type":"number"}},"required":["max_messages_per_hour","min_interval_s","duty_cycle_pct","dwell_time_limited","effective_data_rate_bps"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/meshtastic_range":{"get":{"summary":"Metadata for meshtastic_range","operationId":"get_meshtastic_range","tags":["mesh"],"responses":{"200":{"description":"Metadata for meshtastic_range","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Estimates Meshtastic node communication range using real hardware profiles and firmware channel presets. Combines device-specific TX power and antenna gain (Heltec V3, RAK WisBlock, T-Beam, T-Beam Supreme, Station G2) with firmware modem presets (Long Fast, Long Slow, Very Long Slow, Medium, Short) to compute receiver sensitivity and FSPL-based range with terrain correction. Automatically populates LoRa parameters from device and channel selection, with optional overrides for custom antennas or power levels. Essential for Meshtastic deployment planning and node placement. Returns range, sensitivity, link budget, and the effective radio parameters used.","operationId":"compute_meshtastic_range","tags":["mesh"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"device":{"type":"string","enum":["heltec_v3","rak_wisblock","tbeam","tbeam_supreme","station_g2","custom"],"default":"heltec_v3","description":"Meshtastic hardware device. Selects default TX power, antenna gain, and noise figure. Use 'custom' to override all radio parameters manually."},"channel_preset":{"type":"string","enum":["long_fast","long_moderate","long_slow","very_long_slow","medium_fast","medium_slow","short_fast","short_slow","custom"],"default":"long_fast","description":"Meshtastic firmware channel preset. Selects spreading factor, bandwidth, and coding rate. long_fast is the default; very_long_slow maximizes range at the cost of throughput."},"terrain":{"type":"string","enum":["open","suburban","urban","dense_urban","indoor"],"default":"suburban","description":"Terrain type for path loss correction. open: line-of-sight, suburban: light buildings, urban: moderate buildings, dense_urban: city center, indoor: inside buildings."},"antenna_gain_dbi":{"type":"number","description":"Override device default antenna gain in dBi. Useful for aftermarket antennas."},"tx_power_dbm":{"type":"number","description":"Override device default transmit power in dBm."},"sf":{"type":"number","description":"Custom spreading factor (7-12). Only used when channel_preset is 'custom'."},"bw_khz":{"type":"number","description":"Custom bandwidth in kHz. Only used when channel_preset is 'custom'."},"cr":{"type":"number","description":"Custom coding rate denominator (5-8). Only used when channel_preset is 'custom'."}},"required":[]}}}},"responses":{"200":{"description":"Computed result for meshtastic_range","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"max_range_km":{"description":"Estimated maximum range in km accounting for terrain correction.","type":"number"},"rx_sensitivity_dbm":{"description":"Receiver sensitivity in dBm for the selected channel preset.","type":"number"},"link_budget_db":{"description":"Total link budget in dB before terrain correction.","type":"number"},"device_name":{"description":"Human-readable device name.","type":"string"},"channel_name":{"description":"Human-readable channel preset name.","type":"string"},"effective_sf":{"description":"Spreading factor used for the calculation.","type":"number"},"effective_bw_khz":{"description":"Bandwidth in kHz used for the calculation.","type":"number"},"tx_power_dbm":{"description":"Transmit power in dBm used for the calculation.","type":"number"},"antenna_gain_dbi":{"description":"Antenna gain in dBi used for the calculation.","type":"number"}},"required":["max_range_km","rx_sensitivity_dbm","link_budget_db","device_name","channel_name","effective_sf","effective_bw_khz","tx_power_dbm","antenna_gain_dbi"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/eirp_compliance":{"get":{"summary":"Metadata for eirp_compliance","operationId":"get_eirp_compliance","tags":["mesh"],"responses":{"200":{"description":"Metadata for eirp_compliance","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Checks EIRP (Effective Isotropic Radiated Power) compliance against regional regulatory limits for LoRa and Meshtastic operation. Computes EIRP from transmit power, antenna gain, and cable loss, then compares against FCC (US, 36 dBm), ETSI (EU, 16.15 dBm), ACMA (Australia, 30 dBm), IC (Canada, 36 dBm), and ARIB (Japan, 13 dBm) limits. Returns compliance status, margin in dB, and a warning message if over the limit. Critical for Meshtastic deployments using aftermarket high-gain antennas which can easily exceed ETSI/JP limits. Accepts tx_power and antenna_gain from meshtastic_range for chain validation.","operationId":"compute_eirp_compliance","tags":["mesh"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tx_power_dbm":{"description":"Conducted transmit power at the radio output in dBm. Typical LoRa: 14-22 dBm.","type":"number"},"antenna_gain_dbi":{"description":"Antenna gain in dBi. Stock Meshtastic antennas: 2-3 dBi. External: 6-10+ dBi.","type":"number"},"cable_loss_db":{"type":"number","default":0,"description":"Coaxial cable and connector loss in dB. Set 0 for devices with integrated antennas."},"region":{"type":"string","enum":["FCC_US","ETSI_EU","ACMA_AU","IC_CA","JP","custom"],"default":"FCC_US","description":"Regulatory region for EIRP limit lookup. FCC_US: 36 dBm, ETSI_EU: ~16 dBm, ACMA_AU: 30 dBm, IC_CA: 36 dBm, JP: 13 dBm."},"custom_limit_dbm":{"type":"number","description":"Custom EIRP limit in dBm. Only used when region is 'custom'."}},"required":["tx_power_dbm","antenna_gain_dbi"]}}}},"responses":{"200":{"description":"Computed result for eirp_compliance","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"eirp_dbm":{"description":"Calculated EIRP in dBm: tx_power + antenna_gain - cable_loss.","type":"number"},"eirp_watts":{"description":"Calculated EIRP converted to watts.","type":"number"},"limit_dbm":{"description":"Regional EIRP limit in dBm.","type":"number"},"limit_watts":{"description":"Regional EIRP limit converted to watts.","type":"number"},"margin_db":{"description":"Margin below the limit in dB. Positive = compliant, negative = over limit.","type":"number"},"compliant":{"description":"True if EIRP is at or below the regional limit.","type":"boolean"},"region_name":{"description":"Human-readable region name.","type":"string"},"warning":{"description":"Warning message if non-compliant, or empty string if compliant.","type":"string"}},"required":["eirp_dbm","eirp_watts","limit_dbm","limit_watts","margin_db","compliant","region_name","warning"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/meshtastic_power":{"get":{"summary":"Metadata for meshtastic_power","operationId":"get_meshtastic_power","tags":["mesh"],"responses":{"200":{"description":"Metadata for meshtastic_power","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates Meshtastic node power consumption and battery runtime using device-specific power profiles and firmware role-based duty cycling. Models sleep, RX, and TX current draw for Heltec V3, RAK WisBlock, T-Beam, T-Beam Supreme, and Station G2 with GPS, BLE, and display peripheral toggles. Role selection (client, router, repeater, client_muted) controls the duty cycle model: routers stay in RX mode continuously while clients sleep between events. Returns average current, runtime in hours/days, daily Wh consumption, and time distribution across TX/RX/sleep states. Feed daily_wh to solar_sizing for off-grid planning.","operationId":"compute_meshtastic_power","tags":["mesh"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"device":{"type":"string","enum":["heltec_v3","rak_wisblock","tbeam","tbeam_supreme","station_g2","custom"],"default":"heltec_v3","description":"Meshtastic hardware device. Selects power consumption profile for sleep, RX, TX, GPS, and BLE."},"channel_preset":{"type":"string","enum":["long_fast","long_moderate","long_slow","very_long_slow","medium_fast","medium_slow","short_fast","short_slow"],"default":"long_fast","description":"Meshtastic channel preset. Affects TX airtime per message and thus power consumption."},"battery_mah":{"type":"number","default":3000,"description":"Battery capacity in milliamp-hours. Common: 1100 (18650 min), 3000 (typical), 6000 (large)."},"battery_voltage":{"type":"number","default":3.7,"description":"Nominal battery voltage. 3.7V for single-cell LiPo/Li-ion, 7.4V for 2S packs."},"messages_per_hour":{"type":"number","default":2,"description":"Expected messages sent and received per hour. Includes both TX and RX message events."},"gps_enabled":{"type":"boolean","default":false,"description":"Whether GPS is enabled. Significantly increases power draw on devices with built-in GPS."},"bluetooth_enabled":{"type":"boolean","default":true,"description":"Whether Bluetooth is enabled for phone connection."},"role":{"type":"string","enum":["client","router","repeater","client_muted"],"default":"client","description":"Meshtastic node role. client: sleeps between events. router: always listening. repeater: always listening, no display/BLE. client_muted: aggressive sleep."}},"required":[]}}}},"responses":{"200":{"description":"Computed result for meshtastic_power","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"avg_current_ma":{"description":"Estimated average current draw in milliamps.","type":"number"},"runtime_hours":{"description":"Estimated battery runtime in hours.","type":"number"},"runtime_days":{"description":"Estimated battery runtime in days.","type":"number"},"daily_wh":{"description":"Estimated daily energy consumption in watt-hours.","type":"number"},"tx_time_pct":{"description":"Percentage of time spent transmitting.","type":"number"},"rx_time_pct":{"description":"Percentage of time spent in receive mode (radio listening).","type":"number"},"sleep_time_pct":{"description":"Percentage of time spent in sleep/low-power mode.","type":"number"}},"required":["avg_current_ma","runtime_hours","runtime_days","daily_wh","tx_time_pct","rx_time_pct","sleep_time_pct"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/lora_param_optimizer":{"get":{"summary":"Metadata for lora_param_optimizer","operationId":"get_lora_param_optimizer","tags":["mesh"],"responses":{"200":{"description":"Metadata for lora_param_optimizer","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Recommends optimal LoRa spreading factor, bandwidth, and TX power based on target range, terrain, and optimization priority. Iterates through all SF (7-12) and BW (125/250/500 kHz) combinations, computing achievable range, airtime, data rate, and battery impact for each. Ranks candidates by priority: 'range' maximizes distance, 'speed' minimizes airtime, 'battery' minimizes power consumption, 'balanced' penalizes extremes. Respects regional TX power limits (FCC/ETSI/ACMA) and duty cycle constraints. Returns the recommended parameters with estimated range, airtime, duty-cycle message limit, battery life, and data rate. Essential for tuning Meshtastic and LoRa deployments to specific requirements.","operationId":"compute_lora_param_optimizer","tags":["mesh"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"target_range_km":{"description":"Desired communication range in kilometers.","type":"number"},"terrain":{"type":"string","enum":["open","suburban","urban","dense_urban","indoor"],"default":"suburban","description":"Terrain type for path loss model. open: line-of-sight, suburban: light buildings, urban: moderate buildings, dense_urban: city center, indoor: inside buildings."},"max_payload_bytes":{"type":"number","default":200,"description":"Maximum payload size in bytes for airtime calculation."},"priority":{"type":"string","enum":["range","speed","battery","balanced"],"default":"balanced","description":"Optimization priority. range: maximize distance (high SF, low BW). speed: minimize airtime (low SF, high BW). battery: minimize power draw. balanced: best trade-off across all factors."},"region":{"type":"string","enum":["US915","EU868","AU915","AS923"],"default":"US915","description":"Regulatory region. Determines max TX power and duty cycle limit."},"antenna_gain_dbi":{"type":"number","default":2.15,"description":"Antenna gain in dBi. 2.15 = half-wave dipole reference."}},"required":["target_range_km"]}}}},"responses":{"200":{"description":"Computed result for lora_param_optimizer","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"recommended_sf":{"description":"Recommended spreading factor (7-12).","type":"number"},"recommended_bw_khz":{"description":"Recommended bandwidth in kHz (125, 250, or 500).","type":"number"},"recommended_tx_dbm":{"description":"Recommended transmit power in dBm.","type":"number"},"estimated_range_km":{"description":"Estimated achievable range in km with the recommended parameters.","type":"number"},"airtime_ms":{"description":"Packet airtime in milliseconds for the given payload.","type":"number"},"messages_per_hour_limit":{"description":"Maximum messages per hour under regional duty cycle constraint.","type":"number"},"estimated_battery_hours":{"description":"Estimated battery life in hours with a 3000 mAh reference battery.","type":"number"},"data_rate_bps":{"description":"Effective data rate in bits per second.","type":"number"}},"required":["recommended_sf","recommended_bw_khz","recommended_tx_dbm","estimated_range_km","airtime_ms","messages_per_hour_limit","estimated_battery_hours","data_rate_bps"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/zfs_capacity":{"get":{"summary":"Metadata for zfs_capacity","operationId":"get_zfs_capacity","tags":["homelab"],"responses":{"200":{"description":"Metadata for zfs_capacity","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate usable ZFS pool capacity for any RAID level including stripe, mirror, raidz1, raidz2, and raidz3. Computes raw capacity, parity overhead, data disk count, usable terabytes after ZFS metadata overhead (checksums, block pointers, uberblocks), and storage efficiency percentage. Essential for planning NAS builds, TrueNAS/ZFS server storage, and estimating how much usable space a given disk configuration will provide. Supports variable disk sizes and configurable metadata overhead.","operationId":"compute_zfs_capacity","tags":["homelab"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"disk_count":{"description":"Total number of physical disks in the pool","type":"number"},"disk_size_tb":{"description":"Size of each individual disk in terabytes","type":"number"},"raid_type":{"type":"string","enum":["stripe","mirror","raidz1","raidz2","raidz3"],"default":"raidz1","description":"ZFS RAID level: stripe (no redundancy), mirror (2-way), raidz1/2/3 (single/double/triple parity)"},"record_size_kb":{"type":"number","default":128,"description":"ZFS record size in kilobytes, affects compression and performance"},"metadata_overhead_pct":{"type":"number","default":3.2,"description":"Percentage of raw capacity consumed by ZFS metadata, checksums, and internal structures"}},"required":["disk_count","disk_size_tb"]}}}},"responses":{"200":{"description":"Computed result for zfs_capacity","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"raw_tb":{"description":"Total raw capacity across all disks in terabytes","type":"number"},"usable_tb":{"description":"Usable capacity after parity and metadata overhead in terabytes","type":"number"},"parity_disks":{"description":"Number of disks (or disk-equivalents) consumed by parity/mirroring","type":"number"},"data_disks":{"description":"Number of disks (or disk-equivalents) available for data storage","type":"number"},"efficiency_pct":{"description":"Storage efficiency as a percentage of raw capacity","type":"number"}},"required":["raw_tb","usable_tb","parity_disks","data_disks","efficiency_pct"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/zfs_ram":{"get":{"summary":"Metadata for zfs_ram","operationId":"get_zfs_ram","tags":["homelab"],"responses":{"200":{"description":"Metadata for zfs_ram","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate recommended RAM and ARC sizing for a ZFS storage pool based on workload type, pool size, deduplication status, and L2ARC cache size. Computes minimum and recommended RAM in gigabytes, ARC target size, and dedup table overhead. Accounts for workload-specific IO patterns: NAS (sequential, 1GB/TB), database (random, 2GB/TB), virtualization (mixed, 1.5GB/TB). Deduplication adds approximately 5GB per TB for the DDT. L2ARC index requires 1GB RAM per 10GB of L2ARC. Essential for TrueNAS, FreeNAS, and custom ZFS server builds.","operationId":"compute_zfs_ram","tags":["homelab"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pool_size_tb":{"description":"Total usable pool size in terabytes","type":"number"},"workload":{"type":"string","enum":["general","nas","database","virtualization"],"default":"general","description":"Primary workload type: general (mixed), nas (sequential reads/writes), database (random IO), virtualization (mixed random)"},"dedup_enabled":{"type":"boolean","default":false,"description":"Whether ZFS deduplication is enabled (significantly increases RAM requirements)"},"l2arc_size_gb":{"type":"number","default":0,"description":"Size of L2ARC (read cache SSD) in gigabytes; requires additional RAM for index"}},"required":["pool_size_tb"]}}}},"responses":{"200":{"description":"Computed result for zfs_ram","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"min_ram_gb":{"description":"Minimum recommended RAM in gigabytes for stable operation","type":"number"},"recommended_ram_gb":{"description":"Recommended RAM in gigabytes for optimal performance (2x minimum)","type":"number"},"arc_target_gb":{"description":"Target ARC (Adaptive Replacement Cache) size in gigabytes","type":"number"},"dedup_table_gb":{"description":"Estimated dedup table (DDT) RAM requirement in gigabytes","type":"number"},"notes":{"description":"Human-readable sizing rationale and recommendations","type":"string"}},"required":["min_ram_gb","recommended_ram_gb","arc_target_gb","dedup_table_gb","notes"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/tcp_throughput":{"get":{"summary":"Metadata for tcp_throughput","operationId":"get_tcp_throughput","tags":["homelab"],"responses":{"200":{"description":"Metadata for tcp_throughput","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate maximum TCP throughput using the Bandwidth-Delay Product (BDP) formula. Given link bandwidth and round-trip latency, computes the BDP (maximum in-flight data), achievable throughput with a given TCP window size, link utilization percentage, and recommended window size for full utilization. Critical for diagnosing slow transfers over high-latency links (WAN, VPN, satellite), tuning TCP buffers, and understanding why a 1Gbps link may only deliver 25Mbps with default 64KB windows. Applies to iperf testing, WAN optimization, and network capacity planning.","operationId":"compute_tcp_throughput","tags":["homelab"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"bandwidth_mbps":{"description":"Available link bandwidth in megabits per second","type":"number"},"rtt_ms":{"description":"Round-trip time (latency) in milliseconds","type":"number"},"window_size_kb":{"type":"number","default":64,"description":"TCP receive window size in kilobytes"},"mss_bytes":{"type":"number","default":1460,"description":"Maximum Segment Size in bytes (typically 1460 for Ethernet)"}},"required":["bandwidth_mbps","rtt_ms"]}}}},"responses":{"200":{"description":"Computed result for tcp_throughput","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"bdp_bytes":{"description":"Bandwidth-Delay Product in bytes: maximum data in flight","type":"number"},"bdp_kb":{"description":"Bandwidth-Delay Product in kilobytes","type":"number"},"max_throughput_mbps":{"description":"Maximum achievable TCP throughput in megabits per second given the window size","type":"number"},"window_sufficient":{"description":"Whether the current window size is large enough to fill the pipe","type":"boolean"},"recommended_window_kb":{"description":"Minimum window size in kilobytes needed to fully utilize the link","type":"number"},"utilization_pct":{"description":"Percentage of available bandwidth that can actually be used","type":"number"}},"required":["bdp_bytes","bdp_kb","max_throughput_mbps","window_sufficient","recommended_window_kb","utilization_pct"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/wireguard_mtu":{"get":{"summary":"Metadata for wireguard_mtu","operationId":"get_wireguard_mtu","tags":["homelab"],"responses":{"200":{"description":"Metadata for wireguard_mtu","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate the optimal MTU for a WireGuard VPN tunnel interface with a detailed overhead breakdown. Accounts for WireGuard header (32 bytes), outer IP header (20 bytes IPv4 or 40 bytes IPv6), UDP header (8 bytes), and optional PPPoE encapsulation (8 bytes). Prevents fragmentation and PMTUD black holes by computing the maximum inner packet size that fits within the physical link MTU. Essential for WireGuard setup on residential ISP connections (PPPoE), IPv6 tunnels, and any VPN where incorrect MTU causes slow or stalled connections.","operationId":"compute_wireguard_mtu","tags":["homelab"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"interface_mtu":{"type":"number","default":1500,"description":"MTU of the underlying physical or virtual network interface in bytes"},"ipv6":{"type":"boolean","default":false,"description":"Whether the outer (transport) IP header uses IPv6 (40 bytes) instead of IPv4 (20 bytes)"},"over_pppoe":{"type":"boolean","default":false,"description":"Whether the link uses PPPoE encapsulation (adds 8 bytes of overhead)"}},"required":[]}}}},"responses":{"200":{"description":"Computed result for wireguard_mtu","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"wireguard_mtu":{"description":"Optimal MTU to set on the WireGuard tunnel interface in bytes","type":"number"},"overhead_bytes":{"description":"Total encapsulation overhead in bytes subtracted from interface MTU","type":"number"},"breakdown":{"type":"object","properties":{"wireguard_header":{"description":"WireGuard protocol header overhead in bytes (always 32)","type":"number"},"ip_header":{"description":"Outer IP header size: 20 bytes for IPv4, 40 bytes for IPv6","type":"number"},"udp_header":{"description":"UDP header overhead in bytes (always 8)","type":"number"},"pppoe_header":{"description":"PPPoE encapsulation overhead in bytes (0 or 8)","type":"number"}},"required":["wireguard_header","ip_header","udp_header","pppoe_header"]}},"required":["wireguard_mtu","overhead_bytes","breakdown"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/subnet_calculator":{"get":{"summary":"Metadata for subnet_calculator","operationId":"get_subnet_calculator","tags":["homelab"],"responses":{"200":{"description":"Metadata for subnet_calculator","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate IPv4 subnet details from CIDR notation. Parses a CIDR block (e.g. 192.168.1.0/24) and returns the network address, broadcast address, subnet mask, wildcard mask, first and last usable host addresses, total and usable host counts, prefix length, and classful IP class (A/B/C/D/E). Essential for homelab network planning, VLAN segmentation, firewall rule design, and understanding address space allocation. Handles special cases for /31 point-to-point links (RFC 3021) and /32 host routes.","operationId":"compute_subnet_calculator","tags":["homelab"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cidr":{"description":"IPv4 address in CIDR notation, e.g. 192.168.1.0/24","type":"string"}},"required":["cidr"]}}}},"responses":{"200":{"description":"Computed result for subnet_calculator","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"network_address":{"description":"Network address of the subnet","type":"string"},"broadcast_address":{"description":"Broadcast address of the subnet","type":"string"},"subnet_mask":{"description":"Subnet mask in dotted decimal notation, e.g. 255.255.255.0","type":"string"},"wildcard_mask":{"description":"Wildcard (inverse) mask, e.g. 0.0.0.255","type":"string"},"first_usable":{"description":"First usable host address in the subnet","type":"string"},"last_usable":{"description":"Last usable host address in the subnet","type":"string"},"total_hosts":{"description":"Total number of addresses in the subnet including network and broadcast","type":"number"},"usable_hosts":{"description":"Number of usable host addresses (excluding network and broadcast)","type":"number"},"prefix_length":{"description":"CIDR prefix length, e.g. 24","type":"number"},"ip_class":{"description":"Classful IP address class: A, B, C, D (multicast), or E (reserved)","type":"string"}},"required":["network_address","broadcast_address","subnet_mask","wildcard_mask","first_usable","last_usable","total_hosts","usable_hosts","prefix_length","ip_class"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/raid_iops":{"get":{"summary":"Metadata for raid_iops","operationId":"get_raid_iops","tags":["homelab"],"responses":{"200":{"description":"Metadata for raid_iops","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Estimate RAID array IOPS performance and latency for ZFS and traditional RAID configurations. Calculates maximum read IOPS, write IOPS (accounting for write penalty/amplification per RAID level), blended IOPS for a configurable read/write workload mix, and rough per-disk latency. Supports stripe, mirror, raidz1, raidz2, and raidz3. Use with HDD IOPS (~150), SATA SSD (~50000), or NVMe SSD (~100000) to compare RAID topologies and plan storage performance for databases, VMs, media servers, and general homelab NAS workloads. Chains from zfs_capacity.data_disks for integrated capacity+performance planning.","operationId":"compute_raid_iops","tags":["homelab"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"disk_count":{"description":"Total number of physical disks in the array","type":"number"},"disk_iops":{"type":"number","default":150,"description":"IOPS per individual disk. Typical values: HDD ~150, SATA SSD ~50000, NVMe SSD ~100000"},"raid_type":{"type":"string","enum":["stripe","mirror","raidz1","raidz2","raidz3"],"default":"raidz1","description":"RAID level: stripe (no redundancy, write penalty 1), mirror (write penalty 2), raidz1 (write penalty 2), raidz2 (write penalty 3), raidz3 (write penalty 4)"},"read_pct":{"type":"number","default":70,"description":"Percentage of workload that is reads (0-100). Typical: 70 for mixed, 90 for read-heavy, 30 for write-heavy"}},"required":["disk_count"]}}}},"responses":{"200":{"description":"Computed result for raid_iops","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"read_iops":{"description":"Maximum read IOPS: disk_count * disk_iops","type":"number"},"write_iops":{"description":"Maximum write IOPS: disk_count * disk_iops / write_penalty","type":"number"},"blended_iops":{"description":"Effective IOPS for the given read/write mix: (read_pct * read_iops + write_pct * write_iops) / 100","type":"number"},"write_penalty":{"description":"Write amplification factor for the chosen RAID level","type":"number"},"estimated_latency_ms":{"description":"Rough per-disk latency estimate in milliseconds: 1000 / (blended_iops / disk_count)","type":"number"}},"required":["read_iops","write_iops","blended_iops","write_penalty","estimated_latency_ms"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/power_cost":{"get":{"summary":"Metadata for power_cost","operationId":"get_power_cost","tags":["homelab"],"responses":{"200":{"description":"Metadata for power_cost","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate total power consumption, electricity cost, and circuit requirements for a homelab. Enter each device's wattage to get daily/monthly/yearly kWh and cost at your local electricity rate. Accounts for cooling overhead via PUE (Power Usage Effectiveness). Shows amperage draw at 120V and 240V and warns if you exceed the NEC 80% continuous load limit on a 15A breaker. Essential for budgeting homelab operating expenses and ensuring your electrical panel can handle the load. Chain output total_watts into cooling_btu for heat load sizing.","operationId":"compute_power_cost","tags":["homelab"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"devices":{"description":"List of devices with their wattage","type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Optional label for the device (e.g. 'Dell R730')"},"watts":{"description":"Power draw of the device in watts","type":"number"}},"required":["watts"]}},"hours_per_day":{"type":"number","default":24,"description":"Hours per day the devices are running"},"kwh_rate_cents":{"type":"number","default":12,"description":"Electricity cost in cents per kilowatt-hour"},"pue":{"type":"number","default":1.2,"description":"Power Usage Effectiveness — ratio of total facility power to IT equipment power. 1.0 means no cooling overhead, 1.2 is typical for a home server closet, 1.5+ for poorly ventilated spaces"}},"required":["devices"]}}}},"responses":{"200":{"description":"Computed result for power_cost","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"total_watts":{"description":"Sum of all device wattages before PUE adjustment","type":"number"},"total_with_pue_watts":{"description":"Total power draw including cooling overhead (watts * PUE)","type":"number"},"daily_kwh":{"description":"Daily energy consumption in kilowatt-hours","type":"number"},"monthly_kwh":{"description":"Monthly energy consumption in kilowatt-hours (30.44 day average)","type":"number"},"yearly_kwh":{"description":"Yearly energy consumption in kilowatt-hours (365.25 day average)","type":"number"},"monthly_cost_usd":{"description":"Estimated monthly electricity cost in USD","type":"number"},"yearly_cost_usd":{"description":"Estimated yearly electricity cost in USD","type":"number"},"amps_at_120v":{"description":"Current draw at 120V (typical North American outlet)","type":"number"},"amps_at_240v":{"description":"Current draw at 240V (typical European / high-power outlet)","type":"number"},"breaker_15a_pct":{"description":"Percentage of a 15A / 120V circuit used. NEC requires continuous loads stay under 80% (12A)","type":"number"}},"required":["total_watts","total_with_pue_watts","daily_kwh","monthly_kwh","yearly_kwh","monthly_cost_usd","yearly_cost_usd","amps_at_120v","amps_at_240v","breaker_15a_pct"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/cooling_btu":{"get":{"summary":"Metadata for cooling_btu","operationId":"get_cooling_btu","tags":["homelab"],"responses":{"200":{"description":"Metadata for cooling_btu","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Estimate the cooling load (BTU/hr) for a homelab or server closet based on equipment wattage, room dimensions, insulation quality, and solar exposure. All electrical power converts to heat — this tool calculates equipment heat output, envelope heat gain through walls, and solar gain to produce a total BTU/hr cooling requirement. Recommends AC tonnage, mini-split sizing (rounded to standard 6K BTU increments), and exhaust fan CFM for ventilation-only cooling. Use after power_cost to size cooling for your homelab room.","operationId":"compute_cooling_btu","tags":["homelab"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"total_watts":{"description":"Total power consumption in watts — all power becomes heat","type":"number"},"room_length_ft":{"type":"number","default":10,"description":"Room length in feet"},"room_width_ft":{"type":"number","default":10,"description":"Room width in feet"},"room_height_ft":{"type":"number","default":8,"description":"Room ceiling height in feet"},"insulation":{"type":"string","enum":["poor","average","good","excellent"],"default":"average","description":"Wall/ceiling insulation quality: poor (uninsulated garage), average (standard drywall), good (insulated interior), excellent (server room with vapor barrier)"},"ambient_temp_f":{"type":"number","default":75,"description":"Ambient temperature outside the room in degrees Fahrenheit"},"target_temp_f":{"type":"number","default":72,"description":"Desired room temperature in degrees Fahrenheit"},"sun_exposure":{"type":"string","enum":["none","partial","full"],"default":"partial","description":"Solar heat gain: none (interior/basement room), partial (one exterior wall with window), full (multiple sun-facing windows)"}},"required":["total_watts"]}}}},"responses":{"200":{"description":"Computed result for cooling_btu","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"equipment_btu":{"description":"Heat generated by equipment in BTU/hr (watts * 3.412)","type":"number"},"envelope_btu":{"description":"Heat gain/loss through walls based on room size, insulation, and delta-T","type":"number"},"total_btu":{"description":"Total cooling load in BTU/hr (equipment + envelope + sun)","type":"number"},"ac_tons":{"description":"Cooling capacity needed in tons of refrigeration (1 ton = 12,000 BTU/hr)","type":"number"},"mini_split_btu_recommended":{"description":"Recommended mini-split size rounded up to nearest 6,000 BTU increment","type":"number"},"exhaust_cfm_needed":{"description":"Exhaust fan airflow needed in cubic feet per minute if using ventilation instead of AC","type":"number"},"will_overheat":{"description":"True if total heat load is positive and no cooling is provided","type":"boolean"}},"required":["equipment_btu","envelope_btu","total_btu","ac_tons","mini_split_btu_recommended","exhaust_cfm_needed","will_overheat"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/rack_capacity":{"get":{"summary":"Metadata for rack_capacity","operationId":"get_rack_capacity","tags":["homelab"],"responses":{"200":{"description":"Metadata for rack_capacity","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Quick rack space and weight sizing calculator for homelab and small data center racks. Enter your devices with their height in rack units, weight, and wattage to get total utilization, remaining free space, weight totals in lbs and kg, and recommended PDU count based on the NEC 80% continuous load rule (1920W per 20A/120V PDU). Estimates cable management overhead at 2U per 10U of installed gear. Outputs total_watts that chains into power_cost and cooling_btu for full infrastructure planning.","operationId":"compute_rack_capacity","tags":["homelab"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rack_units":{"type":"number","default":42,"description":"Total rack height in rack units (standard is 42U)"},"devices":{"description":"List of devices to place in the rack","type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Optional label for the device (e.g. 'Dell R730', 'Patch Panel')"},"height_u":{"description":"Height of the device in rack units (U)","type":"number"},"weight_lbs":{"type":"number","default":0,"description":"Weight of the device in pounds"},"watts":{"type":"number","default":0,"description":"Power draw of the device in watts"}},"required":["height_u"]}}},"required":["devices"]}}}},"responses":{"200":{"description":"Computed result for rack_capacity","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"used_u":{"description":"Total rack units consumed by devices","type":"number"},"free_u":{"description":"Remaining empty rack units","type":"number"},"utilization_pct":{"description":"Percentage of rack space used by devices","type":"number"},"total_weight_lbs":{"description":"Total weight of all devices in pounds","type":"number"},"total_weight_kg":{"description":"Total weight of all devices in kilograms","type":"number"},"total_watts":{"description":"Total power draw of all devices in watts","type":"number"},"recommended_pdu_count":{"description":"Recommended number of PDUs (each PDU = 80% of 20A/120V = 1920W)","type":"number"},"overhead_u":{"description":"Estimated cable management overhead in rack units (2U per 10U of gear)","type":"number"},"effective_free_u":{"description":"Free rack units after subtracting cable management overhead","type":"number"}},"required":["used_u","free_u","utilization_pct","total_weight_lbs","total_weight_kg","total_watts","recommended_pdu_count","overhead_u","effective_free_u"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/network_bandwidth":{"get":{"summary":"Metadata for network_bandwidth","operationId":"get_network_bandwidth","tags":["homelab"],"responses":{"200":{"description":"Metadata for network_bandwidth","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Plan and validate network link capacity for homelab workloads. Determine whether a 1G, 2.5G, 10G, or faster link can handle your concurrent streams (VMs, backups, media, iSCSI). Calculates effective bandwidth after TCP/IP overhead, total required bandwidth, utilization percentage, and remaining headroom. Flags saturation at 80% utilization and identifies whether the bottleneck is network or storage. Provides a 1TB transfer time reference and recommends the next link speed upgrade if your current link is saturated. Useful for planning NIC upgrades, switch purchases, and storage network design.","operationId":"compute_network_bandwidth","tags":["homelab"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"link_speed_gbps":{"description":"Network link speed in gigabits per second (e.g. 1, 2.5, 5, 10, 25, 40, 100)","type":"number"},"concurrent_streams":{"type":"number","default":1,"description":"Number of concurrent data streams / transfers"},"stream_bandwidth_mbps":{"type":"number","default":100,"description":"Bandwidth required per stream in megabits per second"},"protocol_overhead_pct":{"type":"number","default":3,"description":"TCP/IP protocol overhead as a percentage (typically 3-5% for TCP, ~1% for UDP)"},"storage_throughput_mbps":{"type":"number","description":"Maximum storage read/write throughput in megabits per second. If provided, checks whether storage is the bottleneck"}},"required":["link_speed_gbps"]}}}},"responses":{"200":{"description":"Computed result for network_bandwidth","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"effective_bandwidth_mbps":{"description":"Usable bandwidth after protocol overhead in Mbps","type":"number"},"required_bandwidth_mbps":{"description":"Total bandwidth required by all streams in Mbps","type":"number"},"utilization_pct":{"description":"Percentage of effective bandwidth used by all streams","type":"number"},"headroom_mbps":{"description":"Remaining bandwidth after all streams (negative means oversubscribed)","type":"number"},"saturated":{"description":"True if utilization exceeds 80% — link is effectively saturated","type":"boolean"},"bottleneck":{"description":"Identified bottleneck: 'storage', 'network', or 'none'","type":"string"},"time_to_transfer_1tb_hours":{"description":"Time to transfer 1 TB over the effective bandwidth, in hours","type":"number"},"recommended_link_speed_gbps":{"type":"number","nullable":true,"description":"Suggested next link speed upgrade if saturated, null if current link is sufficient"}},"required":["effective_bandwidth_mbps","required_bandwidth_mbps","utilization_pct","headroom_mbps","saturated","bottleneck","time_to_transfer_1tb_hours","recommended_link_speed_gbps"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/thermal_enclosure":{"get":{"summary":"Metadata for thermal_enclosure","operationId":"get_thermal_enclosure","tags":["homelab"],"responses":{"200":{"description":"Metadata for thermal_enclosure","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Estimate steady-state thermal behaviour of a rectangular enclosure (server rack, electronics housing, equipment cabinet) using a lumped-parameter energy balance with natural-convection and radiation correlations, or forced-flow air energy balance. Accepts enclosure dimensions, heat source positions and wattages, and airflow configuration. Returns temperature extremes, estimated hotspot location, airflow velocity summary, and overall thermal resistance. Runs instantly in-worker; a full CFD container backend is planned for mesh-level detail.","operationId":"compute_thermal_enclosure","tags":["homelab"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"length_m":{"description":"Enclosure length (X) in metres","type":"number"},"width_m":{"description":"Enclosure width (Y) in metres","type":"number"},"height_m":{"description":"Enclosure height (Z) in metres","type":"number"},"heat_sources":{"description":"Heat sources inside the enclosure","type":"array","items":{"type":"object","properties":{"x_m":{"description":"X position in metres from enclosure origin","type":"number"},"y_m":{"description":"Y position in metres","type":"number"},"z_m":{"description":"Z position in metres","type":"number"},"watts":{"description":"Heat dissipation in watts","type":"number"},"label":{"type":"string","description":"Optional label (e.g. 'CPU', 'PSU')"}},"required":["x_m","y_m","z_m","watts"]}},"flow_type":{"description":"Airflow type","type":"string","enum":["natural_convection","forced"]},"inlet_velocity_ms":{"type":"number","description":"Inlet air velocity in m/s (required for forced flow)"},"inlet_position":{"type":"string","enum":["front_bottom","front_center","side_bottom"],"default":"front_bottom","description":"Inlet location"},"outlet_position":{"type":"string","enum":["rear_top","rear_center","top_rear"],"default":"rear_top","description":"Outlet location"},"ambient_temp_c":{"type":"number","default":25,"description":"Ambient air temperature in Celsius"},"mesh_density":{"type":"string","enum":["coarse","medium","fine"],"default":"medium","description":"Mesh density — coarse (~50K cells), medium (~200K), fine (~500K)"}},"required":["length_m","width_m","height_m","heat_sources","flow_type"]}}}},"responses":{"200":{"description":"Computed result for thermal_enclosure","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"max_temp_c":{"description":"Maximum temperature in the enclosure (°C)","type":"number"},"min_temp_c":{"description":"Minimum temperature (°C)","type":"number"},"avg_temp_c":{"description":"Volume-averaged temperature (°C)","type":"number"},"hotspot_location":{"type":"object","properties":{"x_m":{"description":"X coordinate of hotspot in metres","type":"number"},"y_m":{"description":"Y coordinate of hotspot in metres","type":"number"},"z_m":{"description":"Z coordinate of hotspot in metres","type":"number"}},"required":["x_m","y_m","z_m"]},"max_velocity_ms":{"description":"Peak airflow velocity (m/s)","type":"number"},"avg_velocity_ms":{"description":"Average airflow velocity (m/s)","type":"number"},"thermal_resistance_cw":{"description":"Overall thermal resistance (°C/W)","type":"number"},"total_heat_w":{"description":"Total heat load (W)","type":"number"},"mesh_cells":{"description":"Number of mesh cells used","type":"number"},"solver":{"description":"OpenFOAM solver used","type":"string"},"iterations":{"description":"Number of solver iterations to convergence","type":"number"},"runtime_ms":{"description":"Simulation wall-clock time in milliseconds","type":"number"},"warnings":{"description":"Any solver warnings","type":"array","items":{"type":"string"}}},"required":["max_temp_c","min_temp_c","avg_temp_c","hotspot_location","max_velocity_ms","avg_velocity_ms","thermal_resistance_cw","total_heat_w","mesh_cells","solver","iterations","runtime_ms","warnings"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/heatsink_cfd":{"get":{"summary":"Metadata for heatsink_cfd","operationId":"get_heatsink_cfd","tags":["homelab"],"responses":{"200":{"description":"Metadata for heatsink_cfd","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Analyze a forced-convection fin-array heatsink using established channel-flow correlations (developing laminar Nusselt, fin efficiency tanh(mH)/mH, parallel-plate friction). Computes base-to-air thermal resistance, pressure drop, base and fin-tip temperatures, fin efficiency, and the optimal fin spacing for the given airflow. Use for heatsink selection and first-pass optimization in electronics cooling. Runs instantly in-worker; mesh-level CFD via container backend is planned.","operationId":"compute_heatsink_cfd","tags":["homelab"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"base_length_m":{"description":"Heatsink base length in metres","type":"number"},"base_width_m":{"description":"Heatsink base width in metres","type":"number"},"base_height_m":{"description":"Base plate thickness in metres","type":"number"},"fin_count":{"description":"Number of fins","type":"number"},"fin_height_m":{"description":"Fin height in metres","type":"number"},"fin_thickness_m":{"description":"Fin thickness in metres","type":"number"},"airflow_velocity_ms":{"description":"Incoming airflow velocity in m/s","type":"number"},"heat_load_w":{"description":"Total heat load applied to base in watts","type":"number"},"ambient_temp_c":{"type":"number","default":25,"description":"Ambient air temperature in Celsius"},"mesh_density":{"type":"string","enum":["coarse","medium","fine"],"default":"medium","description":"Mesh density"}},"required":["base_length_m","base_width_m","base_height_m","fin_count","fin_height_m","fin_thickness_m","airflow_velocity_ms","heat_load_w"]}}}},"responses":{"200":{"description":"Computed result for heatsink_cfd","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"thermal_resistance_cw":{"description":"Thermal resistance from base to air (°C/W)","type":"number"},"pressure_drop_pa":{"description":"Pressure drop across the heatsink (Pa)","type":"number"},"max_base_temp_c":{"description":"Maximum base temperature (°C)","type":"number"},"avg_base_temp_c":{"description":"Average base temperature (°C)","type":"number"},"fin_tip_temp_c":{"description":"Average fin tip temperature (°C)","type":"number"},"optimal_fin_spacing_m":{"description":"Suggested optimal fin spacing for this airflow (m)","type":"number"},"fin_efficiency":{"description":"Fin efficiency (0-1)","type":"number"},"mesh_cells":{"description":"Mesh cell count","type":"number"},"runtime_ms":{"description":"Simulation time in ms","type":"number"},"warnings":{"description":"Solver warnings","type":"array","items":{"type":"string"}}},"required":["thermal_resistance_cw","pressure_drop_pa","max_base_temp_c","avg_base_temp_c","fin_tip_temp_c","optimal_fin_spacing_m","fin_efficiency","mesh_cells","runtime_ms","warnings"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/pcb_thermal":{"get":{"summary":"Metadata for pcb_thermal","operationId":"get_pcb_thermal","tags":["homelab"],"responses":{"200":{"description":"Metadata for pcb_thermal","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Estimate PCB component temperatures by solving a thermal resistance network (thermal↔electrical analogy) with the built-in MNA solver. Each component gets a junction node (package θjb from a typical-datasheet table), a local board node coupled to its neighbours through in-plane FR4/copper conduction, and convection to ambient. Computes per-component junction and case temperatures, board extremes, and flags max-junction violations. Runs instantly in-worker; mesh-level CFD via container backend is planned.","operationId":"compute_pcb_thermal","tags":["homelab"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"board_length_m":{"description":"Board length in metres","type":"number"},"board_width_m":{"description":"Board width in metres","type":"number"},"board_thickness_m":{"type":"number","default":0.0016,"description":"Board thickness in metres (default 1.6mm FR4)"},"components":{"description":"Components on the board","type":"array","items":{"type":"object","properties":{"x_m":{"description":"X position on board in metres","type":"number"},"y_m":{"description":"Y position on board in metres","type":"number"},"footprint":{"description":"Package footprint (e.g. QFP-48, BGA-256, SOT-23, TO-220)","type":"string"},"tdp_w":{"description":"Thermal design power in watts","type":"number"},"label":{"type":"string","description":"Component label (e.g. 'U1', 'CPU')"},"max_junction_temp_c":{"type":"number","description":"Maximum junction temperature (°C) for violation checking"}},"required":["x_m","y_m","footprint","tdp_w"]}},"airflow_velocity_ms":{"type":"number","default":0,"description":"Airflow velocity in m/s (0 = natural convection)"},"ambient_temp_c":{"type":"number","default":25,"description":"Ambient temperature in Celsius"},"mesh_density":{"type":"string","enum":["coarse","medium","fine"],"default":"medium","description":"Mesh density"}},"required":["board_length_m","board_width_m","components"]}}}},"responses":{"200":{"description":"Computed result for pcb_thermal","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"max_board_temp_c":{"description":"Maximum board surface temperature (°C)","type":"number"},"avg_board_temp_c":{"description":"Average board temperature (°C)","type":"number"},"component_temps":{"description":"Per-component thermal results","type":"array","items":{"type":"object","properties":{"label":{"description":"Component label","type":"string"},"junction_temp_c":{"description":"Estimated junction temperature (°C)","type":"number"},"case_temp_c":{"description":"Case/surface temperature (°C)","type":"number"},"violation":{"description":"True if junction temp exceeds max_junction_temp_c","type":"boolean"}},"required":["label","junction_temp_c","case_temp_c","violation"]}},"total_heat_w":{"description":"Total heat dissipation (W)","type":"number"},"violations":{"description":"Number of components exceeding thermal limits","type":"number"},"mesh_cells":{"description":"Mesh cell count","type":"number"},"runtime_ms":{"description":"Simulation time in ms","type":"number"},"warnings":{"description":"Solver warnings","type":"array","items":{"type":"string"}}},"required":["max_board_temp_c","avg_board_temp_c","component_temps","total_heat_w","violations","mesh_cells","runtime_ms","warnings"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/battery_life":{"get":{"summary":"Metadata for battery_life","operationId":"get_battery_life","tags":["power"],"responses":{"200":{"description":"Metadata for battery_life","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates battery runtime and energy capacity given cell capacity in mAh, nominal voltage, and average current draw. Accounts for real-world discharge efficiency (Peukert-adjacent derating) to produce effective capacity, total energy in Wh, and runtime in hours and days. Useful for IoT sensor node planning, portable device design, UPS hold-up estimation, and solar battery bank cycling analysis. Outputs feed into solar_sizing (battery_kwh) and ups_runtime (battery_wh) for system-level calculations.","operationId":"compute_battery_life","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"capacity_mah":{"description":"Battery capacity in milliamp-hours (mAh)","type":"number"},"voltage":{"type":"number","default":3.7,"description":"Nominal battery voltage (V), default 3.7 for Li-ion"},"current_draw_ma":{"description":"Average current draw in milliamps (mA)","type":"number"},"efficiency":{"type":"number","default":0.85,"description":"Discharge efficiency factor (0-1), accounts for conversion losses and derating, default 0.85"}},"required":["capacity_mah","current_draw_ma"]}}}},"responses":{"200":{"description":"Computed result for battery_life","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"runtime_hours":{"description":"Estimated runtime in hours","type":"number"},"runtime_days":{"description":"Estimated runtime in days","type":"number"},"energy_wh":{"description":"Total battery energy in watt-hours (capacity_mah * voltage / 1000)","type":"number"},"effective_capacity_mah":{"description":"Effective usable capacity after efficiency derating (mAh)","type":"number"}},"required":["runtime_hours","runtime_days","energy_wh","effective_capacity_mah"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/wire_gauge":{"get":{"summary":"Metadata for wire_gauge","operationId":"get_wire_gauge","tags":["power"],"responses":{"200":{"description":"Metadata for wire_gauge","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Determines the minimum AWG (American Wire Gauge) conductor size for a given current, voltage, one-way cable distance, and maximum allowable voltage drop percentage. Supports copper and aluminum conductors. Computes round-trip resistance, actual voltage drop in volts and percent, and wire cross-sectional area. Essential for DC solar runs, battery bank wiring, EV charging circuits, and low-voltage landscape lighting. NEC recommends 3% max drop for branch circuits and 5% total including feeder. Outputs the smallest AWG that satisfies the drop constraint.","operationId":"compute_wire_gauge","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"current_amps":{"description":"Load current in amperes (A)","type":"number"},"voltage":{"description":"System voltage (V)","type":"number"},"distance_m":{"description":"One-way conductor distance in meters","type":"number"},"max_drop_pct":{"type":"number","default":3,"description":"Maximum allowable voltage drop as percentage (default 3%)"},"conductor":{"type":"string","enum":["copper","aluminum"],"default":"copper","description":"Conductor material: copper or aluminum"}},"required":["current_amps","voltage","distance_m"]}}}},"responses":{"200":{"description":"Computed result for wire_gauge","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"recommended_awg":{"description":"Recommended AWG gauge number (smaller number = thicker wire)","type":"number"},"recommended_awg_label":{"description":"Human-readable AWG label (e.g. '10' or '0000 (4/0)')","type":"string"},"actual_drop_pct":{"description":"Actual voltage drop percentage with recommended gauge","type":"number"},"actual_drop_v":{"description":"Actual voltage drop in volts","type":"number"},"resistance_per_m":{"description":"Resistance per meter of the recommended gauge (ohm/m)","type":"number"},"wire_area_mm2":{"description":"Cross-sectional area of recommended gauge in mm^2","type":"number"},"insufficient":{"description":"True if even the largest AWG (4/0) cannot meet the voltage drop target","type":"boolean"}},"required":["recommended_awg","recommended_awg_label","actual_drop_pct","actual_drop_v","resistance_per_m","wire_area_mm2","insufficient"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/solar_sizing":{"get":{"summary":"Metadata for solar_sizing","operationId":"get_solar_sizing","tags":["power"],"responses":{"200":{"description":"Metadata for solar_sizing","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Sizes an off-grid solar power system by calculating the number of panels and battery bank capacity required for a given daily energy consumption. Accounts for system losses (inverter, wiring, charge controller), battery depth-of-discharge, and autonomy days for cloudy weather. Outputs panel count, total panel wattage, battery capacity in kWh and Ah, and minimum charge controller amperage (with 25% safety margin per NEC 690.8). Supports 12V, 24V, and 48V system architectures. Use for cabin, RV, telecom tower, and remote IoT deployments.","operationId":"compute_solar_sizing","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"daily_kwh":{"description":"Daily energy consumption in kilowatt-hours (kWh)","type":"number"},"peak_sun_hours":{"type":"number","default":5,"description":"Average peak sun hours per day for your location (hours)"},"panel_watts":{"type":"number","default":400,"description":"Rated wattage per solar panel (W)"},"system_voltage":{"default":48,"description":"Battery bank system voltage: 12, 24, or 48 V"},"battery_autonomy_days":{"type":"number","default":2,"description":"Number of days the battery bank should sustain load without solar input"},"dod":{"type":"number","default":0.8,"description":"Battery depth of discharge (0-1), default 0.8 for LiFePO4"},"system_efficiency":{"type":"number","default":0.85,"description":"Overall system efficiency (0-1), accounts for inverter, wiring, and controller losses"}},"required":["daily_kwh"]}}}},"responses":{"200":{"description":"Computed result for solar_sizing","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"panels_needed":{"description":"Number of solar panels required (rounded up)","type":"number"},"total_panel_watts":{"description":"Total installed panel wattage (W)","type":"number"},"battery_kwh":{"description":"Required battery bank capacity in kWh (before DoD)","type":"number"},"battery_ah":{"description":"Required battery bank capacity in amp-hours at system voltage","type":"number"},"charge_controller_amps":{"description":"Minimum charge controller current rating in amps (with 25% margin)","type":"number"},"daily_solar_kwh":{"description":"Daily solar energy needed after accounting for system losses (kWh)","type":"number"}},"required":["panels_needed","total_panel_watts","battery_kwh","battery_ah","charge_controller_amps","daily_solar_kwh"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/ups_runtime":{"get":{"summary":"Metadata for ups_runtime","operationId":"get_ups_runtime","tags":["power"],"responses":{"200":{"description":"Metadata for ups_runtime","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Estimates UPS (Uninterruptible Power Supply) backup runtime from battery specifications and connected load. Takes VA rating, watt rating, load in watts, and battery configuration (count, voltage, amp-hours) to compute effective stored energy after efficiency losses and runtime in minutes and hours. Detects overload conditions when load exceeds the UPS watt rating. Calculates power factor from VA/W ratings. Ideal for server rack planning, homelab power budgeting, network closet UPS selection, and graceful shutdown timer configuration.","operationId":"compute_ups_runtime","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"va_rating":{"description":"UPS VA (volt-ampere) rating","type":"number"},"watt_rating":{"description":"UPS real power (watt) rating","type":"number"},"load_watts":{"description":"Connected load in watts","type":"number"},"battery_count":{"type":"number","default":1,"description":"Number of batteries in the UPS"},"battery_voltage":{"type":"number","default":12,"description":"Voltage per battery (V)"},"battery_ah":{"type":"number","default":9,"description":"Capacity per battery in amp-hours (Ah)"},"efficiency":{"type":"number","default":0.9,"description":"Inverter/conversion efficiency (0-1), default 0.9"}},"required":["va_rating","watt_rating","load_watts"]}}}},"responses":{"200":{"description":"Computed result for ups_runtime","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"runtime_minutes":{"description":"Estimated backup runtime in minutes","type":"number"},"runtime_hours":{"description":"Estimated backup runtime in hours","type":"number"},"load_pct":{"description":"Load as percentage of UPS watt capacity","type":"number"},"battery_wh":{"description":"Total battery energy in watt-hours (before efficiency)","type":"number"},"effective_wh":{"description":"Usable battery energy after efficiency losses (Wh)","type":"number"},"pf":{"description":"Power factor (watt_rating / va_rating)","type":"number"},"overloaded":{"description":"True if load exceeds UPS watt rating","type":"boolean"}},"required":["runtime_minutes","runtime_hours","load_pct","battery_wh","effective_wh","pf","overloaded"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/mah_to_wh":{"get":{"summary":"Metadata for mah_to_wh","operationId":"get_mah_to_wh","tags":["power"],"responses":{"200":{"description":"Metadata for mah_to_wh","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Converts battery capacity from milliamp-hours (mAh) to watt-hours (Wh), kilowatt-hours (kWh), and joules (J) given the nominal cell voltage. This is the most common battery unit conversion needed when comparing cells rated in mAh (e.g. 18650, AA) against energy budgets specified in Wh. Essential for airline lithium battery compliance (100 Wh limit for carry-on), solar battery bank sizing, and UPS capacity planning. Echoes back input values for easy chaining into battery_life, solar_sizing, and ups_runtime tools.","operationId":"compute_mah_to_wh","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"capacity_mah":{"description":"Battery capacity in milliamp-hours (mAh)","type":"number"},"voltage_v":{"description":"Nominal battery voltage (V)","type":"number"}},"required":["capacity_mah","voltage_v"]}}}},"responses":{"200":{"description":"Computed result for mah_to_wh","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"wh":{"description":"Energy in watt-hours","type":"number"},"kwh":{"description":"Energy in kilowatt-hours","type":"number"},"joules":{"description":"Energy in joules","type":"number"},"mah":{"description":"Input capacity echoed back (mAh)","type":"number"},"voltage_v":{"description":"Input voltage echoed back (V)","type":"number"}},"required":["wh","kwh","joules","mah","voltage_v"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/watts_to_amps":{"get":{"summary":"Metadata for watts_to_amps","operationId":"get_watts_to_amps","tags":["power"],"responses":{"200":{"description":"Metadata for watts_to_amps","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Converts electrical power in watts to current in amps (and milliamps) for a given voltage, using the DC power formula P = V * I. Also computes the implied load resistance via Ohm's law (R = V / I) assuming a purely resistive load. This is the most common electrical conversion for circuit design, fuse selection, wire sizing, and breaker rating. Use the output amps value to feed into wire_gauge for conductor sizing or voltage_drop for cable loss analysis. Covers DC circuits; for AC with power factor, adjust watts to true power first.","operationId":"compute_watts_to_amps","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"watts":{"description":"Power in watts (W)","type":"number"},"voltage_v":{"description":"Voltage in volts (V)","type":"number"}},"required":["watts","voltage_v"]}}}},"responses":{"200":{"description":"Computed result for watts_to_amps","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"amps":{"description":"Current in amperes (A)","type":"number"},"milliamps":{"description":"Current in milliamperes (mA)","type":"number"},"voltage_v":{"description":"Input voltage echoed back (V)","type":"number"},"watts":{"description":"Input power echoed back (W)","type":"number"},"implied_resistance_ohm":{"description":"Implied load resistance in ohms assuming resistive load (V/I)","type":"number"}},"required":["amps","milliamps","voltage_v","watts","implied_resistance_ohm"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/voltage_drop":{"get":{"summary":"Metadata for voltage_drop","operationId":"get_voltage_drop","tags":["power"],"responses":{"200":{"description":"Metadata for voltage_drop","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates voltage drop across a conductor run given current, wire length, AWG gauge, system voltage, and conductor material (copper or aluminum). Computes round-trip resistance, voltage drop in volts and percent, voltage at the load end, power dissipated in the wire, and NEC compliance flags (3% max for branch circuits, 5% max for feeders). Use this after wire_gauge to verify a specific gauge meets requirements, or to evaluate an existing installation. Critical for solar panel string wiring, EV charger circuits, low-voltage lighting, and any long DC or AC cable run where resistive losses matter.","operationId":"compute_voltage_drop","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"current_amps":{"description":"Load current in amperes (A)","type":"number"},"wire_length_m":{"description":"One-way wire length in meters","type":"number"},"wire_gauge_awg":{"description":"Wire gauge in AWG (e.g. 14, 12, 10; use negative for large gauges: -3 = 4/0)","type":"number"},"voltage_v":{"description":"System voltage (V)","type":"number"},"conductor":{"type":"string","enum":["copper","aluminum"],"default":"copper","description":"Conductor material: copper or aluminum"}},"required":["current_amps","wire_length_m","wire_gauge_awg","voltage_v"]}}}},"responses":{"200":{"description":"Computed result for voltage_drop","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"voltage_drop_v":{"description":"Voltage drop across the conductor run (V)","type":"number"},"voltage_drop_pct":{"description":"Voltage drop as a percentage of system voltage","type":"number"},"voltage_at_load_v":{"description":"Voltage at the load end (V)","type":"number"},"resistance_ohm":{"description":"Total round-trip conductor resistance (ohm)","type":"number"},"power_loss_w":{"description":"Power dissipated as heat in the conductor (W)","type":"number"},"compliant":{"description":"True if voltage drop is within NEC limits (<=3% branch, <=5% feeder)","type":"boolean"}},"required":["voltage_drop_v","voltage_drop_pct","voltage_at_load_v","resistance_ohm","power_loss_w","compliant"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/battery_charge_time":{"get":{"summary":"Metadata for battery_charge_time","operationId":"get_battery_charge_time","tags":["power"],"responses":{"200":{"description":"Metadata for battery_charge_time","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Estimates battery charge time given capacity in mAh, charge current in mA, charger efficiency, and initial state of charge. Accounts for real-world charging losses (typically 80-90% efficient) to produce time in hours and minutes, energy required in Wh (at an optional voltage, default 3.7V for Li-ion), and the C-rate of the charge. Useful for solar charge controller sizing, USB charging time estimation, lead-acid float charging, and EV battery planning. The C-rate output helps verify the charge current is within safe limits (typically 0.5C-1C for Li-ion). Chain from solar_sizing charge_controller_amps to size a solar charging system end-to-end.","operationId":"compute_battery_charge_time","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"capacity_mah":{"description":"Total battery capacity in milliamp-hours (mAh)","type":"number"},"charge_current_ma":{"description":"Charge current in milliamps (mA)","type":"number"},"efficiency":{"type":"number","default":0.85,"description":"Charger efficiency factor (0-1), default 0.85"},"initial_soc_pct":{"type":"number","default":0,"description":"Initial state of charge as percentage (0-100), default 0 (empty)"},"voltage_v":{"type":"number","default":3.7,"description":"Nominal battery voltage for energy calculation (V), default 3.7 for Li-ion"}},"required":["capacity_mah","charge_current_ma"]}}}},"responses":{"200":{"description":"Computed result for battery_charge_time","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"charge_time_hours":{"description":"Estimated charge time in hours","type":"number"},"charge_time_minutes":{"description":"Estimated charge time in minutes","type":"number"},"energy_required_wh":{"description":"Energy required to charge at nominal voltage (Wh)","type":"number"},"c_rate":{"description":"C-rate of the charge (charge_current / capacity)","type":"number"}},"required":["charge_time_hours","charge_time_minutes","energy_required_wh","c_rate"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/solar_load_audit":{"get":{"summary":"Metadata for solar_load_audit","operationId":"get_solar_load_audit","tags":["power"],"responses":{"200":{"description":"Metadata for solar_load_audit","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates total daily energy consumption from an appliance list — the critical first step before sizing solar panels or batteries. Enter each appliance with its wattage, hours of daily use, and quantity. Outputs total daily kWh (with configurable safety margin for surge and inrush current), peak simultaneous wattage, and recommended inverter VA rating per NEC 125% continuous load rule. Feeds directly into solar_sizing (daily_kwh) and battery_autonomy (daily_kwh). Essential for residential, RV, cabin, and off-grid system design.","operationId":"compute_solar_load_audit","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"appliances":{"description":"List of appliances with wattage, hours per day, and quantity","type":"array","items":{"type":"object","properties":{"name":{"description":"Appliance name (e.g. 'Refrigerator', 'LED Light')","type":"string"},"watts":{"description":"Power consumption in watts (W)","type":"number"},"hours_per_day":{"description":"Average hours of use per day","type":"number"},"quantity":{"type":"number","default":1,"description":"Number of identical units, default 1"}},"required":["name","watts","hours_per_day"]}},"safety_margin_pct":{"type":"number","default":20,"description":"Safety margin percentage to account for surge/inrush current, default 20%"}},"required":["appliances"]}}}},"responses":{"200":{"description":"Computed result for solar_load_audit","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"total_daily_wh":{"description":"Total daily energy consumption in watt-hours (Wh)","type":"number"},"total_daily_kwh":{"description":"Total daily energy consumption in kilowatt-hours (kWh)","type":"number"},"with_margin_kwh":{"description":"Daily kWh including safety margin","type":"number"},"peak_watts":{"description":"Peak simultaneous wattage if all appliances run at once (W)","type":"number"},"recommended_inverter_va":{"description":"Recommended inverter size in VA (peak watts * 1.25 per NEC)","type":"number"},"appliance_count":{"description":"Total number of appliance entries","type":"number"},"largest_load_watts":{"description":"Wattage of the single largest appliance (W)","type":"number"}},"required":["total_daily_wh","total_daily_kwh","with_margin_kwh","peak_watts","recommended_inverter_va","appliance_count","largest_load_watts"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/solar_roi":{"get":{"summary":"Metadata for solar_roi","operationId":"get_solar_roi","tags":["power"],"responses":{"200":{"description":"Metadata for solar_roi","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates solar system return on investment, payback period, and levelized cost of energy (LCOE). Models year-by-year savings accounting for panel degradation, utility rate inflation, federal Investment Tax Credit (ITC), state rebates, and annual maintenance. Outputs net cost after incentives, payback year, total lifetime savings, ROI percentage, and LCOE in cents/kWh. Essential for residential and commercial solar financial analysis, installer proposals, and comparing solar vs. grid economics over a 25-year system lifetime.","operationId":"compute_solar_roi","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"system_cost_usd":{"description":"Total installed system cost in USD","type":"number"},"system_size_kw":{"description":"System size in kilowatts (kW)","type":"number"},"annual_production_kwh":{"description":"Estimated annual energy production in kWh (from PVWatts or system_size_kw * peak_sun_hours * 365 * 0.80)","type":"number"},"electricity_rate_cents":{"type":"number","default":15,"description":"Current electricity rate in cents per kWh, default 15"},"annual_rate_increase_pct":{"type":"number","default":3,"description":"Annual utility rate increase percentage, default 3%"},"federal_itc_pct":{"type":"number","default":30,"description":"Federal Investment Tax Credit percentage, default 30% (US ITC)"},"state_rebate_usd":{"type":"number","default":0,"description":"State or local rebate amount in USD, default 0"},"annual_degradation_pct":{"type":"number","default":0.5,"description":"Annual panel degradation rate, default 0.5% per year"},"annual_maintenance_usd":{"type":"number","default":100,"description":"Annual maintenance cost in USD, default $100"},"system_lifetime_years":{"type":"number","default":25,"description":"System lifetime in years, default 25"}},"required":["system_cost_usd","system_size_kw","annual_production_kwh"]}}}},"responses":{"200":{"description":"Computed result for solar_roi","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"net_cost_usd":{"description":"Net system cost after federal ITC and state rebates (USD)","type":"number"},"payback_years":{"description":"Number of years to recoup net cost from savings","type":"number"},"total_savings_usd":{"description":"Total cumulative savings over system lifetime (USD)","type":"number"},"roi_pct":{"description":"Return on investment percentage over system lifetime","type":"number"},"lcoe_cents_per_kwh":{"description":"Levelized cost of energy in cents per kWh","type":"number"},"year_1_savings_usd":{"description":"First year net savings (USD)","type":"number"},"year_25_savings_usd":{"description":"Final year net savings (USD), or last year if lifetime < 25","type":"number"},"lifetime_production_kwh":{"description":"Total energy produced over system lifetime (kWh)","type":"number"}},"required":["net_cost_usd","payback_years","total_savings_usd","roi_pct","lcoe_cents_per_kwh","year_1_savings_usd","year_25_savings_usd","lifetime_production_kwh"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/battery_autonomy":{"get":{"summary":"Metadata for battery_autonomy","operationId":"get_battery_autonomy","tags":["power"],"responses":{"200":{"description":"Metadata for battery_autonomy","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates how many days a battery bank can sustain loads without solar input — critical for off-grid and backup power sizing. Accounts for depth of discharge, round-trip efficiency (lithium vs lead-acid), minimum state of charge, and optional partial solar contribution during cloudy weather. Outputs autonomy in days and hours, usable capacity, and daily deficit. Use with avg_solar_contribution_pct = 0 for worst-case (no sun) scenarios, or 20-30% for realistic cloudy-day modeling. Chains from solar_sizing (battery_kwh) and solar_load_audit (daily_kwh).","operationId":"compute_battery_autonomy","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"daily_kwh":{"description":"Daily energy consumption in kilowatt-hours (kWh)","type":"number"},"battery_kwh":{"description":"Total installed battery capacity in kWh","type":"number"},"dod":{"type":"number","default":0.8,"description":"Depth of discharge (0-1), default 0.8 for lithium"},"round_trip_efficiency":{"type":"number","default":0.9,"description":"Battery round-trip efficiency (0-1), default 0.90 for lithium, use 0.80 for lead-acid"},"min_soc_pct":{"type":"number","default":20,"description":"Minimum state of charge percentage, default 20%"},"avg_solar_contribution_pct":{"type":"number","default":0,"description":"Average solar contribution during autonomy period (0-100%), default 0 for worst-case"}},"required":["daily_kwh","battery_kwh"]}}}},"responses":{"200":{"description":"Computed result for battery_autonomy","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"usable_kwh":{"description":"Usable battery capacity after DoD and efficiency losses (kWh)","type":"number"},"autonomy_days":{"description":"Number of days the battery can sustain loads","type":"number"},"autonomy_hours":{"description":"Number of hours the battery can sustain loads","type":"number"},"daily_deficit_kwh":{"description":"Effective daily energy need after solar contribution (kWh)","type":"number"},"battery_cycles_per_year":{"description":"Estimated full discharge cycles per year (365 / autonomy_days)","type":"number"}},"required":["usable_kwh","autonomy_days","autonomy_hours","daily_deficit_kwh","battery_cycles_per_year"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/string_sizing":{"get":{"summary":"Metadata for string_sizing","operationId":"get_string_sizing","tags":["power"],"responses":{"200":{"description":"Metadata for string_sizing","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates optimal solar panel string and MPPT configuration based on panel electrical specs, inverter/charge-controller MPPT limits, and site temperature extremes. Applies temperature coefficients to determine Voc at minimum temperature (cold) and Vmp at maximum temperature (hot), then computes the safe range of panels per string, maximum parallel strings, and total array wattage. Prevents over-voltage damage in winter and under-voltage MPPT dropout in summer. Essential for NEC 690.7 compliant residential and commercial solar design.","operationId":"compute_string_sizing","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"panel_voc":{"description":"Panel open circuit voltage (Voc) at STC in volts","type":"number"},"panel_vmp":{"description":"Panel maximum power voltage (Vmp) at STC in volts","type":"number"},"panel_isc":{"description":"Panel short circuit current (Isc) at STC in amps","type":"number"},"panel_imp":{"description":"Panel maximum power current (Imp) at STC in amps","type":"number"},"mppt_vmax":{"description":"Maximum MPPT input voltage in volts","type":"number"},"mppt_vmin":{"description":"Minimum MPPT start/operating voltage in volts","type":"number"},"mppt_imax":{"description":"Maximum MPPT input current in amps","type":"number"},"temp_min_c":{"type":"number","default":-10,"description":"Minimum expected site temperature in Celsius, default -10"},"temp_max_c":{"type":"number","default":60,"description":"Maximum expected cell temperature in Celsius, default 60"},"temp_coeff_voc_pct_per_c":{"type":"number","default":-0.3,"description":"Voc temperature coefficient in %/C (negative for silicon), default -0.30"}},"required":["panel_voc","panel_vmp","panel_isc","panel_imp","mppt_vmax","mppt_vmin","mppt_imax"]}}}},"responses":{"200":{"description":"Computed result for string_sizing","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"max_panels_per_string":{"description":"Maximum panels per string (limited by Voc at cold temp)","type":"number"},"min_panels_per_string":{"description":"Minimum panels per string (to meet MPPT Vmin at hot temp)","type":"number"},"recommended_panels_per_string":{"description":"Recommended panels per string (uses max for best output)","type":"number"},"max_parallel_strings":{"description":"Maximum parallel strings (limited by MPPT Imax)","type":"number"},"total_panels":{"description":"Total panels in the array (strings * panels per string)","type":"number"},"array_watts":{"description":"Total array power at maximum power point (W)","type":"number"},"voc_cold_per_string":{"description":"String Voc at minimum temperature (V)","type":"number"},"vmp_hot_per_string":{"description":"String Vmp at maximum temperature (V)","type":"number"},"isc_total":{"description":"Total short circuit current from all parallel strings (A)","type":"number"}},"required":["max_panels_per_string","min_panels_per_string","recommended_panels_per_string","max_parallel_strings","total_panels","array_watts","voc_cold_per_string","vmp_hot_per_string","isc_total"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/generator_offset":{"get":{"summary":"Metadata for generator_offset","operationId":"get_generator_offset","tags":["power"],"responses":{"200":{"description":"Metadata for generator_offset","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Compares total cost of ownership between a fuel generator and a solar+battery system over a configurable time horizon. Calculates yearly and cumulative costs for generator-only, solar-only (amortized), and hybrid scenarios. Accounts for fuel cost, generator consumption rate, maintenance intervals, solar system amortization, and battery coverage. Outputs yearly costs, total savings, breakeven year, solar coverage percentage, and generator hours saved. Essential for off-grid site planning, remote telecom towers, construction sites, and rural electrification proposals.","operationId":"compute_generator_offset","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"generator_fuel_cost_per_gallon":{"type":"number","default":3.5,"description":"Fuel cost per gallon in USD, default $3.50"},"generator_consumption_gph":{"type":"number","default":1,"description":"Generator fuel consumption in gallons per hour at load, default 1.0"},"generator_hours_per_day":{"type":"number","default":8,"description":"Generator runtime hours per day, default 8"},"generator_maintenance_per_1000hrs":{"type":"number","default":200,"description":"Generator maintenance cost per 1000 running hours in USD, default $200"},"solar_system_cost_usd":{"description":"Total solar+battery system cost in USD","type":"number"},"solar_daily_kwh_produced":{"description":"Daily solar energy production in kWh","type":"number"},"battery_kwh":{"type":"number","default":0,"description":"Battery storage capacity in kWh (0 means no battery, generator needed at night), default 0"},"daily_kwh_needed":{"description":"Total daily energy requirement in kWh","type":"number"},"years_to_compare":{"type":"number","default":10,"description":"Number of years to compare, default 10"}},"required":["solar_system_cost_usd","solar_daily_kwh_produced","daily_kwh_needed"]}}}},"responses":{"200":{"description":"Computed result for generator_offset","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"generator_yearly_cost_usd":{"description":"Annual generator cost (fuel + maintenance) in USD","type":"number"},"generator_total_cost_usd":{"description":"Total generator cost over comparison period in USD","type":"number"},"solar_yearly_cost_usd":{"description":"Annualized solar system cost (amortized + maintenance) in USD","type":"number"},"solar_total_cost_usd":{"description":"Total solar cost over comparison period in USD","type":"number"},"savings_usd":{"description":"Total savings of solar over generator in USD (negative means generator is cheaper)","type":"number"},"savings_pct":{"description":"Percentage savings of solar vs generator","type":"number"},"breakeven_year":{"description":"Year when solar cumulative cost becomes cheaper than generator (0 if never)","type":"number"},"solar_coverage_pct":{"description":"Percentage of daily energy needs covered by solar+battery","type":"number"},"generator_hours_saved_per_year":{"description":"Generator hours eliminated per year by solar","type":"number"}},"required":["generator_yearly_cost_usd","generator_total_cost_usd","solar_yearly_cost_usd","solar_total_cost_usd","savings_usd","savings_pct","breakeven_year","solar_coverage_pct","generator_hours_saved_per_year"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/wire_ampacity":{"get":{"summary":"Metadata for wire_ampacity","operationId":"get_wire_ampacity","tags":["power"],"responses":{"200":{"description":"Metadata for wire_ampacity","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Determine minimum wire gauge using NEC Table 310.16 ampacity ratings with full derating. Looks up base ampacity for copper or aluminum conductors at 60°C, 75°C, or 90°C insulation rating, then applies NEC 310.15(C)(1) ambient temperature correction and NEC 310.15(C)(2) conductor count adjustment. Automatically applies the 125% continuous load factor per NEC 210.20(A) when flagged. Returns the minimum AWG that meets the derated requirement, plus a comparison table of all gauges. Different from wire_gauge which focuses on voltage drop — use both together for complete wire sizing. Essential for residential panels, commercial feeders, solar arrays, and EV charging installations.","operationId":"compute_wire_ampacity","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"current_amps":{"description":"Required circuit current in amperes. Use 125% of continuous load per NEC 210.20(A).","type":"number"},"conductor":{"type":"string","enum":["copper","aluminum"],"default":"copper","description":"Conductor material. Copper has higher ampacity; aluminum is lighter and cheaper for large feeders."},"insulation":{"type":"string","enum":["60","75","90"],"default":"75","description":"Insulation temperature rating in °C. 60=TW/UF-B, 75=THW/THWN/XHHW (most common), 90=THHN/THWN-2."},"ambient_temp_c":{"type":"number","default":30,"description":"Ambient temperature in °C. NEC base is 30°C. Higher temps require derating. Typical: 30 (indoor), 40 (attic/hot), 45+ (rooftop conduit)."},"conductors_in_raceway":{"type":"number","default":3,"description":"Number of current-carrying conductors in a single raceway or cable. More than 3 requires derating per NEC 310.15(C)(2)."},"continuous_load":{"type":"boolean","default":true,"description":"Whether the load operates continuously (3+ hours). NEC requires 125% sizing for continuous loads. Set false for intermittent loads."}},"required":["current_amps"]}}}},"responses":{"200":{"description":"Computed result for wire_ampacity","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"minimum_awg":{"description":"Minimum AWG wire gauge that meets the derated ampacity requirement.","type":"number"},"minimum_awg_label":{"description":"Human-readable AWG label (e.g. '4/0', '12', '2').","type":"string"},"base_ampacity_a":{"description":"Base ampacity from NEC 310.16 before any derating, in amperes.","type":"number"},"derated_ampacity_a":{"description":"Final ampacity after applying ambient temperature and conductor count correction factors, in amperes.","type":"number"},"required_ampacity_a":{"description":"Ampacity required to carry the load (includes 125% factor if continuous).","type":"number"},"ambient_correction":{"description":"Ambient temperature correction factor applied (1.0 at 30°C).","type":"number"},"conductor_count_correction":{"description":"Conductor count correction factor (1.0 for 3 or fewer).","type":"number"},"insulation_label":{"description":"Insulation rating description.","type":"string"},"all_gauges":{"description":"All available gauges with their ampacities for comparison.","type":"array","items":{"type":"object","properties":{"awg":{"description":"AWG gauge number","type":"number"},"awg_label":{"description":"Human-readable AWG label","type":"string"},"base_ampacity_a":{"description":"NEC 310.16 base ampacity","type":"number"},"derated_ampacity_a":{"description":"Ampacity after derating","type":"number"},"sufficient":{"description":"Whether this gauge meets the requirement","type":"boolean"}},"required":["awg","awg_label","base_ampacity_a","derated_ampacity_a","sufficient"]}}},"required":["minimum_awg","minimum_awg_label","base_ampacity_a","derated_ampacity_a","required_ampacity_a","ambient_correction","conductor_count_correction","insulation_label","all_gauges"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/inverter_sizing":{"get":{"summary":"Metadata for inverter_sizing","operationId":"get_inverter_sizing","tags":["power"],"responses":{"200":{"description":"Metadata for inverter_sizing","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Size a DC-to-AC inverter for off-grid solar, battery backup, or mobile power systems. Computes the required continuous VA rating from total load watts and power factor, estimates surge capacity for motor-starting loads (3-7x rated power), applies NEC-recommended 20% derating for continuous operation, and selects the nearest standard inverter size. Also calculates DC input current at the system voltage for cable and fuse sizing. Chain from solar_load_audit to get peak_watts and largest_load_watts, then chain to wire_gauge or wire_ampacity to size the DC cables. Essential for off-grid cabins, RV/van builds, emergency backup, and solar+battery installations.","operationId":"compute_inverter_sizing","tags":["power"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"continuous_watts":{"description":"Total continuous load in watts. Sum of all appliances that may run simultaneously. Chain from solar_load_audit.peak_watts.","type":"number"},"surge_watts":{"type":"number","description":"Peak surge/starting load in watts. Motors and compressors draw 3-7x rated watts on startup. If omitted, estimated as 3x the largest single load or 2x continuous, whichever is greater."},"largest_load_watts":{"type":"number","description":"Wattage of the single largest appliance. Used to estimate surge if surge_watts is not provided. Chain from solar_load_audit.largest_load_watts."},"system_voltage":{"type":"string","enum":["12","24","48"],"default":"48","description":"DC system voltage. 12V for small/mobile, 24V for medium, 48V for large residential/commercial. Higher voltage = lower current = thinner cables."},"power_factor":{"type":"number","default":0.8,"description":"Power factor (0.5-1.0). Resistive loads (heaters, lights) are ~1.0. Motor loads (fridge, AC, pump) are 0.6-0.8. Mixed loads typically 0.8."},"efficiency":{"type":"number","default":0.9,"description":"Inverter efficiency (0.5-1.0). Good pure-sine inverters are 0.90-0.95. Modified-sine are 0.85-0.90. Budget units may be lower."},"derating_pct":{"type":"number","default":20,"description":"Derating percentage for temperature, altitude, and safety margin. NEC recommends 20% (80% continuous rating). Range 0-50%."}},"required":["continuous_watts"]}}}},"responses":{"200":{"description":"Computed result for inverter_sizing","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"required_continuous_va":{"description":"Required continuous VA rating accounting for power factor: continuous_watts / power_factor.","type":"number"},"required_surge_va":{"description":"Required surge/peak VA capacity for motor starting loads.","type":"number"},"derated_continuous_va":{"description":"Continuous VA after applying derating factor. The inverter must be rated at or above this value.","type":"number"},"recommended_size_watts":{"description":"Nearest standard inverter size (watts) that meets the derated requirement.","type":"number"},"dc_current_continuous_a":{"description":"Continuous DC input current draw at system voltage: VA / (voltage * efficiency). Sizes the DC wiring and fuses.","type":"number"},"dc_current_surge_a":{"description":"Peak DC input current during surge. Sizes the DC fuse and battery cable.","type":"number"},"battery_cable_note":{"description":"Guidance on DC cable sizing based on the continuous current draw.","type":"string"},"surge_margin_pct":{"description":"How much surge headroom the recommended inverter provides above the estimated surge requirement.","type":"number"},"efficiency_loss_watts":{"description":"Power lost to inverter inefficiency at continuous load, in watts.","type":"number"}},"required":["required_continuous_va","required_surge_va","derated_continuous_va","recommended_size_watts","dc_current_continuous_a","dc_current_surge_a","battery_cable_note","surge_margin_pct","efficiency_loss_watts"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/pcb_layout":{"get":{"summary":"Metadata for pcb_layout","operationId":"get_pcb_layout","tags":["pcb"],"responses":{"200":{"description":"Metadata for pcb_layout","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Turn a SPICE netlist into a fab-ready 2-layer PCB: assigns real footprints (0805, TO-92, DO-35, DIP-8, headers, LED, radial-cap), auto-places components (connectivity-aware; or use your own placement), routes a 2-layer maze router with vias, and VERIFIES the result with DRC (clearance/crossing checks) and ERC (union-find copper connectivity proven against the netlist). Returns the board, routing stats + honest unrouted-net list, DRC violations, ERC net status, a 'manufacturable' flag (true only when DRC+ERC clean and everything routed), SVG layers (top/bottom copper, silkscreen, drill, assembly), and optional Gerber RS-274X + Excellon drill files. Same netlist you simulate with spice_simulate — design, verify, and lay out an entire board through the tool layer. Supply a 'placement' array for production-quality boards; the auto-router is a first-pass best-of-N-seeds.","operationId":"compute_pcb_layout","tags":["pcb"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"netlist":{"description":"SPICE netlist (same format as spice_simulate). Components + nets are extracted; .model/.tran/etc. ignored.","type":"string"},"placement":{"type":"array","items":{"type":"object","properties":{"ref":{"description":"Component reference (e.g. 'Q1')","type":"string"},"x":{"description":"X position of component center in mm","type":"number"},"y":{"description":"Y position in mm","type":"number"},"rot":{"type":"number","description":"Rotation in degrees (0/90/180/270)"}},"required":["ref","x","y"]},"description":"Optional manual placement; omit for connectivity-aware auto-placement (best of N seeds)."},"board":{"type":"object","properties":{"w":{"type":"number"},"h":{"type":"number"}},"required":["w","h"],"description":"Optional board size in mm; auto-sized if omitted"},"clearance_mm":{"type":"number","default":0.2,"description":"Minimum copper clearance in mm"},"trace_width_mm":{"type":"number","default":0.25,"description":"Routing trace width in mm"},"gnd_pour":{"type":"boolean","default":false,"description":"Treat GND as a bottom-layer pour (unions all GND pads for ERC)"},"gerber":{"type":"boolean","default":false,"description":"Also return Gerber RS-274X + Excellon drill files"}},"required":["netlist"]}}}},"responses":{"200":{"description":"Computed result for pcb_layout","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"board":{},"components":{},"nets":{},"routing":{},"drc":{},"erc":{},"manufacturable":{"type":"boolean"},"layers_svg":{},"gerber":{},"warnings":{"type":"array","items":{"type":"string"}}},"required":["board","components","nets","routing","drc","erc","manufacturable","layers_svg","warnings"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/voltage_divider":{"get":{"summary":"Metadata for voltage_divider","operationId":"get_voltage_divider","tags":["pcb"],"responses":{"200":{"description":"Metadata for voltage_divider","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates output voltage, current draw, and power dissipation for a resistive voltage divider. Given an input voltage Vin and two resistor values R1 (upper) and R2 (lower), computes Vout = Vin * R2 / (R1 + R2), divider current, individual resistor power dissipation, and the division ratio. Essential for biasing circuits, level shifting, ADC input scaling, and feedback networks. Use before trace_width to size traces for divider current, or chain from a power supply output to verify signal levels.","operationId":"compute_voltage_divider","tags":["pcb"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"vin":{"description":"Input voltage in volts (V). Must be positive.","type":"number"},"r1_ohm":{"description":"Upper resistor value in ohms (R1), connected between Vin and Vout node.","type":"number"},"r2_ohm":{"description":"Lower resistor value in ohms (R2), connected between Vout node and ground.","type":"number"}},"required":["vin","r1_ohm","r2_ohm"]}}}},"responses":{"200":{"description":"Computed result for voltage_divider","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"vout":{"description":"Output voltage in volts at the R1-R2 junction.","type":"number"},"current_ma":{"description":"Current through the divider in milliamps (mA).","type":"number"},"power_r1_mw":{"description":"Power dissipated by R1 in milliwatts (mW).","type":"number"},"power_r2_mw":{"description":"Power dissipated by R2 in milliwatts (mW).","type":"number"},"ratio":{"description":"Voltage division ratio R2/(R1+R2), dimensionless 0-1.","type":"number"},"total_power_mw":{"description":"Total power dissipated by the divider in milliwatts (mW).","type":"number"}},"required":["vout","current_ma","power_r1_mw","power_r2_mw","ratio","total_power_mw"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/rc_filter":{"get":{"summary":"Metadata for rc_filter","operationId":"get_rc_filter","tags":["pcb"],"responses":{"200":{"description":"Metadata for rc_filter","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Computes the cutoff frequency, time constant, impedance, and phase shift of a first-order RC filter. Supports both lowpass and highpass topologies. The cutoff frequency is f = 1/(2*pi*R*C) where the signal is attenuated by 3 dB. The time constant tau = R*C governs transient response — the capacitor reaches 63.2% of its final value after one tau. Use for anti-aliasing before ADCs, DC blocking, noise filtering, and signal conditioning. Chain from voltage_divider to design filtered bias networks.","operationId":"compute_rc_filter","tags":["pcb"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"resistance_ohm":{"description":"Resistance in ohms (R). The resistive element of the RC filter.","type":"number"},"capacitance_f":{"description":"Capacitance in farads (C). The capacitive element of the RC filter.","type":"number"},"filter_type":{"type":"string","enum":["lowpass","highpass"],"default":"lowpass","description":"Filter topology: 'lowpass' (R then C to ground) or 'highpass' (C then R to ground)."}},"required":["resistance_ohm","capacitance_f"]}}}},"responses":{"200":{"description":"Computed result for rc_filter","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"cutoff_freq_hz":{"description":"Cutoff frequency (-3 dB point) in hertz.","type":"number"},"cutoff_freq_khz":{"description":"Cutoff frequency in kilohertz for convenience.","type":"number"},"time_constant_s":{"description":"RC time constant (tau) in seconds.","type":"number"},"time_constant_ms":{"description":"RC time constant in milliseconds.","type":"number"},"impedance_at_cutoff_ohm":{"description":"Total impedance magnitude at the cutoff frequency in ohms. Equals R * sqrt(2) for a first-order RC filter.","type":"number"},"phase_at_cutoff_deg":{"description":"Phase shift at the cutoff frequency in degrees. -45 for lowpass, +45 for highpass.","type":"number"}},"required":["cutoff_freq_hz","cutoff_freq_khz","time_constant_s","time_constant_ms","impedance_at_cutoff_ohm","phase_at_cutoff_deg"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/lc_resonance":{"get":{"summary":"Metadata for lc_resonance","operationId":"get_lc_resonance","tags":["pcb"],"responses":{"200":{"description":"Metadata for lc_resonance","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates the resonant frequency of an LC circuit, along with optional Q factor and bandwidth when series resistance is provided. The resonant frequency f0 = 1/(2*pi*sqrt(L*C)) is where inductive and capacitive reactances cancel. Used for designing tank circuits, oscillators, bandpass filters, and antenna matching networks. If resistance R is given, computes quality factor Q = (1/R)*sqrt(L/C) and 3 dB bandwidth = f0/Q. Chain into impedance_match to design matching networks at the resonant frequency.","operationId":"compute_lc_resonance","tags":["pcb"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"inductance_h":{"description":"Inductance in henries (H). The inductive element of the LC circuit.","type":"number"},"capacitance_f":{"description":"Capacitance in farads (F). The capacitive element of the LC circuit.","type":"number"},"resistance_ohm":{"type":"number","description":"Optional series resistance in ohms for Q factor and bandwidth calculation. Omit for ideal LC analysis."}},"required":["inductance_h","capacitance_f"]}}}},"responses":{"200":{"description":"Computed result for lc_resonance","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"resonant_freq_hz":{"description":"Resonant frequency in hertz.","type":"number"},"resonant_freq_mhz":{"description":"Resonant frequency in megahertz for convenience.","type":"number"},"angular_freq_rad":{"description":"Angular resonant frequency in radians per second (omega_0 = 2*pi*f0).","type":"number"},"impedance_at_resonance_ohm":{"type":"number","nullable":true,"description":"Impedance at resonance in ohms. Equals the series resistance R if provided; null if ideal (no R)."},"q_factor":{"type":"number","nullable":true,"description":"Quality factor Q = (1/R)*sqrt(L/C). Null if no resistance provided."},"bandwidth_hz":{"type":"number","nullable":true,"description":"3 dB bandwidth in hertz (f0/Q). Null if no resistance provided."}},"required":["resonant_freq_hz","resonant_freq_mhz","angular_freq_rad","impedance_at_resonance_ohm","q_factor","bandwidth_hz"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/impedance_match":{"get":{"summary":"Metadata for impedance_match","operationId":"get_impedance_match","tags":["pcb"],"responses":{"200":{"description":"Metadata for impedance_match","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Designs an L-network impedance matching circuit between two real impedances at a given frequency. Computes the required shunt and series reactive components (inductor and capacitor) to transform the source impedance to the load impedance. The network Q factor is sqrt(Rh/Rl - 1) where Rh is the higher impedance. Topology is automatically selected: the shunt element is placed across the higher impedance side. Essential for antenna matching, amplifier input/output matching, and maximizing power transfer. Chain from lc_resonance to match at a tank circuit's resonant frequency.","operationId":"compute_impedance_match","tags":["pcb"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"source_ohm":{"description":"Source impedance in ohms (real, resistive). Must differ from load impedance.","type":"number"},"load_ohm":{"description":"Load impedance in ohms (real, resistive). Must differ from source impedance.","type":"number"},"freq_mhz":{"description":"Design frequency in megahertz for component value calculation.","type":"number"}},"required":["source_ohm","load_ohm","freq_mhz"]}}}},"responses":{"200":{"description":"Computed result for impedance_match","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"q_factor":{"description":"Network Q factor = sqrt(Rh/Rl - 1), where Rh is the higher impedance.","type":"number"},"topology":{"description":"Description of the L-network arrangement (which side gets shunt vs series element).","type":"string"},"shunt_component":{"type":"object","properties":{"type":{"description":"Component type: inductor or capacitor.","type":"string","enum":["inductor","capacitor"]},"value_h":{"type":"number","description":"Inductance value in henries, present when type is inductor."},"value_f":{"type":"number","description":"Capacitance value in farads, present when type is capacitor."},"reactance_ohm":{"description":"Reactance magnitude in ohms at the design frequency.","type":"number"}},"required":["type","reactance_ohm"]},"series_component":{"type":"object","properties":{"type":{"description":"Component type: inductor or capacitor.","type":"string","enum":["inductor","capacitor"]},"value_h":{"type":"number","description":"Inductance value in henries, present when type is inductor."},"value_f":{"type":"number","description":"Capacitance value in farads, present when type is capacitor."},"reactance_ohm":{"description":"Reactance magnitude in ohms at the design frequency.","type":"number"}},"required":["type","reactance_ohm"]}},"required":["q_factor","topology","shunt_component","series_component"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/trace_width":{"get":{"summary":"Metadata for trace_width","operationId":"get_trace_width","tags":["pcb"],"responses":{"200":{"description":"Metadata for trace_width","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates the minimum PCB trace width for a given current using the IPC-2221 standard formula. The IPC-2221 empirical equation relates current capacity to cross-sectional area and temperature rise: I = k * dT^0.44 * A^0.725, where k=0.048 for external layers and k=0.024 for internal layers. Supports configurable copper weight (oz/ft^2) and temperature rise. Also computes approximate DC resistance per centimeter. Essential for power delivery, high-current motor drivers, and ensuring PCB reliability. Chain from voltage_divider or impedance_match to verify trace sizing for computed currents.","operationId":"compute_trace_width","tags":["pcb"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"current_amps":{"description":"Required current capacity in amperes (A).","type":"number"},"copper_oz":{"type":"number","default":1,"description":"Copper weight in ounces per square foot. 1 oz/ft^2 = 1.37 mil (34.8 um) thickness. Common values: 0.5, 1, 2."},"temp_rise_c":{"type":"number","default":10,"description":"Allowable temperature rise above ambient in degrees Celsius. IPC-2221 standard uses 10, 20, or 30 C."},"layer":{"type":"string","enum":["external","internal"],"default":"external","description":"PCB layer type. External layers dissipate heat better (k=0.048); internal layers use k=0.024."}},"required":["current_amps"]}}}},"responses":{"200":{"description":"Computed result for trace_width","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"width_mil":{"description":"Required trace width in mils (thousandths of an inch).","type":"number"},"width_mm":{"description":"Required trace width in millimeters.","type":"number"},"area_mil2":{"description":"Required cross-sectional area in square mils.","type":"number"},"resistance_per_cm_mohm":{"description":"Approximate DC resistance per centimeter of trace in milliohms, using copper resistivity.","type":"number"}},"required":["width_mil","width_mm","area_mil2","resistance_per_cm_mohm"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/ohms_law":{"get":{"summary":"Metadata for ohms_law","operationId":"get_ohms_law","tags":["pcb"],"responses":{"200":{"description":"Metadata for ohms_law","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Solves Ohm's Law and the power equation given any two of four electrical quantities: voltage (V), current (I), resistance (R), and power (P). Uses V=IR, P=VI, P=I^2R, and P=V^2/R to derive the missing two values. Fundamental for every circuit design task: sizing resistors, estimating current draw, checking power dissipation, and verifying component ratings. Chain into led_resistor for LED circuits or voltage_divider for bias networks.","operationId":"compute_ohms_law","tags":["pcb"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"voltage_v":{"type":"number","description":"Voltage in volts (V). Provide exactly 2 of the 4 parameters."},"current_a":{"type":"number","description":"Current in amps (A). Provide exactly 2 of the 4 parameters."},"resistance_ohm":{"type":"number","description":"Resistance in ohms. Provide exactly 2 of the 4 parameters."},"power_w":{"type":"number","description":"Power in watts (W). Provide exactly 2 of the 4 parameters."}},"required":[]}}}},"responses":{"200":{"description":"Computed result for ohms_law","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"voltage_v":{"description":"Voltage in volts (V).","type":"number"},"current_a":{"description":"Current in amps (A).","type":"number"},"resistance_ohm":{"description":"Resistance in ohms.","type":"number"},"power_w":{"description":"Power in watts (W).","type":"number"}},"required":["voltage_v","current_a","resistance_ohm","power_w"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/resistor_color_code":{"get":{"summary":"Metadata for resistor_color_code","operationId":"get_resistor_color_code","tags":["pcb"],"responses":{"200":{"description":"Metadata for resistor_color_code","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Decodes 4-band or 5-band resistor color codes into resistance value, tolerance, and min/max range. Accepts an ordered array of color names (left-to-right as printed on the resistor body). Supports standard EIA color codes including gold and silver multiplier/tolerance bands. Outputs the nominal resistance in ohms, a human-readable formatted value (e.g. '4.7kΩ'), tolerance percentage, and the min/max resistance range. Chain into ohms_law or led_resistor for circuit analysis.","operationId":"compute_resistor_color_code","tags":["pcb"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"bands":{"description":"Array of 4 or 5 color band names from left to right. 4-band: [digit1, digit2, multiplier, tolerance]. 5-band: [digit1, digit2, digit3, multiplier, tolerance]."}},"required":["bands"]}}}},"responses":{"200":{"description":"Computed result for resistor_color_code","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"resistance_ohm":{"description":"Resistance value in ohms.","type":"number"},"resistance_formatted":{"description":"Human-readable resistance string, e.g. '4.7kΩ'.","type":"string"},"tolerance_pct":{"description":"Tolerance in percent.","type":"number"},"min_ohm":{"description":"Minimum resistance within tolerance.","type":"number"},"max_ohm":{"description":"Maximum resistance within tolerance.","type":"number"},"band_count":{"description":"Number of bands (4 or 5).","type":"number"}},"required":["resistance_ohm","resistance_formatted","tolerance_pct","min_ohm","max_ohm","band_count"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/led_resistor":{"get":{"summary":"Metadata for led_resistor","operationId":"get_led_resistor","tags":["pcb"],"responses":{"200":{"description":"Metadata for led_resistor","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates the current-limiting resistor for driving one or more LEDs in series from a DC supply. Computes the exact resistance from R = (Vsupply - n*Vf) / I, then selects the nearest E24 standard resistor value. Reports the actual current with the standard resistor, power dissipation, and voltage across the resistor. Supports series LED strings by specifying led_count. Validates that supply voltage exceeds total forward voltage. Chain from ohms_law for power budgeting or into trace_width for PCB layout.","operationId":"compute_led_resistor","tags":["pcb"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"supply_voltage_v":{"description":"Supply voltage in volts (V). Must be positive.","type":"number"},"led_forward_v":{"type":"number","default":2,"description":"LED forward voltage in volts (V). Defaults to 2.0V (typical red LED)."},"led_current_ma":{"type":"number","default":20,"description":"Desired LED current in milliamps (mA). Defaults to 20mA."},"led_count":{"type":"number","default":1,"description":"Number of LEDs in series. Defaults to 1."}},"required":["supply_voltage_v"]}}}},"responses":{"200":{"description":"Computed result for led_resistor","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"resistance_ohm":{"description":"Exact calculated resistance in ohms.","type":"number"},"nearest_e24_ohm":{"description":"Nearest standard E24 series resistor value in ohms.","type":"number"},"power_dissipation_mw":{"description":"Power dissipated by the resistor in milliwatts (mW), using the E24 value.","type":"number"},"actual_current_ma":{"description":"Actual LED current in milliamps (mA) when using the nearest E24 resistor.","type":"number"},"voltage_across_resistor_v":{"description":"Voltage drop across the current-limiting resistor in volts.","type":"number"}},"required":["resistance_ohm","nearest_e24_ohm","power_dissipation_mw","actual_current_ma","voltage_across_resistor_v"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/timer_555":{"get":{"summary":"Metadata for timer_555","operationId":"get_timer_555","tags":["pcb"],"responses":{"200":{"description":"Metadata for timer_555","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates timing parameters for the ubiquitous NE555 / LM555 timer IC in astable (free-running oscillator) and monostable (one-shot pulse) modes. In astable mode, computes frequency, period, duty cycle, and HIGH/LOW durations from R1, R2, and C using f = 1.44 / ((R1 + 2·R2) · C). In monostable mode, computes pulse width from R and C using t = 1.1 · R · C. Standard 555 astable duty cycle is always >50%; for 50% duty cycle use a diode across R2. Useful for generating clock signals, PWM, delays, and debounce circuits. Chain from ohms_law for power calculations or resistor_color_code for component selection.","operationId":"compute_timer_555","tags":["pcb"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"description":"Operating mode. 'astable' produces a continuous square wave. 'monostable' produces a single timed pulse.","type":"string","enum":["astable","monostable"]},"r1_ohm":{"description":"Resistance R1 in ohms. In astable mode this is the charge-path resistor between Vcc and the discharge pin. In monostable mode this is the timing resistor.","type":"number"},"r2_ohm":{"type":"number","description":"Resistance R2 in ohms (astable mode only). Charge/discharge resistor between the discharge and threshold pins. Required for astable mode."},"c_farad":{"description":"Timing capacitor in farads. Typical values range from 1 pF to 1000 µF. Use scientific notation, e.g. 1e-6 for 1 µF.","type":"number"}},"required":["mode","r1_ohm","c_farad"]}}}},"responses":{"200":{"description":"Computed result for timer_555","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"mode":{"description":"Operating mode used for calculation.","type":"string"},"frequency_hz":{"type":"number","nullable":true,"description":"Output frequency in Hz (astable only, null for monostable)."},"period_s":{"type":"number","nullable":true,"description":"Total period in seconds (astable only, null for monostable)."},"duty_cycle_pct":{"type":"number","nullable":true,"description":"Duty cycle as a percentage (astable only, null for monostable). Always > 50% for standard 555."},"time_high_s":{"description":"Output HIGH duration in seconds. In astable this is the charge time; in monostable this is the pulse width.","type":"number"},"time_low_s":{"type":"number","nullable":true,"description":"Output LOW duration in seconds (astable only, null for monostable)."},"r1_ohm":{"description":"R1 value used in ohms.","type":"number"},"r2_ohm":{"type":"number","nullable":true,"description":"R2 value used in ohms (null for monostable)."},"c_farad":{"description":"Capacitor value used in farads.","type":"number"},"c_display":{"description":"Human-readable capacitor value string (e.g. '100 nF', '4.7 µF').","type":"string"}},"required":["mode","frequency_hz","period_s","duty_cycle_pct","time_high_s","time_low_s","r1_ohm","r2_ohm","c_farad","c_display"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/op_amp_gain":{"get":{"summary":"Metadata for op_amp_gain","operationId":"get_op_amp_gain","tags":["pcb"],"responses":{"200":{"description":"Metadata for op_amp_gain","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate voltage gain and output for operational amplifier circuits in inverting, non-inverting, and differential configurations. For inverting: Av = -Rf/Ri with input impedance equal to Ri. For non-inverting: Av = 1 + Rf/Rg with very high input impedance. For differential: Av = Rf/Ri applied to (V1 - V2). Reports gain in linear and dB, output voltage when input is provided, input impedance, and phase inversion status. Ideal op-amp assumptions (infinite open-loop gain, zero input bias current). Chain from ohms_law for power budgeting or resistor_color_code for component selection.","operationId":"compute_op_amp_gain","tags":["pcb"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"topology":{"description":"Op-amp circuit topology. 'inverting' uses Rf/Ri feedback with input to inverting terminal. 'non_inverting' applies input to non-inverting terminal with Rf/Rg feedback. 'differential' amplifies the voltage difference between two inputs.","type":"string","enum":["inverting","non_inverting","differential"]},"rf_ohm":{"description":"Feedback resistor Rf in ohms. Sets gain magnitude in all topologies.","type":"number"},"ri_ohm":{"description":"Input/gain resistor in ohms. For inverting: input resistor Ri. For non-inverting: ground resistor Rg. For differential: input resistor on both channels.","type":"number"},"vin_v":{"type":"number","description":"Input voltage in volts (optional). When provided, computes actual output voltage. For differential topology, this is V1 (non-inverting input)."},"vin2_v":{"type":"number","description":"Second input voltage in volts (differential topology only). This is V2 (inverting input)."}},"required":["topology","rf_ohm","ri_ohm"]}}}},"responses":{"200":{"description":"Computed result for op_amp_gain","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"topology":{"description":"Op-amp topology used.","type":"string"},"gain":{"description":"Voltage gain (Av). Negative for inverting topology.","type":"number"},"gain_abs":{"description":"Absolute value of voltage gain.","type":"number"},"gain_db":{"description":"Gain in decibels: 20 * log10(|Av|).","type":"number"},"vout_v":{"type":"number","nullable":true,"description":"Output voltage in volts (null if no input voltage provided)."},"input_impedance_ohm":{"description":"Input impedance in ohms. Inverting: Ri. Non-inverting: very high (returned as 1e12). Differential: Ri.","type":"number"},"rf_ohm":{"description":"Feedback resistor value used in ohms.","type":"number"},"ri_ohm":{"description":"Input/gain resistor value used in ohms.","type":"number"},"phase_inversion":{"description":"True if the output is phase-inverted relative to the input.","type":"boolean"}},"required":["topology","gain","gain_abs","gain_db","vout_v","input_impedance_ohm","rf_ohm","ri_ohm","phase_inversion"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/capacitor_charge":{"get":{"summary":"Metadata for capacitor_charge","operationId":"get_capacitor_charge","tags":["pcb"],"responses":{"200":{"description":"Metadata for capacitor_charge","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates RC capacitor charge timing, energy storage, and transient voltages. Given resistance, capacitance, supply voltage, and optional initial voltage, computes the RC time constant (τ = R×C), time to reach standard charge thresholds (63%, 86%, 95%, 99%), voltage at key time points, energy stored (E = ½CV²), and peak charging current. Optionally calculates time to reach a specific target voltage using t = -τ × ln((Vsupply - Vtarget) / (Vsupply - Vinitial)). Essential for timing circuits, power-on reset delays, debounce networks, and soft-start designs. Chain from rc_filter for frequency-domain analysis or timer_555 for oscillator timing.","operationId":"compute_capacitor_charge","tags":["pcb"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"resistance_ohm":{"description":"Series resistance in ohms (R). Controls charge/discharge rate.","type":"number"},"capacitance_f":{"description":"Capacitance in farads (C). Use scientific notation, e.g. 1e-6 for 1 µF.","type":"number"},"v_supply":{"description":"Supply voltage in volts. The voltage the capacitor charges toward.","type":"number"},"v_initial":{"type":"number","default":0,"description":"Initial capacitor voltage in volts (default 0 for fully discharged)."},"v_target":{"type":"number","description":"Target voltage to reach in volts (optional). When provided, calculates time to reach this voltage. Must be between v_initial and v_supply."}},"required":["resistance_ohm","capacitance_f","v_supply"]}}}},"responses":{"200":{"description":"Computed result for capacitor_charge","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"tau_s":{"description":"RC time constant (τ = R×C) in seconds.","type":"number"},"tau_ms":{"description":"RC time constant in milliseconds.","type":"number"},"time_to_63pct_ms":{"description":"Time to reach 63.2% of (Vsupply − Vinitial) in milliseconds (1τ).","type":"number"},"time_to_86pct_ms":{"description":"Time to reach 86.5% of (Vsupply − Vinitial) in milliseconds (2τ).","type":"number"},"time_to_95pct_ms":{"description":"Time to reach 95.0% of (Vsupply − Vinitial) in milliseconds (3τ).","type":"number"},"time_to_99pct_ms":{"description":"Time to reach 99.3% of (Vsupply − Vinitial) in milliseconds (5τ).","type":"number"},"time_to_target_ms":{"type":"number","nullable":true,"description":"Time to reach v_target in milliseconds (null if v_target not specified)."},"v_at_1tau":{"description":"Capacitor voltage after 1τ in volts.","type":"number"},"v_at_2tau":{"description":"Capacitor voltage after 2τ in volts.","type":"number"},"v_at_5tau":{"description":"Capacitor voltage after 5τ in volts.","type":"number"},"energy_joules":{"description":"Energy stored at full charge: E = ½CV² in joules.","type":"number"},"energy_mj":{"description":"Energy stored at full charge in millijoules.","type":"number"},"peak_current_ma":{"description":"Peak charging current at t=0 in milliamps: Ipeak = (Vsupply − Vinitial) / R.","type":"number"}},"required":["tau_s","tau_ms","time_to_63pct_ms","time_to_86pct_ms","time_to_95pct_ms","time_to_99pct_ms","time_to_target_ms","v_at_1tau","v_at_2tau","v_at_5tau","energy_joules","energy_mj","peak_current_ma"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/pcb_via_current":{"get":{"summary":"Metadata for pcb_via_current","operationId":"get_pcb_via_current","tags":["pcb"],"responses":{"200":{"description":"Metadata for pcb_via_current","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate PCB via current-carrying capacity using the IPC-2221 standard. A plated via is a hollow copper cylinder whose cross-sectional area is the annular ring of plating: A = pi * (D - t) * t, where D is the drill diameter and t is plating thickness. The IPC-2221 empirical formula I = k * dT^0.44 * A^0.725 (k=0.048) then gives the maximum current for a given temperature rise. Also computes via barrel resistance from copper resistivity (1.724e-6 ohm-cm) and barrel length (board thickness). When a target current is specified, returns how many parallel vias are needed. Essential for power planes, high-current paths, and thermal via arrays. Chain with trace_width to verify both trace and via can handle the same current.","operationId":"compute_pcb_via_current","tags":["pcb"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"drill_diameter_mm":{"type":"number","default":0.3,"description":"Via drill hole diameter in millimeters. Common values: 0.2 (microvia), 0.3 (standard), 0.4, 0.6, 0.8, 1.0."},"plating_thickness_um":{"type":"number","default":25,"description":"Copper plating thickness on the via barrel wall in micrometers. Standard is 25 um (IPC Class 2). Heavy plating is 50 um (IPC Class 3)."},"board_thickness_mm":{"type":"number","default":1.6,"description":"Total PCB board thickness in millimeters. Standard 2-layer is 1.6 mm. Common values: 0.8, 1.0, 1.6, 2.0, 2.4."},"temp_rise_c":{"type":"number","default":10,"description":"Allowable temperature rise above ambient in degrees Celsius. IPC-2221 standard uses 10, 20, or 30 C."},"target_current_a":{"type":"number","description":"Optional target current in amperes. When provided, calculates how many parallel vias are needed to carry this current safely."}},"required":[]}}}},"responses":{"200":{"description":"Computed result for pcb_via_current","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"max_current_a":{"description":"Maximum current capacity of a single via at the specified temperature rise, in amperes.","type":"number"},"cross_section_mil2":{"description":"Copper cross-sectional area of the via barrel annulus in square mils.","type":"number"},"cross_section_mm2":{"description":"Copper cross-sectional area of the via barrel annulus in square millimeters.","type":"number"},"resistance_mohm":{"description":"DC resistance of the via barrel in milliohms, calculated from copper resistivity and barrel length.","type":"number"},"voltage_drop_mv":{"description":"Voltage drop across the via at maximum rated current in millivolts.","type":"number"},"power_dissipation_mw":{"description":"Power dissipated in the via at maximum rated current in milliwatts.","type":"number"},"vias_needed":{"type":"number","nullable":true,"description":"Number of parallel vias needed for the target current. Null if no target_current_a was provided."}},"required":["max_current_a","cross_section_mil2","cross_section_mm2","resistance_mohm","voltage_drop_mv","power_dissipation_mw","vias_needed"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/power_supply_decoupling":{"get":{"summary":"Metadata for power_supply_decoupling","operationId":"get_power_supply_decoupling","tags":["pcb"],"responses":{"200":{"description":"Metadata for power_supply_decoupling","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Select bypass and bulk decoupling capacitors for IC power supply pins. Computes the target PDN (Power Distribution Network) impedance from supply current, voltage, and allowable ripple using Z_target = V_ripple / I_total. Recommends a ceramic bypass capacitor (high-frequency decoupling, placed closest to IC pins) and a bulk capacitor (low-frequency decoupling, near the regulator). Calculates the ceramic cap's self-resonant frequency assuming typical lead inductance, and checks whether ESR-induced ripple stays within limits. Essential for digital, analog, and mixed-signal PCB design. Chain with lc_resonance to verify the decoupling capacitor's resonant behavior, or with trace_width to size the power trace.","operationId":"compute_power_supply_decoupling","tags":["pcb"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"supply_current_ma":{"description":"IC supply current draw in milliamps (mA). Use the maximum or typical from the datasheet.","type":"number"},"supply_voltage_v":{"description":"Supply voltage in volts (V). Common values: 1.8, 2.5, 3.3, 5.0, 12.0.","type":"number"},"switching_freq_mhz":{"type":"number","default":1,"description":"Primary switching or clock frequency of the IC in MHz. Determines the target impedance frequency range."},"max_ripple_mv":{"type":"number","default":50,"description":"Maximum allowable supply ripple in millivolts (mV). Typical: 50 mV for digital, 10 mV for analog/RF."},"num_ics":{"type":"number","default":1,"description":"Number of identical ICs sharing this supply rail. Scales the total current demand."},"esr_mohm":{"type":"number","default":10,"description":"Equivalent series resistance (ESR) of the ceramic bypass capacitor in milliohms. Typical MLCC: 5-20 mohm."}},"required":["supply_current_ma","supply_voltage_v"]}}}},"responses":{"200":{"description":"Computed result for power_supply_decoupling","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"target_impedance_ohm":{"description":"Target supply impedance at the switching frequency: Z_target = V_ripple / I_total. The decoupling network must keep PDN impedance below this value.","type":"number"},"ceramic_cap_uf":{"description":"Recommended ceramic bypass capacitor value in microfarads (uF). Placed closest to IC pins.","type":"number"},"ceramic_cap_value":{"description":"Nearest standard E12 capacitor value with unit (e.g. '100 nF', '1 uF').","type":"string"},"bulk_cap_uf":{"description":"Recommended bulk capacitor value in microfarads (uF). Placed near the voltage regulator for low-frequency decoupling.","type":"number"},"bulk_cap_value":{"description":"Nearest standard bulk capacitor value with unit (e.g. '10 uF', '47 uF').","type":"string"},"self_resonant_freq_mhz":{"description":"Self-resonant frequency of the recommended ceramic capacitor assuming 0.5 nH lead inductance. Above this frequency, the capacitor becomes inductive.","type":"number"},"total_current_ma":{"description":"Total supply current for all ICs on this rail.","type":"number"},"ripple_at_esr_mv":{"description":"Estimated ripple voltage due to ESR at the switching frequency: V = I_peak * ESR.","type":"number"},"bypass_adequate":{"description":"Whether the ESR-induced ripple is within the specified max_ripple_mv limit.","type":"boolean"}},"required":["target_impedance_ohm","ceramic_cap_uf","ceramic_cap_value","bulk_cap_uf","bulk_cap_value","self_resonant_freq_mhz","total_current_ma","ripple_at_esr_mv","bypass_adequate"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/log_calc":{"get":{"summary":"Metadata for log_calc","operationId":"get_log_calc","tags":["general"],"responses":{"200":{"description":"Metadata for log_calc","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Compute logarithms of a positive number in any base. Returns the custom-base logarithm, natural logarithm (ln), common logarithm (log10), and binary logarithm (log2). Useful for signal processing (decibel calculations), information theory (entropy in bits), pH chemistry, and general scientific computation. Uses the change-of-base formula log_b(x) = ln(x) / ln(b). Feeds into exponent_calc for inverse operations and scientific_notation for order-of-magnitude analysis.","operationId":"compute_log_calc","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"value":{"description":"The positive number to compute the logarithm of","type":"number"},"base":{"type":"number","default":10,"description":"The logarithm base (default 10). Must be positive and not equal to 1"}},"required":["value"]}}}},"responses":{"200":{"description":"Computed result for log_calc","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"result":{"description":"Logarithm of the value in the specified base: log_base(value)","type":"number"},"natural_log":{"description":"Natural logarithm (ln) of the value","type":"number"},"log10":{"description":"Common logarithm (base 10) of the value","type":"number"},"log2":{"description":"Binary logarithm (base 2) of the value","type":"number"}},"required":["result","natural_log","log10","log2"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/sig_figs":{"get":{"summary":"Metadata for sig_figs","operationId":"get_sig_figs","tags":["general"],"responses":{"200":{"description":"Metadata for sig_figs","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Count significant figures in a number and optionally round to N significant figures. Accepts the number as a string to preserve trailing zeros (e.g. '1.200' has 4 sig figs). Applies standard sig fig rules: leading zeros do not count, trailing zeros after a decimal point count, trailing zeros before a decimal point are treated as significant. Also returns the number in scientific notation. Essential for laboratory measurements, error analysis, and maintaining proper precision in chained calculations.","operationId":"compute_sig_figs","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"number_str":{"description":"The number as a string to preserve trailing zeros (e.g. '1.200')","type":"string"},"round_to_n":{"type":"number","description":"Optionally round the number to this many significant figures"}},"required":["number_str"]}}}},"responses":{"200":{"description":"Computed result for sig_figs","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"sig_figs_count":{"description":"Number of significant figures in the input","type":"number"},"rounded_to_n":{"type":"string","nullable":true,"description":"The number rounded to N significant figures (null if N not provided)"},"scientific_notation":{"description":"The number expressed in scientific notation","type":"string"}},"required":["sig_figs_count","rounded_to_n","scientific_notation"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/scientific_notation":{"get":{"summary":"Metadata for scientific_notation","operationId":"get_scientific_notation","tags":["general"],"responses":{"200":{"description":"Metadata for scientific_notation","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Convert any number to scientific notation and engineering notation. Returns the coefficient, exponent, a formatted string with Unicode superscripts (e.g. '3.14 × 10²'), and engineering notation where the exponent is a multiple of 3. Useful for expressing very large or very small values compactly, common in physics, electronics (picofarads, gigahertz), and astronomy. Accepts output from sig_figs and log_calc for precision-aware formatting.","operationId":"compute_scientific_notation","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"value":{"description":"The number to convert to scientific notation","type":"number"}},"required":["value"]}}}},"responses":{"200":{"description":"Computed result for scientific_notation","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"coefficient":{"description":"The coefficient (mantissa) between 1 and 10","type":"number"},"exponent":{"description":"The power-of-10 exponent","type":"number"},"notation_string":{"description":"Formatted scientific notation with Unicode superscripts (e.g. '3.14 × 10²')","type":"string"},"engineering_notation":{"description":"Engineering notation with exponent divisible by 3","type":"string"}},"required":["coefficient","exponent","notation_string","engineering_notation"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/percentage_calc":{"get":{"summary":"Metadata for percentage_calc","operationId":"get_percentage_calc","tags":["general"],"responses":{"200":{"description":"Metadata for percentage_calc","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate what percentage one number is of another. Given a value and a total, returns the percentage, decimal form, and simplified fraction. For example, 3 out of 4 yields 75%, 0.75, and '3/4'. Commonly used for test scores, survey results, financial ratios, completion rates, and unit conversions. Chain with percentage_increase to compare successive measurements or use with test_grade for academic scoring.","operationId":"compute_percentage_calc","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"value":{"description":"The part or numerator value","type":"number"},"total":{"description":"The whole or denominator value (must not be zero)","type":"number"}},"required":["value","total"]}}}},"responses":{"200":{"description":"Computed result for percentage_calc","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"percentage":{"description":"The percentage value (e.g. 75 for 75%)","type":"number"},"decimal":{"description":"The decimal form (e.g. 0.75)","type":"number"},"fraction_simplified":{"description":"Simplified fraction as a string (e.g. '3/4')","type":"string"}},"required":["percentage","decimal","fraction_simplified"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/percentage_increase":{"get":{"summary":"Metadata for percentage_increase","operationId":"get_percentage_increase","tags":["general"],"responses":{"200":{"description":"Metadata for percentage_increase","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate the percentage change between an old value and a new value. Determines whether the change is an increase or decrease, the absolute change, and the percentage change. Essential for financial analysis (stock price changes, revenue growth), scientific measurements (before/ after experiments), performance benchmarks, and population statistics. A positive percentage indicates growth; negative indicates decline. Division by zero (old_value = 0) is handled gracefully.","operationId":"compute_percentage_increase","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"old_value":{"description":"The original or starting value","type":"number"},"new_value":{"description":"The new or ending value","type":"number"}},"required":["old_value","new_value"]}}}},"responses":{"200":{"description":"Computed result for percentage_increase","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"change":{"description":"The signed difference (new_value - old_value)","type":"number"},"percentage_change":{"description":"Percentage change from old to new value","type":"number"},"is_increase":{"description":"True if new_value > old_value, false otherwise","type":"boolean"},"absolute_change":{"description":"Absolute value of the change","type":"number"}},"required":["change","percentage_change","is_increase","absolute_change"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/exponent_calc":{"get":{"summary":"Metadata for exponent_calc","operationId":"get_exponent_calc","tags":["general"],"responses":{"200":{"description":"Metadata for exponent_calc","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Compute the result of raising a base to an exponent (base^exponent). Handles positive and negative exponents, fractional exponents, and zero. Returns the numeric result and a scientific notation string for very large or very small results. Useful for compound interest calculations, exponential growth/decay models, physics power laws, and combinatorics. The inverse of log_calc; chain with scientific_notation for formatted display of extreme values.","operationId":"compute_exponent_calc","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"base":{"description":"The base number","type":"number"},"exponent":{"description":"The exponent (power) to raise the base to","type":"number"}},"required":["base","exponent"]}}}},"responses":{"200":{"description":"Computed result for exponent_calc","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"result":{"description":"The computed value of base^exponent","type":"number"},"scientific_notation":{"description":"Result in scientific notation for very large/small values","type":"string"}},"required":["result","scientific_notation"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/square_root":{"get":{"summary":"Metadata for square_root","operationId":"get_square_root","tags":["general"],"responses":{"200":{"description":"Metadata for square_root","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Compute the square root of a non-negative number. Returns the decimal result, whether the input is a perfect square, and a simplified radical form (e.g. '√12' simplifies to '2√3'). For integer inputs, factors are extracted from under the radical sign. Useful for geometry (diagonal/hypotenuse calculations), statistics (standard deviation from variance), signal processing (RMS values), and general algebra. Chain with pythagorean_theorem for triangle side calculations.","operationId":"compute_square_root","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"value":{"description":"The non-negative number to compute the square root of","type":"number"}},"required":["value"]}}}},"responses":{"200":{"description":"Computed result for square_root","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"result":{"description":"The square root of the input value","type":"number"},"is_perfect_square":{"description":"True if the input is a perfect square integer","type":"boolean"},"simplified_radical":{"description":"Simplified radical form (e.g. '2√3' for √12)","type":"string"}},"required":["result","is_perfect_square","simplified_radical"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/circumference":{"get":{"summary":"Metadata for circumference","operationId":"get_circumference","tags":["general"],"responses":{"200":{"description":"Metadata for circumference","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate the circumference and area of a circle given either a radius or diameter. Provide one or both; if both are given, radius takes precedence. Returns circumference (C = 2πr), area (A = πr²), and both radius and diameter for completeness. Common in mechanical engineering (pulley systems, pipe sizing), electronics (antenna loop calculations, coil winding), civil engineering (manhole covers, circular foundations), and everyday measurement tasks.","operationId":"compute_circumference","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"radius":{"type":"number","description":"The radius of the circle (takes precedence over diameter)"},"diameter":{"type":"number","description":"The diameter of the circle"}},"required":[]}}}},"responses":{"200":{"description":"Computed result for circumference","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"circumference":{"description":"Circumference of the circle (C = 2πr)","type":"number"},"area":{"description":"Area of the circle (A = πr²)","type":"number"},"diameter":{"description":"Diameter of the circle","type":"number"},"radius":{"description":"Radius of the circle","type":"number"}},"required":["circumference","area","diameter","radius"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/slope_calc":{"get":{"summary":"Metadata for slope_calc","operationId":"get_slope_calc","tags":["general"],"responses":{"200":{"description":"Metadata for slope_calc","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate the slope, y-intercept, line equation, angle, and distance between two points in a 2D Cartesian plane. Given coordinates (x1, y1) and (x2, y2), computes slope (rise/run), y-intercept, the equation in slope-intercept form (y = mx + b), angle in degrees relative to the x-axis, and Euclidean distance. Handles vertical and horizontal lines as special cases. Useful for surveying, civil engineering grade calculations, linear regression visualization, and physics kinematics problems.","operationId":"compute_slope_calc","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"x1":{"description":"X-coordinate of the first point","type":"number"},"y1":{"description":"Y-coordinate of the first point","type":"number"},"x2":{"description":"X-coordinate of the second point","type":"number"},"y2":{"description":"Y-coordinate of the second point","type":"number"}},"required":["x1","y1","x2","y2"]}}}},"responses":{"200":{"description":"Computed result for slope_calc","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"slope":{"type":"number","nullable":true,"description":"Slope of the line (null for vertical lines)"},"y_intercept":{"type":"number","nullable":true,"description":"Y-intercept of the line (null for vertical lines)"},"equation":{"description":"Line equation in slope-intercept form or 'x = c' for vertical","type":"string"},"angle_degrees":{"description":"Angle of the line relative to the positive x-axis in degrees","type":"number"},"distance":{"description":"Euclidean distance between the two points","type":"number"},"is_vertical":{"description":"True if the line is vertical (undefined slope)","type":"boolean"},"is_horizontal":{"description":"True if the line is horizontal (slope = 0)","type":"boolean"}},"required":["slope","y_intercept","equation","angle_degrees","distance","is_vertical","is_horizontal"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/pythagorean_theorem":{"get":{"summary":"Metadata for pythagorean_theorem","operationId":"get_pythagorean_theorem","tags":["general"],"responses":{"200":{"description":"Metadata for pythagorean_theorem","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Solve for any side of a right triangle using the Pythagorean theorem (a² + b² = c²). Provide any two of the three sides (a, b, c) and the missing side is computed. Also returns the triangle area (0.5 * a * b), perimeter, and confirms it is a right triangle. Side c is always the hypotenuse. Fundamental to surveying, construction (squaring corners), navigation (distance calculations), physics (vector decomposition), and 3D graphics. Chain with slope_calc for coordinate geometry or square_root for simplified radical answers.","operationId":"compute_pythagorean_theorem","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"a":{"type":"number","description":"Length of side a (leg)"},"b":{"type":"number","description":"Length of side b (leg)"},"c":{"type":"number","description":"Length of side c (hypotenuse)"}},"required":[]}}}},"responses":{"200":{"description":"Computed result for pythagorean_theorem","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"a":{"description":"Length of side a","type":"number"},"b":{"description":"Length of side b","type":"number"},"c":{"description":"Length of side c (hypotenuse)","type":"number"},"area":{"description":"Area of the right triangle (0.5 * a * b)","type":"number"},"perimeter":{"description":"Perimeter of the triangle (a + b + c)","type":"number"},"is_right_triangle":{"description":"Always true when computed from two sides","type":"boolean"}},"required":["a","b","c","area","perimeter","is_right_triangle"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/p_value":{"get":{"summary":"Metadata for p_value","operationId":"get_p_value","tags":["general"],"responses":{"200":{"description":"Metadata for p_value","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate the p-value for a z-score or t-statistic. Supports one-tailed (left or right) and two-tailed hypothesis tests using either the standard normal distribution or the Student's t-distribution when degrees of freedom are specified. Returns significance flags at the 0.01, 0.05, and 0.10 alpha levels. Essential for interpreting results from t-tests, z-tests, ANOVA post-hoc comparisons, and regression coefficients. Uses the Abramowitz & Stegun normal CDF approximation and regularized incomplete beta function for the t-distribution.","operationId":"compute_p_value","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"test_statistic":{"description":"The z-score or t-statistic from your hypothesis test. Positive values indicate the observed value is above the null hypothesis mean.","type":"number"},"test_type":{"type":"string","enum":["one_tail_left","one_tail_right","two_tail"],"default":"two_tail","description":"Tail type: one_tail_left (p from left), one_tail_right (p from right), or two_tail (both tails combined)."},"degrees_of_freedom":{"type":"number","description":"Degrees of freedom for the t-distribution. Omit to use the standard normal (z) distribution."}},"required":["test_statistic"]}}}},"responses":{"200":{"description":"Computed result for p_value","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"p_value":{"description":"The computed p-value representing the probability of observing a result at least as extreme as the test statistic under the null hypothesis.","type":"number"},"significant_at_01":{"description":"Whether the result is statistically significant at the 0.01 (1%) level.","type":"boolean"},"significant_at_05":{"description":"Whether the result is statistically significant at the 0.05 (5%) level.","type":"boolean"},"significant_at_10":{"description":"Whether the result is statistically significant at the 0.10 (10%) level.","type":"boolean"},"test_type":{"description":"The tail type used for this calculation.","type":"string","enum":["one_tail_left","one_tail_right","two_tail"]}},"required":["p_value","significant_at_01","significant_at_05","significant_at_10","test_type"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/confidence_interval":{"get":{"summary":"Metadata for confidence_interval","operationId":"get_confidence_interval","tags":["general"],"responses":{"200":{"description":"Metadata for confidence_interval","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate the confidence interval for a sample mean. Given a sample mean, sample size, standard deviation, and confidence level, computes the margin of error, lower and upper bounds, critical z-score, and standard error. Supports finite population correction (FPC) when a population size is provided, which narrows the interval for samples that are a large fraction of the population. Uses the Abramowitz & Stegun rational approximation for the inverse normal CDF to derive the critical z-value. Common in survey analysis, A/B testing, and quality control.","operationId":"compute_confidence_interval","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sample_mean":{"description":"The observed sample mean (x-bar) around which the confidence interval is centered.","type":"number"},"sample_size":{"description":"The number of observations in the sample (n). Must be a positive integer.","type":"number"},"standard_deviation":{"description":"The standard deviation of the sample or population. Must be a positive number.","type":"number"},"confidence_level":{"type":"number","default":0.95,"description":"Confidence level as a decimal between 0 and 1 (e.g. 0.95 for 95%). Default is 0.95."},"population_size":{"type":"number","description":"Total population size for finite population correction (FPC). Omit for infinite population assumption."}},"required":["sample_mean","sample_size","standard_deviation"]}}}},"responses":{"200":{"description":"Computed result for confidence_interval","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"lower_bound":{"description":"Lower bound of the confidence interval.","type":"number"},"upper_bound":{"description":"Upper bound of the confidence interval.","type":"number"},"margin_of_error":{"description":"Half-width of the confidence interval (z_score * standard_error).","type":"number"},"z_score":{"description":"Critical z-value used for the given confidence level.","type":"number"},"standard_error":{"description":"Standard error of the mean, optionally adjusted with finite population correction.","type":"number"},"confidence_level":{"description":"The confidence level used (echoed back).","type":"number"}},"required":["lower_bound","upper_bound","margin_of_error","z_score","standard_error","confidence_level"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/sales_tax":{"get":{"summary":"Metadata for sales_tax","operationId":"get_sales_tax","tags":["general"],"responses":{"200":{"description":"Metadata for sales_tax","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates total cost including sales tax for a purchase. Given a unit price, tax rate percentage, and optional quantity, computes the subtotal (price times quantity), the tax amount rounded to two decimal places, and the final total. Useful for estimating purchase costs across US states and municipalities with different tax rates, comparing pre-tax and post-tax prices, and budgeting. Chain into salary_to_hourly to see how many work-hours a purchase represents.","operationId":"compute_sales_tax","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"price":{"description":"Unit price of the item in dollars (or any currency). Must be positive.","type":"number"},"tax_rate_pct":{"type":"number","default":0,"description":"Sales tax rate as a percentage (e.g. 8.875 for 8.875%). Defaults to 0 — enter your local rate."},"quantity":{"type":"number","default":1,"description":"Number of items to purchase. Defaults to 1."}},"required":["price"]}}}},"responses":{"200":{"description":"Computed result for sales_tax","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"subtotal":{"description":"Price times quantity before tax.","type":"number"},"tax_amount":{"description":"Total tax amount, rounded to two decimal places.","type":"number"},"total":{"description":"Subtotal plus tax amount.","type":"number"},"effective_rate_pct":{"description":"The tax rate applied, echoed back for confirmation.","type":"number"}},"required":["subtotal","tax_amount","total","effective_rate_pct"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/salary_to_hourly":{"get":{"summary":"Metadata for salary_to_hourly","operationId":"get_salary_to_hourly","tags":["general"],"responses":{"200":{"description":"Metadata for salary_to_hourly","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Converts compensation between annual salary, monthly pay, weekly pay, and hourly wage. Accepts any of the four pay periods as input and derives all others. Uses configurable hours per week (default 40) and weeks per year (default 52). Daily rate assumes an 8-hour workday; monthly is annual divided by 12. Useful for comparing job offers quoted in different pay periods, freelance rate-setting, and budgeting. Chain from sales_tax to see how many hours a purchase costs.","operationId":"compute_salary_to_hourly","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"description":"The salary or wage amount to convert.","type":"number"},"from_type":{"type":"string","enum":["annual","monthly","weekly","hourly"],"default":"annual","description":"The pay period of the input amount. Defaults to 'annual'."},"hours_per_week":{"type":"number","default":40,"description":"Hours worked per week. Defaults to 40 for a standard full-time schedule."},"weeks_per_year":{"type":"number","default":52,"description":"Working weeks per year. Defaults to 52. Use 50 to account for 2 weeks unpaid vacation."}},"required":["amount"]}}}},"responses":{"200":{"description":"Computed result for salary_to_hourly","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"hourly":{"description":"Hourly wage.","type":"number"},"daily":{"description":"Daily earnings assuming an 8-hour workday.","type":"number"},"weekly":{"description":"Weekly earnings.","type":"number"},"biweekly":{"description":"Biweekly (every two weeks) earnings.","type":"number"},"monthly":{"description":"Monthly earnings (annual / 12).","type":"number"},"annual":{"description":"Annual salary.","type":"number"}},"required":["hourly","daily","weekly","biweekly","monthly","annual"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/loan_amortization":{"get":{"summary":"Metadata for loan_amortization","operationId":"get_loan_amortization","tags":["general"],"responses":{"200":{"description":"Metadata for loan_amortization","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Computes a full loan amortization schedule given principal, annual interest rate, and term in months. Returns the fixed monthly payment, total interest, total payments, and a month-by-month breakdown of principal vs interest. Supports optional extra monthly payments — shows months saved and interest saved. Works for mortgages (30yr/15yr), auto loans, personal loans, and student loans. All currency-agnostic. Use with /run?page=1&page_size=12 to paginate the schedule array for context-friendly agent consumption.","operationId":"compute_loan_amortization","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"principal":{"description":"Loan principal amount in dollars (or any currency unit).","type":"number"},"annual_rate_pct":{"description":"Annual interest rate as a percentage (e.g., 6.5 for 6.5%).","type":"number"},"term_months":{"description":"Loan term in months. Max 600 (50 years). Common values: 360 (30yr), 180 (15yr), 60 (5yr auto).","type":"number"},"extra_payment":{"type":"number","default":0,"description":"Optional fixed extra monthly payment toward principal. Defaults to 0."}},"required":["principal","annual_rate_pct","term_months"]}}}},"responses":{"200":{"description":"Computed result for loan_amortization","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"monthly_payment":{"description":"Fixed monthly payment (excluding extra payments).","type":"number"},"total_payments":{"description":"Sum of all payments over the life of the loan.","type":"number"},"total_interest":{"description":"Total interest paid over the life of the loan.","type":"number"},"total_extra_paid":{"description":"Total extra payments made.","type":"number"},"payoff_months":{"description":"Actual number of months to pay off (may be less than term with extra payments).","type":"number"},"interest_saved":{"description":"Interest saved by extra payments vs. full term. 0 if no extra payments.","type":"number"},"schedule":{"description":"Month-by-month amortization schedule.","type":"array","items":{"type":"object","properties":{"month":{"description":"Payment number (1-based).","type":"number"},"payment":{"description":"Total payment this month.","type":"number"},"principal_paid":{"description":"Portion of payment applied to principal.","type":"number"},"interest_paid":{"description":"Portion of payment applied to interest.","type":"number"},"extra_paid":{"description":"Extra payment applied this month.","type":"number"},"remaining_balance":{"description":"Outstanding balance after this payment.","type":"number"}},"required":["month","payment","principal_paid","interest_paid","extra_paid","remaining_balance"]}}},"required":["monthly_payment","total_payments","total_interest","total_extra_paid","payoff_months","interest_saved","schedule"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/compound_interest":{"get":{"summary":"Metadata for compound_interest","operationId":"get_compound_interest","tags":["general"],"responses":{"200":{"description":"Metadata for compound_interest","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates compound interest growth over time using the formula A = P(1 + r/n)^(nt). Given a principal, annual rate, duration in years, and compounding frequency, returns the future value, total interest earned, effective annual rate (APY), and a year-by-year growth schedule. Supports optional recurring monthly contributions for savings projections. Works for savings accounts, CDs, investment returns, and retirement planning. Currency-agnostic.","operationId":"compute_compound_interest","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"principal":{"description":"Initial investment or deposit amount (any currency unit).","type":"number"},"annual_rate_pct":{"description":"Annual interest rate as a percentage (e.g., 5.5 for 5.5%).","type":"number"},"years":{"description":"Investment duration in years. Max 100.","type":"number"},"compounds_per_year":{"description":"How often interest compounds per year. Allowed: 1 (annually), 2 (semi-annually), 4 (quarterly), 12 (monthly), 52 (weekly), 365 (daily). Defaults to 12."},"monthly_contribution":{"type":"number","default":0,"description":"Optional recurring monthly contribution added at each month. Defaults to 0."}},"required":["principal","annual_rate_pct","years","compounds_per_year"]}}}},"responses":{"200":{"description":"Computed result for compound_interest","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"future_value":{"description":"Final balance after all compounding and contributions.","type":"number"},"total_interest":{"description":"Total interest earned over the full period.","type":"number"},"total_contributions":{"description":"Total of all contributions (principal + recurring).","type":"number"},"effective_annual_rate_pct":{"description":"Effective annual rate accounting for compounding frequency (APY).","type":"number"},"schedule":{"description":"Year-by-year growth schedule.","type":"array","items":{"type":"object","properties":{"year":{"description":"Year number (1-based).","type":"number"},"start_balance":{"description":"Balance at the start of the year.","type":"number"},"interest_earned":{"description":"Interest earned during this year.","type":"number"},"contributions":{"description":"Total contributions added during this year.","type":"number"},"end_balance":{"description":"Balance at the end of the year.","type":"number"}},"required":["year","start_balance","interest_earned","contributions","end_balance"]}}},"required":["future_value","total_interest","total_contributions","effective_annual_rate_pct","schedule"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/test_grade":{"get":{"summary":"Metadata for test_grade","operationId":"get_test_grade","tags":["general"],"responses":{"200":{"description":"Metadata for test_grade","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculates a test or exam grade from the number of correct answers and total questions. Returns the percentage score, letter grade, points missed, and GPA points. Supports US grading (A/B/C/D/F with 4.0 GPA scale), UK grading (First/2:1/2:2/Third/Fail), and percentage-only mode. US thresholds: A>=90, B>=80, C>=70, D>=60, F<60. UK thresholds: First>=70, 2:1>=60, 2:2>=50, Third>=40, Fail<40. Useful for students checking scores and teachers computing class statistics.","operationId":"compute_test_grade","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"correct":{"description":"Number of questions answered correctly. Must be a non-negative integer.","type":"number"},"total":{"description":"Total number of questions on the test. Must be a positive integer.","type":"number"},"grading_scale":{"type":"string","enum":["us","uk","percentage_only"],"default":"us","description":"Grading scale to use. 'us' for A-F letter grades, 'uk' for First/2:1/2:2/Third/Fail, 'percentage_only' for just the percentage."}},"required":["correct","total"]}}}},"responses":{"200":{"description":"Computed result for test_grade","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"percentage":{"description":"Score as a percentage (0-100).","type":"number"},"letter_grade":{"type":"string","nullable":true,"description":"Letter grade based on the selected grading scale. Null if percentage_only."},"points_missed":{"description":"Number of questions answered incorrectly (total - correct).","type":"number"},"gpa_points":{"type":"number","nullable":true,"description":"GPA points on a 4.0 scale (US only). A=4.0, B=3.0, C=2.0, D=1.0, F=0. Null for UK and percentage_only."}},"required":["percentage","letter_grade","points_missed","gpa_points"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/unit_convert":{"get":{"summary":"Metadata for unit_convert","operationId":"get_unit_convert","tags":["general"],"responses":{"200":{"description":"Metadata for unit_convert","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Convert between units across 10 categories: length (m, km, mi, ft, in, yd, nmi), mass (kg, lb, oz, g, ton), volume (l, gal, ml, cup, fl_oz), area (m2, ft2, acre, hectare), speed (mps, kph, mph, knot), pressure (pa, psi, bar, atm, mmhg), energy (j, kwh, btu, cal, wh), data (b, kb, mb, gb, tb), time (s, ms, min, hr, day, year), and temperature (c, f, k). Accepts any value with source and target unit abbreviations. Returns the converted result with the formula used.","operationId":"compute_unit_convert","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"value":{"description":"The numeric value to convert.","type":"number"},"from":{"description":"Source unit abbreviation (e.g., 'km', 'lb', 'f', 'psi', 'kwh'). Case-insensitive.","type":"string"},"to":{"description":"Target unit abbreviation (e.g., 'mi', 'kg', 'c', 'bar', 'btu'). Case-insensitive.","type":"string"}},"required":["value","from","to"]}}}},"responses":{"200":{"description":"Computed result for unit_convert","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"result":{"description":"The converted value.","type":"number"},"from_unit":{"description":"Normalized source unit abbreviation.","type":"string"},"to_unit":{"description":"Normalized target unit abbreviation.","type":"string"},"category":{"description":"Unit category (length, mass, volume, area, speed, pressure, energy, data, time, temperature).","type":"string"},"formula":{"description":"Human-readable conversion formula applied.","type":"string"}},"required":["result","from_unit","to_unit","category","formula"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/hex_converter":{"get":{"summary":"Metadata for hex_converter","operationId":"get_hex_converter","tags":["general"],"responses":{"200":{"description":"Metadata for hex_converter","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Convert numbers between hexadecimal, binary, decimal, and octal bases. Accepts any base as input (prefix 0x for hex, 0b for binary, 0o for octal, or plain decimal) and returns all four representations simultaneously. Also reports bit width, byte count, ASCII character (if printable), and signed interpretations (8-bit, 16-bit, 32-bit two's complement). Essential for embedded programming, register debugging, network protocol analysis, and color code conversion. Example: 0xFF → decimal 255, binary 0b11111111, octal 0o377, 8 bits, 1 byte.","operationId":"compute_hex_converter","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"value":{"description":"The number to convert. Prefix with 0x for hex (0xFF), 0b for binary (0b1010), 0o for octal (0o17). Plain numbers are treated as decimal. Supports negative values with leading minus.","type":"string"}},"required":["value"]}}}},"responses":{"200":{"description":"Computed result for hex_converter","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"decimal":{"description":"Decimal (base-10) value.","type":"number"},"hex":{"description":"Hexadecimal string with 0x prefix (e.g. '0xFF').","type":"string"},"hex_upper":{"description":"Hexadecimal with uppercase letters (e.g. '0xFF').","type":"string"},"binary":{"description":"Binary string with 0b prefix (e.g. '0b11111111').","type":"string"},"octal":{"description":"Octal string with 0o prefix (e.g. '0o377').","type":"string"},"bits":{"description":"Minimum number of bits needed to represent this value (unsigned).","type":"number"},"bytes":{"description":"Minimum number of bytes needed (ceil(bits/8)).","type":"number"},"ascii":{"type":"string","nullable":true,"description":"ASCII character if the value is a printable character (32-126), null otherwise."},"signed_8":{"type":"number","nullable":true,"description":"Signed 8-bit interpretation (-128 to 127), null if out of range."},"signed_16":{"type":"number","nullable":true,"description":"Signed 16-bit interpretation (-32768 to 32767), null if out of range."},"signed_32":{"type":"number","nullable":true,"description":"Signed 32-bit interpretation, null if out of range."}},"required":["decimal","hex","hex_upper","binary","octal","bits","bytes","ascii","signed_8","signed_16","signed_32"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/timestamp_converter":{"get":{"summary":"Metadata for timestamp_converter","operationId":"get_timestamp_converter","tags":["general"],"responses":{"200":{"description":"Metadata for timestamp_converter","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Convert between Unix timestamps and human-readable date/time formats. Accepts Unix epoch (in seconds or milliseconds), ISO 8601 strings, or 'now' for the current time. Returns both Unix seconds and milliseconds, ISO 8601 UTC string, date and time components, day of the week, relative time description ('2 hours ago'), and past/future indicator. Auto-detects whether a numeric input is seconds or milliseconds based on magnitude. Essential for debugging logs, API timestamps, cron scheduling, and time zone conversions.","operationId":"compute_timestamp_converter","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"value":{"description":"A timestamp to convert. Accepts Unix epoch (seconds or milliseconds), ISO 8601 string (e.g. '2024-01-15T10:30:00Z'), or 'now' for the current time.","type":"string"}},"required":["value"]}}}},"responses":{"200":{"description":"Computed result for timestamp_converter","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"unix_seconds":{"description":"Unix timestamp in seconds since epoch (Jan 1 1970 00:00:00 UTC).","type":"number"},"unix_milliseconds":{"description":"Unix timestamp in milliseconds since epoch.","type":"number"},"iso_8601":{"description":"ISO 8601 formatted string in UTC (e.g. '2024-01-15T10:30:00.000Z').","type":"string"},"iso_date":{"description":"Date portion only (YYYY-MM-DD).","type":"string"},"iso_time":{"description":"Time portion only (HH:MM:SS).","type":"string"},"day_of_week":{"description":"Day of the week (e.g. 'Monday').","type":"string"},"relative":{"description":"Human-readable relative time (e.g. '2 hours ago', 'in 3 days').","type":"string"},"is_past":{"description":"True if the timestamp is in the past.","type":"boolean"}},"required":["unix_seconds","unix_milliseconds","iso_8601","iso_date","iso_time","day_of_week","relative","is_past"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/bmi_calculator":{"get":{"summary":"Metadata for bmi_calculator","operationId":"get_bmi_calculator","tags":["general"],"responses":{"200":{"description":"Metadata for bmi_calculator","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate Body Mass Index (BMI) from weight and height using the WHO standard formula. Supports metric (kg/cm) and imperial (lbs/inches) units. Returns the BMI value, WHO classification (Underweight, Normal, Overweight, Obese Class I-III), and the healthy weight range for the given height. Formula: BMI = weight_kg / (height_m)^2. Useful for health screening, fitness planning, and clinical intake forms.","operationId":"compute_bmi_calculator","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"weight":{"description":"Body weight. Units determined by the 'unit' parameter.","type":"number"},"height":{"description":"Height. Units determined by the 'unit' parameter.","type":"number"},"unit":{"type":"string","enum":["metric","imperial"],"default":"metric","description":"Unit system. 'metric' = kg and cm. 'imperial' = lbs and inches. Defaults to 'metric'."}},"required":["weight","height"]}}}},"responses":{"200":{"description":"Computed result for bmi_calculator","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"bmi":{"description":"Body Mass Index value rounded to 1 decimal.","type":"number"},"category":{"description":"WHO BMI classification: Underweight, Normal weight, Overweight, Obese Class I/II/III.","type":"string"},"healthy_weight_range_low":{"description":"Low end of healthy weight range (BMI 18.5) in the input unit system.","type":"number"},"healthy_weight_range_high":{"description":"High end of healthy weight range (BMI 24.9) in the input unit system.","type":"number"},"weight_unit":{"description":"Unit of the weight values in this response (kg or lbs).","type":"string"}},"required":["bmi","category","healthy_weight_range_low","healthy_weight_range_high","weight_unit"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/tip_calculator":{"get":{"summary":"Metadata for tip_calculator","operationId":"get_tip_calculator","tags":["general"],"responses":{"200":{"description":"Metadata for tip_calculator","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate tip and split a restaurant bill among multiple people. Given a bill amount, tip percentage, and number of diners, returns the tip amount, total with tip, per-person share, and effective tip percentage. Supports rounding up to the nearest whole number for convenience. Defaults to 18% tip for 1 person. Currency-agnostic — works with any monetary unit.","operationId":"compute_tip_calculator","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"bill_amount":{"description":"Total bill amount before tip (any currency).","type":"number"},"tip_pct":{"type":"number","default":18,"description":"Tip percentage. Common values: 15 (standard), 18 (good), 20 (great), 25 (excellent). Defaults to 18%."},"split":{"type":"number","default":1,"description":"Number of people splitting the bill. Defaults to 1 (no split)."},"round_up":{"type":"boolean","default":false,"description":"Round the total up to the nearest whole number. Defaults to false."}},"required":["bill_amount"]}}}},"responses":{"200":{"description":"Computed result for tip_calculator","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"tip_amount":{"description":"Tip amount.","type":"number"},"total":{"description":"Bill plus tip.","type":"number"},"per_person_tip":{"description":"Each person's share of the tip.","type":"number"},"per_person_total":{"description":"Each person's total including their share of the bill and tip.","type":"number"},"effective_tip_pct":{"description":"Actual tip percentage after rounding (if round_up is true, may differ from input).","type":"number"}},"required":["tip_amount","total","per_person_tip","per_person_total","effective_tip_pct"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}},"/api/date_difference":{"get":{"summary":"Metadata for date_difference","operationId":"get_date_difference","tags":["general"],"responses":{"200":{"description":"Metadata for date_difference","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Tool not found"}}},"post":{"summary":"Calculate the difference between two dates in days, weeks, months, years, and business days. Accepts dates in YYYY-MM-DD format. Returns the absolute difference (order doesn't matter) plus a flag indicating whether the end date is in the future relative to start. Business days count only Monday through Friday. Useful for project planning, deadline tracking, contract duration calculations, and age computations.","operationId":"compute_date_difference","tags":["general"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"start_date":{"description":"Start date in YYYY-MM-DD format (e.g., '2024-01-15').","type":"string"},"end_date":{"description":"End date in YYYY-MM-DD format (e.g., '2024-12-31').","type":"string"}},"required":["start_date","end_date"]}}}},"responses":{"200":{"description":"Computed result for date_difference","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","properties":{"days":{"description":"Total number of days between the two dates (absolute value).","type":"number"},"weeks":{"description":"Number of complete weeks.","type":"number"},"months":{"description":"Approximate number of months (days / 30.44).","type":"number"},"years":{"description":"Approximate number of years (days / 365.25).","type":"number"},"business_days":{"description":"Number of weekdays (Monday-Friday) between the dates.","type":"number"},"is_future":{"description":"True if end_date is after start_date.","type":"boolean"}},"required":["days","weeks","months","years","business_days","is_future"]},"tool":{"type":"string"},"version":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"chain":{"type":"object","properties":{"feeds":{"type":"array"},"accepts_from":{"type":"array"}}}},"required":["result","tool","version","computed_at","chain"]}}}},"400":{"description":"Validation error or invalid JSON"},"404":{"description":"Tool not found"}}}}}}