Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions agents/energy-modeler.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ maxTurns: 50

You are an expert building energy modeler with deep knowledge of:

- **EnergyPlus**: All object types, simulation parameters, output reporting, and best practices for versions 8.9 through 25.2
- **EnergyPlus**: All object types, simulation parameters, output reporting, and best practices for versions 8.9 through the latest supported
- **Building thermodynamics**: Heat transfer, thermal mass, solar gains, infiltration, ventilation
- **HVAC system design**: Air-side systems (VAV, CAV, DOAS), water-side systems (chillers, boilers, heat pumps), controls, and sizing
- **ASHRAE standards**: 90.1 (energy), 62.1 (ventilation), 55 (thermal comfort), 189.1 (high-performance)
- **idfkit tooling**: All 40 MCP tools and 11 resources for schema exploration, model editing, validation, integrity checks, simulation, peak load analysis, weather data, and interactive viewers (geometry, schedules, reports)
- **idfkit tooling**: The full idfkit MCP toolset and `idfkit://…` resources for schema exploration, model editing, validation, integrity checks, simulation, peak load analysis, weather data, version migration, and interactive viewers (geometry, schedules, reports) — consult the live tool list for the authoritative set

## Working Principles

Expand Down
8 changes: 4 additions & 4 deletions commands/quick-sim.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ Run a complete simulation workflow for: $ARGUMENTS
1. Load the model with `load_model`
2. Read the `idfkit://model/summary` resource for a brief overview
3. Validate with `validate_model` and `check_model_integrity` — report any issues but continue if non-critical
4. Check for weather data — if no weather file is configured, search for one based on the model's Site:Location
5. Run `run_simulation` with annual=true
4. Check for weather data — if no weather file is configured, `search_weather_stations` based on the model's Site:Location, then `download_weather_file` and pass its EPW path as `weather_file` (a search alone leaves the run with no weather)
5. Run `run_simulation` with `design_day=true, annual=true` (sizing + annual in one pass, so autosized equipment is sized before the annual run)
6. Read the `idfkit://simulation/results` resource and present:
- Total energy consumption and intensity (kWh/m2)
- Energy breakdown by end-use
- Peak loads
- Unmet hours
- Any simulation errors or warnings
- Unmet hours (occupied, heating and cooling separately; ASHRAE 90.1 target ≤ 300 each)
- Any QA flags, simulation errors, or warnings
7. Use `view_simulation_report` to open the interactive report viewer for deeper exploration
8. Ask user if they want to fix any issues and re-run, or if they want to explore specific results in more detail
33 changes: 10 additions & 23 deletions scripts/check-deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,7 @@ else
issues+=("uvx is not installed. Install uv (https://docs.astral.sh/uv/getting-started/installation/) to use the idfkit MCP server and LSP.")
fi

# 2. Check idfkit-mcp availability (don't actually install, just check)
if command -v uvx &>/dev/null; then
if uvx --help &>/dev/null 2>&1; then
info+=("idfkit-mcp: will be available via uvx")
fi
fi

# 3. Look for EnergyPlus installation
# 2. Look for EnergyPlus installation
ep_dir=""

# Check user config first
Expand All @@ -37,22 +30,16 @@ if [[ -z "$ep_dir" && -n "${ENERGYPLUS_DIR:-}" ]]; then
fi
fi

# Auto-detect on macOS
if [[ -z "$ep_dir" ]]; then
for d in /Applications/EnergyPlus-*/; do
if [[ -d "$d" ]]; then
ep_dir="$d"
fi
done
fi

