Stand-alone tooling to turn a collection of domain-specific semantic models (Turtle/RDF) into an interactive ontology "hairball" visualisation with a built-in AI chat assistant.
hairball.py— Python script that merges domain TTLs, generates the visualisation HTML, and exports the ontology context JSON used by the assistant.index.mjs— AWS Lambda script that serves the static files from S3 and handles/api/chatvia Amazon Bedrock (Claude).sample-models/— drop your*.ttlfiles here.Pipfile— Python dependencies (managed viapipenv).
- Install Python deps with pipenv:
pipenv install
- Drop your TTL files under
sample-models/(one per domain — the filename becomes the domain label). - Run the script inside the pipenv environment:
…or use the named script shortcut:
pipenv run python hairball.py
Outputs go topipenv run hairball
./output/<VERSION>/:index.html,ontology.html,ontology-with-object-properties.htmlontology-context.jsonmerged-ontology.ttl
- Open
output/<VERSION>/index.htmllocally to verify the visualisation. The chat widget will appear bottom-right but won't work until the Lambda is deployed.
All settings have sensible defaults — override with flags as needed:
pipenv run python hairball.py \
--input-dir ./sample-models \
--output-dir ./output \
--base-uri https://example.com/ontology/ \
--version 20260521 \
--strip-prefix "My Semantic Model - " \
[--no-graphbuild-fixes]
Run pipenv run python hairball.py --help for the full list.
- Create an S3 bucket and upload the version folder:
aws s3 sync ./output/<VERSION>/ s3://<your-bucket>/<your-prefix>/
- Deploy the Lambda (Node.js 20.x or later):
zip lambda.zip index.mjs aws lambda create-function \ --function-name hairball-handler \ --runtime nodejs22.x \ --handler index.handler \ --role <lambda-role-arn> \ --zip-file fileb://lambda.zip \ --timeout 60 \ --memory-size 256 \ --environment 'Variables={S3_BUCKET=<your-bucket>,S3_PREFIX=<your-prefix>/}' - Grant the Lambda role these permissions:
s3:GetObjectonarn:aws:s3:::<your-bucket>/<your-prefix>*bedrock:InvokeModelon the Claude inference profile you choose (defaults toeu.anthropic.claude-sonnet-4-5-20250929-v1:0)
- Front the Lambda with an ALB (or API Gateway). Route all paths to this Lambda:
GET <path>→ S3 file fetchPOST /api/chat→ Bedrock chatOPTIONS /api/chat→ CORS preflight
| Variable | Required | Default | Notes |
|---|---|---|---|
S3_BUCKET |
yes | — | S3 bucket holding the visualisation files |
S3_PREFIX |
no | '' |
Key prefix, include trailing slash (e.g. visualisations/) |
BEDROCK_MODEL_ID |
no | eu.anthropic.claude-sonnet-4-5-20250929-v1:0 |
Bedrock model or inference profile ID |
BEDROCK_REGION |
no | AWS_REGION or eu-west-2 |
Region for the Bedrock client |
DEFAULT_INDEX |
no | index.html |
File served for directory requests |
The Lambda loads ontology-context.json from S3 once per cold-start. When a user sends a question, it invokes Bedrock (Claude) with five tools defined over the parsed JSON: list_domains, get_domain_classes, get_class_details, search_terms, get_relationships. The LLM calls these tools to look up real ontology data, then composes a CLI-style plain-text answer.