This runbook explains how to build all GeoSQL deliverables from source.
- Python 3.8+
pip
From repo root:
pip install build
python3 -m buildArtifacts:
dist/geosql-<version>-py3-none-any.whldist/geosql-<version>.tar.gz
From repo root:
python3 scripts/build_skill_package.pyArtifact:
geosql.skill
The package is generated from canonical sources only:
geosql/SKILL.mdgeosql/references/*
pip install -e .
python3 -m geosql --help
geosql --helpExplicit installs:
geosql install claude
geosql install codex
geosql install copilot
geosql install allExpected paths:
~/.claude/skills/geosql/SKILL.md~/.codex/skills/geosql/SKILL.md~/.copilot/skills/geosql/SKILL.md
After each successful command, verify the optional Dekart step matches the current state:
- No
dekartonPATH: the short arrow-key menu explains the map-in-the-loop benefit, defaults to the recommended install option, and shows the exact pip and init commands before consent. dekartinstalled butdekart tools --jsonis not ready: GeoSQL skips pip and offers onlydekart init.dekartinstalled inside an isolated GeoSQL environment: GeoSQL skips pip and, with consent, exposes a launcher beside the reachablegeosqlcommand before init.dekart tools --jsonsucceeds: GeoSQL reports both tools ready without prompting.- Non-interactive input/output: GeoSQL never runs pip or init and prints repeatable setup commands.
geosql install all: the Dekart check and optional prompt appear once, after all skill copies succeed.
The Cloud setup path selected by dekart init does not require Docker. Declining or cancelling the optional step must return success because the GeoSQL skill is already installed.
Run the installer regression tests:
python3 -m unittest tests.test_cli -vFor a clean interactive machine with Python, Claude Code, a nested Docker daemon, the repository mounted at /workspace, and host port 8080 forwarded:
make shell-docker-claudeThe target uses a privileged Docker-in-Docker container so nested containers and their data disappear when the shell exits. Disposable describes data cleanup, not security isolation: --privileged can compromise a native Linux Docker host, and inherited Claude credentials are available to processes in the container. Run this target only with trusted repository code, or run Docker itself inside a disposable VM when you need a real host boundary.
The local repository is the only read/write mount, so source changes persist. The interactive shell matches the invoking host UID/GID to avoid root-owned checkout files on Linux. The outer host publish for port 8080 is loopback-only. The nested -p 8080:8080 listener is still reachable from trusted peer containers on the local Docker bridge, so do not use it for untrusted services. The local test image and Docker build cache remain after exit, but container state, Claude login created inside it, nested images, and nested containers are removed. The target inherits ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN when either is exported; otherwise run /login inside Claude. macOS Keychain login cannot be mounted into the Linux container.
Inside the shell:
python -m pip install -e .
geosql install claude
docker run --rm -d --name dekart -p 8080:8080 dekartxyz/dekart
claudeIf host port 8080 is already occupied, Docker refuses to start the disposable shell without leaving a container behind.
rg -n "giskill|gis-skill" .Expected result: no matches.
Install hooks path:
./scripts/install_hooks.shThe pre-push hook runs only on main and performs:
- Rebuild
geosql.skilland commit if changed. - Bump minor version in
pyproject.tomland commit (separate commit). - Build package and publish to PyPI.
- Exit with non-zero so you run
git pushagain and include the new commits.
Optional environment variable:
export PYPI_API_TOKEN='pypi-...'If PYPI_API_TOKEN is not set, hook falls back to your local Twine auth
(~/.pypirc, keyring, or interactive prompt).
Recommended push flow on main:
git push # hook runs, creates commits, publishes, exits non-zero intentionally
git push # push new local commitsFrom repo root:
make shell-dekart-claude
claude --dangerously-skip-permissionsInside Claude:
- If prompted with
Not logged in, run/loginfirst. - Select model via
/model(pickOpus 4.7from available models).
Do not hardcode model id in this flow because model names/availability can vary by account and release.
If your local Claude build uses different bypass flag names, check:
claude --help | rg -i "model|permission|bypass|danger"Then run the equivalent bypass-permissions flag supported by your version.
Use bypass mode only in trusted local repositories.
Run one Dekart eval case non-interactively from the isolated shell:
python3 evals/run.py \
--case london-boroughs-dekart-bigquery \
--model opus \
--thinking-level mediumFrom repo root:
make shell-dekart-copilotInside the shell:
command -v copilot
command -v dekart
command -v bq || true
command -v snow || true
python -m geosql install copilot
test -f ~/.copilot/skills/geosql/SKILL.md
test -f ~/.copilot/skills/geosql/references/map-styling.mdThen start Copilot and verify it recognizes the GeoSQL skill with a prompt like:
/geosql Show EV charger density along major roads and render a map