Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
93415ce
Add geothermal extraction integration artifacts
bpulluta Mar 17, 2026
d9e868d
Add COMPASS workflow skills
bpulluta Mar 17, 2026
54b8d29
Added one-shot skills
bpulluta Mar 17, 2026
a71447f
update one-shot SKILL.md structure and trigger contracts
bpulluta Mar 17, 2026
74495a6
Initial plan (#398)
Copilot Mar 17, 2026
81fcbff
Fix skills documentation: correct paths, caching behavior, and tab fo…
Copilot Mar 17, 2026
1b8571f
renamed skills and fixed minor comments
bpulluta Mar 19, 2026
bc1a516
Merge branch 'feature/skills-pr' into feature/geothermal-extraction-pr
bpulluta Mar 20, 2026
61f9b2e
fix URL space encoding and anchor text scoring in website crawl retri…
bpulluta Mar 20, 2026
bac918c
remove testing skills
bpulluta Mar 20, 2026
dab97ff
fixed schema
bpulluta Mar 21, 2026
c6eb335
Refactor URL sanitization: shared helper, space-only encoding, robust…
Copilot Mar 21, 2026
93ad791
Bump release-drafter/release-drafter from 7.0.0 to 7.1.1 (#402)
dependabot[bot] Mar 24, 2026
a0fbd55
Add One-Shot Skills Reliability and Guardrails (#397)
bpulluta Mar 26, 2026
56fe389
updated schema, added cli overwrite option, and added optional post p…
bpulluta Mar 30, 2026
87e72d3
fix ruff error in components.py
bpulluta Mar 31, 2026
eaaab54
ruff check on components.py
bpulluta Mar 31, 2026
ca3aaac
fix ruff errors in process.py
bpulluta Mar 31, 2026
7ea2627
ruff check on updated files
bpulluta Mar 31, 2026
197a98c
Bump codecov/codecov-action from 5 to 6 (#403)
dependabot[bot] Mar 30, 2026
633ecdf
Merge remote-tracking branch 'origin/main' into feature/geothermal-ex…
ppinchuk Mar 31, 2026
a9c8929
Update tox file
ppinchuk Mar 31, 2026
314af43
Update tox file
ppinchuk Mar 31, 2026
c4f335b
Merge branch 'main' into feature/geothermal-extraction-pr
bpulluta May 20, 2026
e325f0a
resolved pending comments in PR400. Cleaned up logic.
bpulluta May 20, 2026
d766e45
fix: Wrapped long docstring lines for ruff
bpulluta May 20, 2026
a8ba59c
updated YAML
bpulluta May 21, 2026
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
123 changes: 121 additions & 2 deletions compass/_cli/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

import asyncio
import logging
import shutil
import sys
import warnings
import multiprocessing

from pathlib import Path

import click
from rich.live import Live
from rich.theme import Theme
Expand All @@ -14,8 +18,11 @@
from compass.pb import COMPASS_PB
from compass.plugin import create_schema_based_one_shot_extraction_plugin
from compass.scripts.process import process_jurisdictions_with_openai
from compass.utilities.logs import AddLocationFilter
from compass.utilities.io import load_config
from compass.utilities.logs import AddLocationFilter


OUT_DIR_POLICY_CHOICES = ["fail", "increment", "overwrite", "prompt"]


@click.command
Expand Down Expand Up @@ -49,10 +56,24 @@
default=None,
help="One-shot plugin configuration to add to COMPASS before processing",
)
def process(config, verbose, no_progress, plugin):
@click.option(
"--out_dir_exists",
required=False,
default=None,
type=click.Choice(OUT_DIR_POLICY_CHOICES, case_sensitive=False),
help="How to handle an existing output directory."
" Choices: fail, increment, overwrite, prompt."
" If omitted, prompts interactively when running in a terminal,"
" or fails when running non-interactively (e.g. CI).",
)
def process(config, verbose, no_progress, plugin, out_dir_exists):
"""Download and extract ordinances for a list of jurisdictions"""
config = load_config(config)

config["out_dir"] = _resolve_out_dir_conflict(
config["out_dir"], out_dir_exists
)

if plugin is not None:
create_schema_based_one_shot_extraction_plugin(
config=plugin, tech=config["tech"]
Expand Down Expand Up @@ -128,3 +149,101 @@ def _setup_cli_logging(console, verbosity_level, log_level="INFO"):
handler.addFilter(AddLocationFilter())
logger.addHandler(handler)
logger.setLevel(log_level)


def _resolve_out_dir_conflict(out_dir, policy):
"""Handle existing output directory using the selected policy"""
out_dir = Path(out_dir)
policy = _resolve_out_dir_policy(policy)

if not out_dir.exists() or policy == "fail":
return out_dir

if policy == "increment":
new_out_dir = _next_versioned_directory(out_dir)
click.echo(
"Output directory exists. "
f"Using incremented directory: {new_out_dir!s}"
)
return new_out_dir

if policy == "overwrite":
click.echo(f"Overwriting existing output directory: {out_dir!s}")
shutil.rmtree(out_dir)
return out_dir

if policy == "prompt":
return _resolve_prompt_out_dir_conflict(out_dir)

msg = (
f"Unknown out_dir_exists policy '{policy}'. "
f"Supported values: {OUT_DIR_POLICY_CHOICES}."
)
raise click.ClickException(msg)


def _next_versioned_directory(out_dir):
"""
Create the next available output directory suffix with
versioning
"""
idx = 2
max_idx = 1_000_000
while idx <= max_idx:
candidate = out_dir.parent / f"{out_dir.name}_v{idx}"
if not candidate.exists():
return candidate
idx += 1

msg = (
f"Unable to find an available versioned directory for '{out_dir!s}' "
f"up to suffix _v{max_idx}."
)
raise click.ClickException(msg)


def _resolve_out_dir_policy(policy):
"""Resolve output directory policy from explicit input

Falls back to terminal mode defaults when no policy is set.
"""
if policy is not None:
return policy.lower()
if sys.stdin.isatty():
return "prompt"
return "fail"


def _resolve_prompt_out_dir_conflict(out_dir):
"""Handle interactive prompt flow for existing output directory"""
if not sys.stdin.isatty():
msg = (
"Cannot use out_dir_exists='prompt' in non-interactive mode. "
"Use one of: fail, increment, overwrite."
)
raise click.ClickException(msg)

create_incremented = click.confirm(
f"Output directory '{out_dir!s}' already exists. "
"Create a new incremented directory automatically?",
default=True,
)
if create_incremented:
new_out_dir = _next_versioned_directory(out_dir)
click.echo(f"Using incremented directory: {new_out_dir!s}")
return new_out_dir

overwrite = click.confirm(
f"Overwrite '{out_dir!s}' by deleting it and continuing?",
default=False,
)
if overwrite:
click.echo(f"Overwriting existing output directory: {out_dir!s}")
shutil.rmtree(out_dir)
return out_dir

msg = (
"Run cancelled. Please update out_dir in config, or rerun with "
"--out_dir_exists increment/overwrite."
)
raise click.ClickException(msg)
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
schema: ./geothermal_schema.json

data_type_short_desc: utility-scale geothermal electricity ordinance

cache_llm_generated_content: true

query_templates:
- "filetype:pdf {jurisdiction} geothermal power plant ordinance"
- "geothermal electricity generation ordinance {jurisdiction}"
- "{jurisdiction} geothermal energy facility zoning ordinance"
- "{jurisdiction} geothermal power plant land use code"
- "{jurisdiction} geothermal code of ordinances"

website_keywords:
pdf: 92160
geothermal: 46080
ordinance: 23040
zoning: 11520
regulation: 5760
code: 2880
power: 1440
electricity: 1440
planning: 720
permit: 720
land use: 720
municipal: 720
county: 360
ordinance code: 360
code of ordinances: 360
land use code: 360
use table: 360
chapter: 180
article: 180
title: 180
statute: 180
administrative code: 180
conditional use permit: 180
special use permit: 180
drilling permit: 180
resource development: 180
government: 180

heuristic_keywords:
good_tech_keywords:
- "wellfield"
- "brine"
good_tech_acronyms:
- "egs"
- "kgra"
good_tech_phrases:
- "well field"
- "production well"
- "geothermal exploration"
- "geothermal generating"
- "geothermal generation"
- "geothermal power"
- "geothermal power plant"
- "geothermal production"
- "geothermal project"
- "geothermal overlay zone"
- "geothermal facility"
- "geothermal electric"
- "geothermal electricity generation"
- "geothermal energy facility"
- "geothermal resource"
- "geothermal resource development"
- "known geothermal resource area"
- "geothermal production project"
- "geothermal drilling"
- "geothermal lease"
- "geothermal development"
- "geothermal well"
- "geothermal reservoir"
- "binary cycle"
- "flash steam"
- "dry steam"
- "steam turbine"
- "enhanced geothermal"
- "reservoir temperature"
- "reinjection well"
- "production zone"
- "exploratory well"
- "injection well"
- "drilling permit"
- "plan of utilization"
not_tech_words:
- "geothermal heat pump"
- "ground source heat pump"
- "ground-source heat pump"
- "ghp"
- "ground heat pump"
- "gshp"
- "ground-coupled heat pump"
- "ground coupled heat pump"
- "earth-coupled heat pump"
- "earth-source heat pump"
- "geoexchange"
- "geo-exchange"
- "closed loop"
- "closed-loop"
- "open loop"
- "vertical loop"
- "horizontal loop"
- "heating and cooling"
- "hvac"
- "space heating"
- "water heating"
- "direct use"
- "direct-use"
- "district heating"
- "greenhouse heating"
- "residential geothermal"
- "accessory use"
- "energy star"
- "solar panel"
- "solar array"
- "solar farm"
- "solar energy system"
- "solar energy facility"
- "photovoltaic"
- "net metering"
- "solar collector"
- "solar ordinance"
- "wind energy"
- "wind farm"
- "wind turbine"
- "wind energy system"
- "wind energy facility"
- "wind energy conversion"
- "wind ordinance"
- "anemometer tower"
- "meteorological tower"
- "rotor diameter"
- "tip height"
- "nacelle"
- "battery storage"
- "energy storage system"
- "hydroelectric"
- "biomass"
- "cannabis"
- "cannabis cultivation"
- "commercial cannabis"

collection_prompts: True
Loading
Loading