hcl-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| PYTHONPATH | No | Only for a local clone launched from source — set to the src dir. Default: —. | |
| SMARTSPATH | No | SMARTS executable — the file, not its directory. Default: unset (SMARTS engine unavailable). | |
| HCL_WORK_ROOT | No | Directory where simulation files are written. Default: first MCP client root, else ~/hcl_work. | |
| HCL_DAYSIM_BIN | No | Daysim bin directory (ds_shortterm, epw2wea). Default: auto-discovered on PATH. | |
| HCL_RADIANCE_BIN | No | Radiance bin directory, if not on PATH. Default: auto-discovered on PATH. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
| logging | {} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| extensions | {
"io.modelcontextprotocol/ui": {}
} |
| completions | {} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| spd_to_channelsA | Average a spectral power distribution into the 3- or 9-channel bins. spd: a |
| glass_transmissivityA | Convert glazing transmittance (0-1) to Radiance transmissivity. Accepts a number or list. Transmittance (Tvis, the datasheet number) and transmissivity (the value a Radiance glass primitive takes) are NOT the same: transmissivity is always the larger, e.g. 0.70 -> 0.763. USE THIS ONLY when hand-writing a Radiance glass primitive. Do NOT pre-convert for
The float|list annotation is load-bearing: without it FastMCP emits an empty arg schema and delivers the value as a string, so the core's transmittance-squared term would raise (DEF-1). |
| write_materialC | Write Radiance material .rad file(s). material_type 0=glass,1=plastic. Honors client roots for work_dir. |
| circadian_metricsA | Photopic / melanopic / neuropic equivalent illuminance from channel irradiances. Returns one metrics dict for a single point, or a list of dicts for many points. Each carries
BOTH spd: the SOURCE spectrum feeding these channels, when known ( |
| alpha_opicA | CIE S 026 alpha-opic E/ELR/EDI. Provide spd accepts a For the |
| validateB | Run the built-in correctness self-test (weight sums, alpha-opic guards). |
| spectral_metricsA | Derived HCL quantities from an SPD: cct/duv, mel-DER, mel/photopic ratio, and EML<->EDI. spd accepts a
|
| complianceA | Check a value against a lighting standard. standard: well_v2_l03 | brown_2022 | iso_cie_8995_1_2025 | en_17037 | en_12464_1 | ul_24480. CIRCADIAN standards are scored on standard="en_12464_1" is the ELECTRIC VISUAL-TASK path and ignores mel_edi entirely: pass
|
| presetsA | List available illuminant presets (CIE standards + illustrative LED models), or fetch one by name. Names: D65, D50, A, FL1..FL12, and the illustrative LED models LED_3000K/4000K/5000K/BLUEPUMP/VIOLETPUMP (flagged illustrative, not measured - see spec 5.7). Returns SPD + metadata when a name is given. |
| colored_skyA | Generate a colored Perez sky+sun Radiance definition. mode 'spectra' (per-channel spectral scaling, runs gendaylit) or 'luminance' (Radiance -C built-in coloring, 3-channel only, pure emit). irrad_mode 'W' (direct+diffuse) or 'E' (global). diffuse_channels/direct_channels: 3 or 9 channel values (from spd_to_channels); ignored in luminance mode. lon is standard signed / EAST-positive (Seattle = -122.3, Athens = 23.73), matching raw EPW. SOLAR POSITION. By default the sun is derived by gendaylit's own ephemeris from month/day/hour +
lat/lon/utc, and To keep them on one instant, pass that record's geometry through here VERBATIM:
sun_zenith_deg = record["geometry"]["zenith_deg"]
sun_azimuth_deg = record["geometry"]["azimuth_deg"]
Both are required together; supplied, they emit gendaylit's |
| colored_luminaireA | Inject a channel triplet into a luminaire .rad, writing a NEW file (never edits the input). count: 0=blue,1=green,2=red third of 9 values. The colored definition is written to work_dir (client-roots aware) as .rad — the source rad_path is left untouched — and its absolute path is returned. rad_path may be a .rad file path or raw .rad text. Returns {file, rad}. |
| referenceB | Look up HCL reference content. topic: bins | coefficients | caveats | overview. |
| run_gridB | Point-in-time grid HCL metrics via Radiance (oconv -> rtrace -I per channel -> recombine). scene_sets: 1 list of .rad paths for 3-channel, or 3 lists (blue/green/red bin sets) for 9-channel. points: rows [x,y,z,dx,dy,dz] or a .pts path. Runs Radiance if present, else returns the commands. export_csv: optional path (abs or relative to work_dir) to dump the per-point result table. sky_files: which scene paths are sky, listed exactly as they appear in scene_sets. Only matters
with electric_lights, which builds a sky-free octree for the |
| run_imageC | Fisheye HCL image workflow: rpict -> mel/neuropic greyscale luminance maps (falsecolor-ready) -> optional ipRGC FOV weighting -> RGB-from-HDR eye irradiance. Runs Radiance if present, else returns the commands. |
| import_geometryA | Import a Wavefront .obj room into a per-channel Radiance scene (obj2rad -> xform). material_map: {group_name: spec} keyed by OBJ usemtl (else g) names; unmapped groups hard-fail. spec is a library-name string (illustrative reflectance) or a dict {"type": "plastic"|"glass"|"ground"|"context"|"luminaire"|"floor", "refl"/"tvis": float, ...}: plastic=opaque diffuse; glass=transmitting; ground=opaque + drives ground_albedo; context=exterior shading (in oconv, excluded from sensor footprint/room-sanity); luminaire=marker + IES (-> electric_lights); floor=opaque + anchors the sensor footprint. units: mm|cm|m|ft. up_axis: Y|Z. v2/v3 parameters:
Returns geometry_set + material_sets (index-aligned per channel-set) to compose into
run_grid / run_annual scene_sets, plus discovered groups and warnings, an always-present
|
| check_geometryA | Health-check an OBJ scene without building it (spec 2026-07-23). Reports geometry defects that would otherwise complete silently and return a plausible
number: coplanar surfaces (Radiance z-fighting), glazing with no opening cut in the
wall, duplicated and non-planar faces, an unclosed enclosure. Every error and warning
carries a Needs no Radiance binaries and builds no scene, so it is cheap to re-run while fixing a model. import_geometry embeds the same report as result["health"]. |
| radiance_statusA | Report Radiance availability: {available, bin_dir, version, found, missing}. Use this to check whether Radiance tools (run_grid, ...) will execute vs return commands. |
| weatherB | Ingest a .wea (DNI/DHI per timestamp) and/or decompose an analysis period into HOY + wea line numbers. Returns |
| run_annualA | Annual 2-phase DDS HCL simulation (per channel) -> annual mel-EDI + circadian dosimetry. channel_scenes: 1 dict (3ch) or 3 dicts (9ch), each {materials:[paths], geometry:path,
sky_color:[r,g,b]}. NOTE each dict's |
| nvrdA | Light-driven alerting response over time (Amundadottir nvRD). spectral_series: per-timestep spectral irradiance rows (311 pts 390-700 nm, or 401 pts 380-780) as an inline list, OR a path to a text/CSV file with one row per line. PREFER THE FILE PATH for large/full-resolution series: a big inline array can be truncated over the MCP wire (e.g. 401-pt rows arriving as 367) and then fail the row-length check. Rows must be a SINGLE point+view orientation, in CHRONOLOGICAL order, ideally uniformly spaced at timestep_h. Pre-group multi-orientation/multi-day data and call once per orientation (§9.4 — the source's automatic per-orientation grouping is not reproduced in v1). timestep_h: hours per step. Must be <= 0.3 and yield odd nvRD filter lengths; the model is validated at 0.1 (= 6 min), the recommended value. Other steps raise ValueError. You supply the series (no Daysim). hours: optional explicit per-timestep hour vector for non-uniform spacing; must be monotonically non-decreasing. When omitted, a uniform grid (i*timestep_h) is used. Returns effective_irradiance, relative_response, and cumulative_response per timestep. |
| ies_analyzeA | Parse an IESNA LM-63 luminaire and return its photometric report (rated lumens, watts, efficacy, max candela + location, beam/field angles, zonal flux down/up, LOR). ies: raw IES text or a file path. |
| ies_to_radianceB | Convert an IES luminaire to a Radiance .rad via ies2rad, optionally placed via xform. -m carries user scaling only (multiplier * maintenance_factor); ies2rad applies the IES candela/ballast/pfactor itself. Runs ies2rad if Radiance is present, else returns the commands. |
| glare_ugrC | Render a fisheye (daylight and/or electric_lights) and run evalglare -> UGR/DGP/glare sources. Delegates to run_image with glare=True. Runs Radiance if present, else returns the commands. |
| lighting_controlsA | Daylight-responsive lighting-control calculator (EnergyPlus §7.3.5; verified vs elec_lights.xlsx). Point-in-time: pass itot_per_point=[lx at each reference point] -> {fL, fP, FP, P_elec, P_saved, reduction}. Annual/series: pass itot_series=[[lx per point] per hour] + area -> {per_hour, annual_kwh, annual_kwh_per_m2, mean_FP, mean_reduction, occupied_hours}. weights are the per-point area weights (e.g. from area_weights_from_geometry). control_type: ContinuousOff (default) | Continuous | Stepped. workbook_compat=True reproduces the elec_lights.xlsx off-gates (regression). |
| daylight_savingsA | Automated daylight-responsive savings: daylight sim at the reference points -> lighting_controls. mode='point_in_time' uses run_grid (scene_sets + points; supports multiple reference points); mode='annual' uses run_annual_daylight (channel_scenes + wea + points, 8760 h) and supports a multi-point grid (one weight per reference point) via points=[...] or sensor_set='name'. run=False emits the command plan without executing. An annual run elicits confirmation first (it is long); decline -> the emitted plan is returned. weights: one per reference point, interpreted as that daylight zone's FLOOR-AREA FRACTION, so they must sum to <= 1.0 (NOT one-per-zone full-power flags -- e.g. [1, 1] is invalid; use [0.4, 0.3] etc.). The leftover (1 - Σweights) is the uncontrolled core area billed at full power. For a single point pass [1.0]. Compute proper fractions with hcl_core.lighting_controls.area_weights_from_geometry(width, length, window_head, task_height). Return shapes: {"ran": False, ...commands...} (not executed); {"ran": True, "error": ..., "failed_step": ...} (a Radiance step failed mid-run); else {"ran": True, "mode": ..., "controls": ...} on success. Note: in annual mode with schedule=None, the default weekday 08:00-18:00 mask is built to the
length run_annual returns and assumes an 8760-h, Monday-anchored (HOY 0 = Mon 00:00) series. If
run_annual is run over a sub-period or a non-Monday-anchored year, pass an explicit |
| annual_daylightB | Annual climate-based daylight metrics on the grid: per-point DA/cDA/UDI + spatial sDA/ASE. channel_scenes: 1 dict (3ch) or 3 dicts (9ch), each {materials:[paths], geometry:path, sky_color:[r,g,b]} -- same shape as run_annual. points: inline rows or a .pts path; OR pass sensor_set='name' (created via the sensors tool). ASE uses a dedicated direct-only (-ab 0) pass. occupancy: optional per-timestep 0/1 mask (defaults to weekday occupied_start..end, Monday-anchored 8760-h). Runs Radiance if present, else returns the command sequence. shading_model: declare the scene's operable shading -- 'none' (no device modelled),
'modelled' (a device is in the geometry) or 'lm83_default_blind'. The returned |
| lm83_daylightA | IES LM-83-12 sDA(300/50%) and ASE(1000,250h) with MANDATORY operable blinds. Unlike annual_daylight, which computes the arithmetic of sDA/ASE on whatever shading the scene happens to contain, this runs LM-83's method: a three-phase (V.T.D.s) engine per window group, an hourly blind that closes when 2.2.6's direct-sun trigger fires, and a zero-bounce ASE pass with blinds retracted and no sky or ground (3.2.6, 3.3). obj_path + material_map: the same OBJ room and material mapping import_geometry takes. Glazing must be mapped {"type": "glass", "tvis": ...} -- window groups are formed from those faces, and with no glass face there is no window to operate. units (mm|cm|m|ft) and up_axis (Y|Z) describe the OBJ, defaulting to metres and Z-up; north_angle_deg is the clockwise azimuth post-remap +Y points toward. These decide the facade azimuths that window grouping keys on, so a wrong up_axis silently regroups the windows. points: inline rows or a .pts path, OR sensor_set='name'. Grid spacing, workplane height and wall offset are MEASURED from these coordinates and reported, never accepted as parameters. areas: 2.2.6 trigger areas, [{name, area_m2, point_indices}], split by facade orientation and each under 10,000 sf -- the trigger must hold in EVERY area, and pooling facades dilutes the fraction so blinds close later than the standard requires. Omit and pass floor_area_m2 to get a single whole-grid area, which is only correct for a single-facade space. An area over 10,000 sf is refused before any Radiance runs. blind: the operable shade, per 2.2.7. Omitted -> the unknown-shade default of 5% diffuse VLT. {"shade_type": "fabric", "vlt": .., "openness": ..}, {"shade_type": "louver", "reflectance": >0.8} for the 20% white-louver branch, or {"bsdf": "path.xml"} for a measured Klems file. Note the default is 5%, NOT 20% -- the 20% figure is the louver branch and needs a declared reflectance. window_groups: optionally declare grouping instead of auto-clustering by azimuth and plane, [{name, face_indices, role}] with role 'view' or 'clerestory' -- 2.2.6 asks that view groups close before clerestory ones, and role cannot be inferred from azimuth. declared_no_blinds: assert the design documents state no blinds (2.2.6's escape clause). Reported as a per-group condition; it never replaces the headline, which always operates blinds. Returns |
| daylight_factorB | Daylight Factor (%) per point under the CIE Standard Overcast Sky (gensky -c). DF = E_indoor / E_outdoor * 100, with E_outdoor traced from a sky-only exterior reference. scene_sets: the building scene as a single 3-channel list of .rad paths (materials + geometry); the overcast sky is added internally. points: inline rows or a .pts path, OR sensor_set='name'. Returns df_per_point + df_avg/df_min/uniformity + e_outdoor, or the command plan when not run. |
| sensorsA | Manage named, persistent daylight sensor sets (reused across annual_daylight / daylight_factor / daylight_savings via sensor_set='name'). action: 'create' | 'list' | 'get' | 'delete'. create: name + (points=[[x,y,z,dx,dy,dz],...] OR grid={interior:[xmin,xmax,ymin,ymax], floor_z, workplane_h?, max_spacing?}); overwrite=True to replace an existing set. list: all saved sets (name, path, count, source). get: name -> the set's points + .pts path. delete: name -> remove the set. |
| daysim_statusA | Report Daysim availability (ds_shortterm + epw2wea) via HCL_DAYSIM_BIN or PATH. Returns {available, bin_dir, version, found, missing}. No subprocess run except a best-effort version probe. Daysim is built from source locally (never bundled); use build_daysim if missing. |
| build_daysimA | Build Daysim (ds_shortterm + epw2wea) from source: clone master + headless arm64 CMake. run=True executes if git+cmake are present; otherwise returns the ordered command plan + a reason. On success, bin_dir is the build/bin directory — set it as HCL_DAYSIM_BIN. Daysim is NOT bundled (NRC/Fraunhofer ISE source-available EULA); this clones+builds on your machine. |
| generate_subhourly_weaA | EPW -> sub-hourly broadband .wea via Daysim (epw2wea -> .hea -> ds_shortterm). timestep_min default 6 (0.1 h) satisfies the nvRD step guard. Site location defaults to the EPW's own LOCATION line (converted to the DAYSIM convention), so normally you only pass the epw + work_dir. Pass explicit latitude/longitude/time_zone/site_elevation only to override — and only in DAYSIM convention: WEST-positive longitude, time_zone in DEGREES (= -15 × UTC offset); do NOT pass raw EPW East-positive coordinates. Runs Daysim if present, else returns the command plan + the written .hea so you can build Daysim and run it yourself. |
| reconstruct_spectrumA | Reconstruct a 401-value 380-780 nm @1 nm per-nm spectrum from sky+sun channel sets (spec §5.2). method: 'faithful' (flat §9.3a step-expansion + neutral sun -> reproduces the legacy 2.0 method) or 'reference' (reference-SPD-shaped sky + air-mass colored direct sun; re-integrates to the channel bin totals). sun_spectral: 'colored' (air-mass solar SPD by solar_zenith) | 'neutral' (flat). dseries_sky=True reconstructs a per-timestep CIE D-series sky from sky_cct. sun_spd: optional 401-value physical sun reference that overrides the air-mass template. Returns the spectrum + the flat-vs-reference and neutral-vs-colored-sun divergence (always surfaced). |
| annual_nvrdA | Annual light-driven alertness (nvRD R_D) straight from weather (spec §5.1). LONG-RUNNING. EPW -> Daysim sub-hourly .wea -> colored 2-phase DDS (sky & sun separate) -> per-timestep dual
reconstruction (faithful flat + neutral sun; enhanced reference sky + air-mass colored sun) ->
nvRD twice -> {faithful:{R_D,RD_cum}, enhanced:{R_D,RD_cum}, divergence, RD_series_divergence}.
R_D is RELATIVE only. SINGLE reference point+view per run. reconstruction={both|faithful|enhanced}
(default both). timestep_min default 6 (0.1 h). run=False emits the full Daysim+Radiance command plan
— but Site location is read from the EPW itself (converted to DAYSIM convention by the Daysim adapter); the tool takes no caller-supplied coordinates, so wrong-convention coordinates cannot silently corrupt the solar geometry. |
| recommend_fixturesC | First-principles HCL fixture sizing: lumen-method visual flux reconciled with a CIE S 026 mel-DER circadian solve. Returns flux, count, layout, CCT band, energy, and explicit caveats. distribution: direct|direct_indirect|indirect. Deterministic - always runs. See operating-guide.md workflow F. |
| atmosphere_from_epwB | Derived atmospheric state (AOD, PWV, ozone, pressure, albedo, aerosol_g + provenance). Opt-in refinements (defaults reproduce prior output): ozone_mode='climatology' computes ozone from the EPW LOCATION lat/lon + date (van Heuklon 1979); aerosol_g overrides the 0.65 asymmetry; aod_anchor_nm converts a declared-wavelength AOD (e.g. 550) to tau500 via the Angstrom exponent. |
| spectral_sky_from_epwA | Physical spectral sky (1nm direct + sky-diffuse) reconstructed from an EPW hour. Returns the canonical record as a dict. If surface_tilt_deg is given, also returns the spectral ground-glow term for that receiver tilt. spectral_albedo (len 401, 380-780nm @1nm) overrides the default gray albedo — pass import_geometry(...)["ground_albedo"] to couple scene ground reflectance to the sky ground-glow term. engine: spectrl2 (default) | smarts (requires SMARTSPATH). Opt-in refinements (defaults reproduce prior output): ozone_mode='climatology' computes ozone from the EPW LOCATION lat/lon + date (van Heuklon 1979); aerosol_g overrides the 0.65 asymmetry; aod_anchor_nm converts a declared-wavelength AOD (e.g. 550) to tau500 via the Angstrom exponent. smarts_aerosol (engine="smarts" only): None/"rural" (default) or "user" to make the Ångström exponent + asymmetry factor settable via the SMARTS Card 8 USER aerosol model. cloud_variant: which SEDES1 cloud CCM to apply to the sky-diffuse spectrum — 'reanchored' (default, byte-identical to omitting this arg) | 'verbatim' (faithful Fig.11 CCM) | 'seed' (legacy eyeballed 9-anchor seed) | 'local' (your own locally-fitted CCM, requires ccm_coeffs). ccm_coeffs: path to a fitted CCM CSV (from sedes1_fit) — required when cloud_variant='local'. |
| spectral_epwA | Emit spectral-sky artifacts from an EPW over the year (or forms ⊆ {spd_set, band_matrix, spectral_wea, sidecar} (default all). Writes into work_dir and
returns {files: {form: path}, n_records}. Opt-in refinements (defaults reproduce prior output): ozone_mode='climatology' computes ozone from the EPW LOCATION lat/lon + date (van Heuklon 1979); aerosol_g overrides the 0.65 asymmetry; aod_anchor_nm converts a declared-wavelength AOD (e.g. 550) to tau500 via the Angstrom exponent. smarts_aerosol (engine="smarts" only): None/"rural" (default) or "user" to make the Ångström exponent + asymmetry factor settable via the SMARTS Card 8 USER aerosol model. cloud_variant: which SEDES1 cloud CCM to apply to the sky-diffuse spectrum — 'reanchored' (default, byte-identical to omitting this arg) | 'verbatim' (faithful Fig.11 CCM) | 'seed' (legacy eyeballed 9-anchor seed) | 'local' (your own locally-fitted CCM, requires ccm_coeffs). ccm_coeffs: path to a fitted CCM CSV (from sedes1_fit) — required when cloud_variant='local'. |
| spectral_sky_nativeA | Native Radiance 6.x spectral sky from an EPW via gensdaymtx (20-band W/sr/m² matrix). mode: all | sun (-d) | sky (-s). Degrades to emitting the gensdaymtx + rcomb command plan when
Radiance 6.x isn't installed. The melanopic collapse is
|
| save_briefA | Persist (shallow-merge) a study brief to //brief.json. Call after each phase. |
| load_briefA | Load a study brief (empty skeleton if none). Call at journey start to resume where you left off. |
| build_reportC | Render a study brief to //report.{md,html}: goal recap, fixture spec, target-vs-achieved table with pass/fail, circadian↔glare cross-check, compliance. Always runs. |
| workplane_gridA | EN 12464-1 working-plane illuminance grid from an OBJ room. Interior extent via inner-surface detection (bbox of inward-facing vertical wall faces), plane at floor-top + workplane_h, max spacing p=0.2*5^log10(d) with d=the larger dimension of the calculation area (the interior inset by border_offset, per EN 12464-1 -- not the raw interior extent), cell-centre points. Returns points [x,y,z,0,0,1] + a methodology breakdown; writes a .pts (write_pts=None to skip). material_map OR sidecar is required (to identify floor & walls). clip_to_footprint (default True) drops lattice cells outside the floor slab for non-rectangular rooms (ignored when interior_extent is supplied explicitly); footprint_border insets the kept region from the footprint edges. |
| observer_pointsA | Workstation eye-point observers from an OBJ room. Auto-detects seat objects (seat_pattern) paired to screen objects (screen_pattern) by trailing suffix: eye = seat centroid at floor-top+eye_height, gaze = eye->screen centroid (dz=0). Fallback when no screen: direction_fallback in {window, azimuth, sweep}. No seats: position_fallback. Pass workstations=[{eye:[x,y], target:[x,y]|azimuth}] to bypass detection. Returns observers + glare_views (DGP fisheye) + a .pts. material_map OR sidecar required. clip_to_footprint (default True) does NOT move observers (they are furniture-anchored) — it only reports, via a warning, any observer whose eye position falls outside the floor slab. |
| photosensorsA | Daylight-dimming photosensors from an OBJ room (methodology.md §3). Locates the dominant glazed facade, builds sidelighting zones from the window head height (zone_rule='head_height' with depth_factors like [1,2], or 'ies_2.5'), and places one horizontal sensor per zone at sensor_fraction of the zone depth, centred on the facade and clipped to the floor. mount='workplane' (z=floor+workplane_h, up) or 'ceiling' (down). Returns points [x,y,z,dx,dy,dz] + a per-zone methodology; writes a .pts. material_map OR sidecar required (to identify floor & glazing). |
| preview_sceneA | matplotlib PNG preview of a room with sensor overlays (plan + 3D). render: 'grid' (grid, plan+3d), 'observers' (plan), 'observers_3d' (3d), or 'all' (all layers, plan+3d). Point layers are given as .pts paths OR inline [x,y,z,dx,dy,dz] rows in the post-north frame; layers left None are simply omitted. Diagnostic overlays only — not a photometric render. material_map OR sidecar required. |
| quality_presetsA | Ambient-quality presets: pick the accuracy/runtime trade-off up front, by name. Radiance's ambient parameters govern the indirect (interreflected) solve, which dominates both
runtime and the accuracy of every climate-based metric. Passing no Levels, cheapest first: low -ab 0 : geometry checks and direct-sun questions only. NO interreflection. medium -ab 2 : draft studies and design comparison. Preview-grade convergence. high -ab 3 : reportable results — DA/sDA/UDI, compliance. Use this to publish. extra_high -ab 5 : indirect-dominated scenes (light shelves, atria) and validation. Call with no argument for the full table including each level's caveat; call with a level to
get just that one. Pass the level to a simulation tool as |
| get_referenceB | Look up HCL reference content. topic: bins | coefficients | caveats | overview. |
| list_presetsA | List available illuminant presets (CIE standards + illustrative LED models), or fetch one by name. Names: D65, D50, A, FL1..FL12, and the illustrative LED models LED_3000K/4000K/5000K/BLUEPUMP/VIOLETPUMP (flagged illustrative, not measured - see spec 5.7). Returns SPD + metadata when a name is given. |
| import_weatherA | Ingest a .wea (DNI/DHI per timestamp) and/or decompose an analysis period into HOY + wea line numbers. Returns |
| run_validationB | Run the built-in correctness self-test (weight sums, alpha-opic guards). |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
| spd_to_circadian | Guide: turn an SPD into circadian metrics + compliance. |
| hcl_grid_study | Guide: set up a point-in-time grid HCL analysis. |
| fisheye_eye_analysis | Guide: fisheye/FOV eye-level circadian analysis. |
| annual_circadian_dose | Guide: annual circadian dose workflow. |
| explain_concept | Guide: explain an HCL metric/method/component, grounded in the reference resources. |
| electric_lighting_design | Guide: a full electric + daylight HCL design pass with savings and EN 12464-1 interpretation. |
| annual_alertness | Guide: annual light-driven alertness (nvRD R_D) from weather, interpreted RELATIVELY. |
| hcl_studio | Guide: the full start-to-finish HCL artificial-lighting journey — goal → fixture design → simulate → visualize/analyze — with a resumable study brief. The front door to a complete study. |
| import_obj_room | Guide: import a Wavefront .obj/CAD room into a per-channel Radiance scene, then run an HCL study. |
| spectral_sky_from_epw | Guide: reconstruct a physical spectral sky from an EPW hour and read its circadian metrics. |
| place_sensors | Guide: produce EN 12464-1 grid + workstation observer points from an imported OBJ room. |
| annual_daylight_study | Guide: annual climate-based (photopic) daylight metrics — DA/cDA/UDI/sDA/ASE + Daylight Factor + multi-point daylight-linked energy savings, over named persistent sensor sets. |
| visualize_scene | Guide: render matplotlib PNG previews of a room with its sensor points. |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| reference-coefficients | Verified photopic/melanopic/neuropic coefficient vectors (3- and 9-channel). |
| reference-bins | v3.0 wavelength bin definitions (3- and 9-channel). |
| reference-ies | IESNA LM-63 data-line layout, photometric/units types, and derived metrics. |
| reference-lighting-controls | EnergyPlus §7.3.5 daylight-responsive lighting-control equations. |
| reference-daysim | Daysim adapter build-from-source steps, ds_shortterm/epw2wea I/O, and credits. |
| reference-nvrd-bridge | The annual->nvRD bridge data flow and honesty caveats (spec §5.1, §5.3). |
| reference-geometry | The import_geometry contract: material_map shape (+ surface library), the obj2rad Material/Group qualifier rule, units/axis/north, per-channel assembly, run-or-emit, and the v2/v3 conveniences (dual-height sensors, ground-albedo bridge, context-shading, drop-in electric_lights, manifest sidecar+header). |
| compliance-en-12464-1 | EN 12464-1:2021 maintained-illuminance/UGR/Uo/Ra task table + relationships. |
| reference-caveats | Correctness-critical port caveats: float-division fix, channel ordering, image-vs-grid b3. |
| reference-glossary | Definitions: mel-EDI, EML, mel-DER, CCT/Duv, alpha-opic, photopic/melanopic/neuropic. |
| index | One-read catalog of every resource + valid template argument values. |
TDQS
Scored across 51 tools
There are at least four exact duplicate pairs (validate/run_validation, presets/list_presets, reference/get_reference, weather/import_weather), and many simulation/sensor tools overlap heavily (run_annual vs annual_daylight vs lm83_daylight vs annual_nvrd; run_grid vs daylight_factor). An agent cannot reliably distinguish which tool to call.
Most names are readable snake_case, but the set mixes verb_noun (run_grid, import_geometry), noun_verb (glass_transmissivity, workplane_grid), and bare-noun tools (sensors, presets, reference, weather). The duplicate pairs use different conventions for the same function, so no predictable pattern emerges.
51 tools is far beyond the calibration threshold for a well-scoped server, and many are near-duplicates or aliases that inflate the surface without adding capability. This is an extreme mismatch between the number of tools and what a coherent HCL server needs.
The domain surface is genuinely broad: geometry import/health/sensors, sky/weather spectral reconstruction, annual/daylight/glare/circadian simulations, compliance, controls, and reporting are all present. Minor gaps exist (e.g. non-conformant LM-83 method, unsupported UL 24480, no Radiance install path), but agents can work around them.