# Auto-detect on Linux
# Auto-detect (macOS + Linux standard locations). Glob expansion is lexical, so
# EnergyPlus-9.6.0 would sort after EnergyPlus-25.2.0 — pick the highest version
# explicitly with `sort -V`.
if [[ -z "$ep_dir" ]]; then
for d in /usr/local/EnergyPlus-*/; do
if [[ -d "$d" ]]; then
ep_dir="$d"
fi
done
shopt -s nullglob
ep_candidates=(/Applications/EnergyPlus-*/ /usr/local/EnergyPlus-*/)
shopt -u nullglob
if (( ${#ep_candidates[@]} > 0 )); then
ep_dir=$(printf '%s\n' "${ep_candidates[@]}" | sort -V | tail -n1)
fi
fi

if [[ -n "$ep_dir" ]]; then
Expand Down
40 changes: 30 additions & 10 deletions scripts/inject-idf-context.sh
Original file line number Diff line number Diff line change
@@ -1,33 +1,53 @@
#!/usr/bin/env bash
# inject-idf-context.sh — Add EnergyPlus context when working with relevant files
# inject-idf-context.sh — Add EnergyPlus context when working with relevant files.
#
# Wired as a PreToolUse hook (Read|Edit|Write). PreToolUse plain stdout is NOT shown to the
# model — context must be returned as JSON via hookSpecificOutput.additionalContext.

# Read tool input from stdin
input=$(cat)

# Extract file_path from the JSON
file_path=$(echo "$input" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"file_path"[[:space:]]*:[[:space:]]*"//' | sed 's/"$//')
# Extract the target file path. PreToolUse nests it under .tool_input.file_path; fall back to a
# top-level .file_path. Requires jq for robust parsing (handles spaces, quotes, escapes).
if command -v jq &>/dev/null; then
file_path=$(printf '%s' "$input" | jq -r '.tool_input.file_path // .file_path // empty' 2>/dev/null)
else
# Minimal fallback if jq is unavailable.
file_path=$(printf '%s' "$input" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"file_path"[[:space:]]*:[[:space:]]*"//; s/"$//')
fi

if [[ -z "$file_path" ]]; then
exit 0
fi

# Get the file extension
ext="${file_path##*.}"
ext_lower=$(echo "$ext" | tr '[:upper:]' '[:lower:]')
# Lowercase extension
ext_lower=$(printf '%s' "${file_path##*.}" | tr '[:upper:]' '[:lower:]')

case "$ext_lower" in
idf)
echo "[idfkit] This is an EnergyPlus Input Data File (.idf). For structured editing, use the idfkit MCP tools (load_model, get_object, update_object, add_object) rather than raw text manipulation. The MCP tools handle reference tracking and validation automatically."
context="This is an EnergyPlus Input Data File (.idf). For structured editing, use the idfkit MCP tools (load_model, list_objects, update_object, add_object) or read the idfkit://model/objects/{type}/{name} resource rather than raw text manipulation. The MCP tools handle reference tracking and validation automatically."
;;
epjson)
echo "[idfkit] This is an EnergyPlus JSON input file (.epJSON). For structured editing, use the idfkit MCP tools (load_model, get_object, update_object) which handle schema validation and reference integrity."
context="This is an EnergyPlus JSON input file (.epJSON). For structured editing, use the idfkit MCP tools (load_model, list_objects, update_object) which handle schema validation and reference integrity."
;;
epw)
echo "[idfkit] This is an EnergyPlus Weather file (.epw). Use search_weather_stations and download_weather_file MCP tools to find and manage weather data. EPW files should generally not be edited manually."
context="This is an EnergyPlus Weather file (.epw). Use search_weather_stations and download_weather_file MCP tools to find and manage weather data. EPW files should generally not be edited manually."
;;
ddy)
echo "[idfkit] This is an EnergyPlus Design Day file (.ddy), typically paired with an EPW weather file. Design day data is used for HVAC sizing calculations."
context="This is an EnergyPlus Design Day file (.ddy), typically paired with an EPW weather file. Design day data drives HVAC autosizing; the design days must be injected into the model as SizingPeriod:DesignDay objects."
;;
*)
exit 0
;;
esac

# Emit as PreToolUse additionalContext so the model actually sees it.
if command -v jq &>/dev/null; then
jq -n --arg ctx "[idfkit] $context" \
'{hookSpecificOutput: {hookEventName: "PreToolUse", additionalContext: $ctx}}'
else
# Hand-rolled JSON fallback; context strings above contain no characters needing escaping.
printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":"[idfkit] %s"}}\n' "$context"
fi

exit 0
7 changes: 5 additions & 2 deletions skills/developing-with-idfkit/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@ here are about the library API, not the MCP tool surface.
Run the discovery script with the user's project directory:

```bash
python <SKILL_DIR>/scripts/discover.py --project-dir <USER_PROJECT_DIR>
python ${CLAUDE_SKILL_DIR}/scripts/discover.py --project-dir <USER_PROJECT_DIR>
```

Use the literal `${CLAUDE_SKILL_DIR}` token so the command matches the `allowed-tools` permission
pattern and runs without a prompt.

The script prints either:

- **A path on stdout** (exit 0) — the bundled `SKILL.md`. Read it; it routes into
Expand All @@ -43,7 +46,7 @@ The script prints either:
- **An `ERROR:` block on stderr** (non-zero exit). Follow the printed instructions
(install or upgrade idfkit, activate the right environment) and re-run.

`<SKILL_DIR>` is the directory containing this file; `<USER_PROJECT_DIR>` is the
`${CLAUDE_SKILL_DIR}` resolves to the directory containing this file; `<USER_PROJECT_DIR>` is the
absolute path to the user's project. Passing `--project-dir` matters because the
script resolves `.venv`, `../.venv`, `<git-root>/.venv`, `Pipfile`, `poetry.lock`,
`pdm.lock`, and `uv.lock` relative to it — so it inspects the user's project
Expand Down
33 changes: 12 additions & 21 deletions skills/idf-conventions/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,12 @@ paths: "**/*.idf, **/*.epJSON, **/*.epjson, **/*.py"

## idfkit MCP Tools & Resources

You have access to the idfkit MCP server with 40 tools and 11 resources across 10 categories:
This skill assumes the idfkit MCP server is available. Don't rely on a memorized tool count — consult
the **live tool list** and the server's own startup instructions for the authoritative set. The tools
span schema introspection, model read/write, validation + integrity, simulation + analysis, weather,
documentation, and version migration.

### Tools

**Schema** (4): `list_object_types`, `describe_object_type`, `search_schema`, `get_available_references`
**Read** (5): `load_model`, `list_objects`, `search_objects`, `convert_osm_to_idf`, `get_change_log`
**Write** (9): `new_model`, `add_object`, `batch_add_objects`, `update_object`, `remove_object`, `rename_object`, `duplicate_object`, `save_model`, `clear_session`
**Validation** (2): `validate_model` (includes reference checking via `check_references` parameter), `check_model_integrity`
**Simulation** (8): `run_simulation`, `list_output_variables`, `query_timeseries`, `query_simulation_table`, `list_simulation_reports`, `view_simulation_report`, `export_timeseries`, `analyze_peak_loads`
**Weather** (2): `search_weather_stations`, `download_weather_file`
**Documentation** (2): `search_docs`, `get_doc_section`
**Zone** (1): `get_zone_properties`
**Geometry** (1): `view_geometry`
**Schedules** (1): `view_schedules`

### Resources

Read these via MCP resource URIs for structured data:
Structured state is exposed as read-only `idfkit://…` resources you can read at any time, including:

- `idfkit://model/summary` — version, zones, object counts, and groups for the loaded model
- `idfkit://model/objects/{object_type}/{name}` — all field values for a specific object
Expand All @@ -36,6 +24,9 @@ Read these via MCP resource URIs for structured data:
- `idfkit://simulation/results` — energy metrics, errors, and tables from the last simulation
- `idfkit://simulation/peak-loads` — peak heating/cooling load decomposition with QA flags
- `idfkit://simulation/report` — full tabular simulation report organized by section and table
- `idfkit://migration/report` — per-step transition output and structural diff after `migrate_model`

The server may expose more — treat its live instructions as authoritative rather than this list.

## Key Conventions

Expand All @@ -47,7 +38,7 @@ Read these via MCP resource URIs for structured data:
### Field Names
- idfkit uses snake_case Python field names: `direction_of_relative_north`, `ceiling_height`
- The MCP tools accept these snake_case names in the `fields` parameter
- Extensible fields use numbered patterns: `vertex_1_x_coordinate`, `vertex_2_x_coordinate`, etc.
- Extensible groups use a structured array under a wrapper key — e.g. `BuildingSurface:Detailed` takes `vertices: [{vertex_x_coordinate, vertex_y_coordinate, vertex_z_coordinate}, …]`. (Flat numbered keys like `vertex_1_x_coordinate` are a deprecated compat shim that emits warnings — don't use them.) Check `describe_object_type`'s `extensible_group` for the exact key and item fields.

### Workflow Best Practices
1. **Always call `describe_object_type` before creating objects** — know valid fields, constraints, and defaults
Expand All @@ -60,9 +51,9 @@ Read these via MCP resource URIs for structured data:
8. **Read resources for object data** — use `idfkit://model/objects/{type}/{name}` to inspect objects and `idfkit://model/references/{name}` to check references

### Version Support
- Supported EnergyPlus versions: 8.9.0 through 25.2.0 (16 versions)
- Default version for new models: latest (25.2.0)
- Schemas are bundled — no EnergyPlus installation needed for editing, only for simulation
- Supported EnergyPlus versions: 8.9.0 through the latest supported (currently 26.1.0); idfkit exposes the newest as `LATEST_VERSION`
- Default version for new models: the latest supported version
- Schemas are bundled — no EnergyPlus installation needed for editing or schema validation; only simulation and version migration require an EnergyPlus install

### Common Object Categories
- **Simulation Parameters**: SimulationControl, Timestep, RunPeriod, Building
Expand Down
20 changes: 14 additions & 6 deletions skills/new-model/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,28 @@ Create a new building energy model based on: $ARGUMENTS

2. **Weather data** — Use `search_weather_stations` to find the closest weather station, then `download_weather_file` to get EPW + DDY files

3. **Create model** — Use `new_model` (defaults to latest EnergyPlus version). This seeds Version, Building, SimulationControl, and GlobalGeometryRules automatically.
3. **Create model** — Use `new_model` (defaults to the latest EnergyPlus version). This seeds **only**
Version, Building, SimulationControl, and GlobalGeometryRules. You must still add Timestep,
RunPeriod, and Site:Location yourself (see below) — `check_model_integrity` requires Timestep and
RunPeriod, and Site:Location is needed for solar geometry but is *not* caught by either QA gate.

4. **Build the model** using `batch_add_objects` for efficiency. Add in this order:
- **Schedules**: ScheduleTypeLimits and Schedule:Compact for occupancy, lighting, equipment, HVAC
- **Site & controls**: Site:Location (site lat/long/elevation/time zone), Timestep, RunPeriod
- **Schedules**: ScheduleTypeLimits and Schedule:Compact for occupancy, lighting, equipment, HVAC (every schedule needs a referenced ScheduleTypeLimits)
- **Materials and Constructions**: Wall/roof/floor materials and Construction objects
- **Zones**: Thermal zones matching the building layout
- **Surfaces**: BuildingSurface:Detailed for walls, floors, roofs with proper vertices
- **Surfaces**: BuildingSurface:Detailed for walls, floors, roofs with proper vertices (use the structured `vertices` array)
- **Fenestration**: FenestrationSurface:Detailed for windows/doors
- **Internal loads**: People, Lights, ElectricEquipment per zone
- **HVAC**: Zone equipment, air loops, plant loops as needed
- **Infiltration**: ZoneInfiltration:DesignFlowRate per zone (a zero-infiltration model is not credible)
- **HVAC**: Zone equipment, air loops, plant loops as needed — plus ZoneControl:Thermostat + ThermostatSetpoint:DualSetpoint (without thermostats, zones are uncontrolled and unmet-hours are meaningless), and Sizing:Zone / Sizing:System whenever equipment is autosized
- **Sizing periods**: SizingPeriod:DesignDay. There is **no DDY auto-import** — read the downloaded `.ddy` file and hand-author the design-day objects (or copy their values), then ensure SimulationControl enables zone/system sizing
- **Output**: Output:Variable and Output:Meter for key metrics
- **Sizing and RunPeriod**: SizingPeriod:DesignDay (from DDY), RunPeriod for annual

5. **Validate** — Run `validate_model` and fix any errors
5. **Validate** — Run `validate_model`, then `check_model_integrity`, and fix any errors. Schema +
integrity passing does **not** guarantee a successful run; for full confidence continue the QA loop:
`save_model` → `run_simulation` → read `idfkit://simulation/results` → fix → repeat until `qa_flags`
is empty.

6. **Save** — Use `save_model` to write the IDF/epJSON file

Expand Down
31 changes: 20 additions & 11 deletions skills/simulate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,39 @@ Simulate the model: $ARGUMENTS
- Check if the model has a Site:Location or weather file assigned
- If not, ask for the building location and use `search_weather_stations` + `download_weather_file`

4. **Run simulation** — Use `run_simulation` with appropriate parameters:
- `weather_file`: path to EPW file
- `design_day`: true for sizing runs
- `annual`: true for full-year simulation
4. **Sizing readiness** — If any equipment is autosized (the common case), the model needs a sizing
run before/with the annual run, or capacities resolve to zero. Confirm `SizingPeriod:DesignDay`
objects exist and `SimulationControl` enables zone/system sizing. (`check_model_integrity` checks
that `SimulationControl` is *present*, not that its sizing flags are *on*.)

5. **Run simulation** — Use `run_simulation` with appropriate parameters:
- `weather_file`: path to the EPW file
- `design_day`: true to run the sizing (design-day) periods
- `annual`: true for the full-year run
- For an autosized model, run `design_day=true, annual=true` together so sizing feeds the annual run
- `readvars`: true if you want standard ReadVars CSV output (`eplusout.csv`)
- Report progress and any warnings during the run

5. **Analyze results** — Read the `idfkit://simulation/results` resource for the overview:
6. **Analyze results** — Read the `idfkit://simulation/results` resource for the overview:
- **Energy consumption**: Total site/source energy, by end-use category
- **Energy intensity**: kWh/m² (or kBtu/ft²)
- **Peak loads**: Heating and cooling design loads
- **Unmet hours**: Hours where setpoints weren't met (target: < 300 heating + cooling)
- **Errors**: Any severe errors or warnings from the simulation
- **Unmet hours**: Occupied hours where setpoints weren't met — reported **separately** for heating
and cooling. ASHRAE 90.1 G3.1.2.3 targets **≤ 300 occupied unmet hours each** (not a heating +
cooling sum); for a baseline/proposed comparison the two models should also differ by ≤ 50 hours.
- **QA flags / errors**: resolve `qa_flags` and any severe errors or warnings from the simulation

6. **Peak load analysis** — Use `analyze_peak_loads` to decompose facility and zone peaks into components and flag QA issues.
7. **Peak load analysis** — Read the `idfkit://simulation/peak-loads` resource and use `analyze_peak_loads` to decompose facility and zone peaks into components and flag QA issues. (This requires the SensibleHeatGainSummary and HVACSizingSummary reports to be requested in the model.)

7. **Detailed analysis** — Use `query_timeseries` and `query_simulation_table` for specific metrics:
8. **Detailed analysis** — Use `query_timeseries` and `query_simulation_table` for specific metrics:
- Monthly energy breakdown
- Zone temperature profiles
- System performance metrics
- Use `list_output_variables` to see available time series data
- Use `list_simulation_reports` to see available tabular reports

8. **Interactive review** — Use `view_simulation_report` to browse the full tabular report interactively.
9. **Interactive review** — Use `view_simulation_report` to browse the full tabular report interactively.

9. **Export if requested** — Use `export_timeseries` to save results to CSV
10. **Export if requested** — Use `export_timeseries` to save results to CSV

Present results in a clear, organized format with the most important metrics highlighted.
Loading
Loading