{"id":46510274,"url":"https://github.com/toneillcodes/houndtrainer","last_synced_at":"2026-03-06T16:03:17.210Z","repository":{"id":322468707,"uuid":"1088733273","full_name":"toneillcodes/HoundTrainer","owner":"toneillcodes","description":"A tool for managing custom node types and Cypher queries in BloodHound","archived":false,"fork":false,"pushed_at":"2025-12-23T18:51:41.000Z","size":264,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-25T08:59:18.106Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/toneillcodes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-03T11:36:27.000Z","updated_at":"2025-12-23T18:51:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/toneillcodes/HoundTrainer","commit_stats":null,"previous_names":["toneillcodes/houndtrainer"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/toneillcodes/HoundTrainer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toneillcodes%2FHoundTrainer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toneillcodes%2FHoundTrainer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toneillcodes%2FHoundTrainer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toneillcodes%2FHoundTrainer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/toneillcodes","download_url":"https://codeload.github.com/toneillcodes/HoundTrainer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toneillcodes%2FHoundTrainer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30184885,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T14:42:24.748Z","status":"ssl_error","status_checked_at":"2026-03-06T14:42:14.925Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-03-06T16:03:12.214Z","updated_at":"2026-03-06T16:03:17.201Z","avatar_url":"https://github.com/toneillcodes.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/houndtrainer.png\"\u003e\n\u003c/p\u003e\n\n# Overview\nHoundTrainer is a tool for managing custom node types and cypher queries in BloodHound.\n## Quick Start \u0026 Prerequisites\nHoundTrainer requires Python 3.x.\nPandas is optional for model creation and the script will fallback to standard libraries for CSV parsing if the import is unavailable.\n1. Clone the repository\n```\n$ git clone https://github.com/toneillcodes/HoundTrainer.git\n$ cd HoundTrainer\n```\n\n2. Install dependencies\n```\n$ pip install -r requirements.txt\n```\n\n## Usage\n```\n$ python houndtrainer.py -h\nusage: houndtrainer.py [-h] {create,get,list,upload,export,delete,deleteall} ...\n\nManage custom types and cypher queries in BloodHound.\n\npositional arguments:\n  {create,get,list,upload,export,delete,deleteall}\n    create              Create a schema model from CSV definitions.\n    get                 Retrieve a specific resource\n    list                List custom node or cypher resources\n    upload              Upload custom node or cypher resources\n    export              Export custom node or cypher resources\n    delete              Delete a custom node or cypher resource\n    deleteall           Delete all custom node or cypher resources\n\noptions:\n  -h, --help            show this help message and exit\n$\n```\n\n## Operations\n* [create](#create-operation)\n* [list](#list-operation)\n* [get](#get-operation)\n* [upload](#upload-operation)\n* [export](#export-operation)\n* [delete](#delete-operation)\n* [deleteall](#deleteall-operation)  \nNOTE: For cypher operations, when no ```--scope``` argument is provided, the default scope used is 'owned'.\n\n### Create Operation\n#### Create a Custom Node Type Model\nCreate a model from CSV definitions\n```\nKind Name,Icon Name,Color\nExampleUser,user,#4D93D9\nExampleRole,user-group,#47D359\n```\nParse CSV (--csv) and generate JSON (--file)\n```\n$ python houndtrainer.py create --type model --csv examples\\example-model.csv --file examples\\example-model.json\nSuccess: Data written to examples\\example-model.json\n[INFO] Successfully wrote model from 'examples\\example-model.csv' to file 'examples\\example-model.json'.\n[INFO] Done.\n$\n```\nReferences: \n* [examples/example-model.csv](examples/example-model.csv)\n* [examples/example-model.json](examples/example-model.json)\n\n### List Operation\n#### List Custom Node Types\nList custom node types\n```\n$ python houndtrainer.py list --type node --url http://127.0.0.1:8080\n[INFO] Listing all custom types...\nEnter JWT:\n[INFO] ID: 280, Kind Name: ExampleUser\n[INFO] ID: 281, Kind Name: ExampleRole\n[INFO] Done.\n$\n```\nList output when no custom node types nodes are found\n```\n$ python houndtrainer.py list --type node --url http://127.0.0.1:8080\n[INFO] Listing all custom types...\nEnter JWT:\n[INFO] No custom kinds found.\n[INFO] Done.\n$\n```\n#### List Cypher Queries\nList output with cypher queries\n```\n$ python houndtrainer.py list --type cypher --url http://127.0.0.1:8080\n[INFO] Listing all cypher queries under scope: 'owned'...\nEnter JWT:\n[INFO] ID: 14, Query: Test Query\n[INFO] Done.\n```\nList output when no cypher queries are found\n```\n$ python houndtrainer.py list --type cypher --url http://127.0.0.1:8080\n[INFO] Listing all cypher queries under scope: 'owned'...\nEnter JWT:\n[INFO] No cypher queries found.\n[INFO] Done.\n$\n```\n\n### Get Operation\n#### Get a Custom Node Type\nRetrieve custom node type details by kind name (--name)\n```\n$ python houndtrainer.py get --type node --url http://127.0.0.1:8080 --name ExampleUser\n[INFO] Listing custom type for kind_name 'ExampleUser'...\nEnter JWT:\n[INFO] ID: 280, Name: ExampleUser, type: font-awesome, Name: user, Color: #4D93D9\n[INFO] Done.\n$\n```\n#### Get a Cypher Query\nRetrieve cypher query details by ID (--id)\n```\n$ python houndtrainer.py get --type cypher --url http://127.0.0.1:8080 --id 14\n[INFO] Retrieving cypher query for ID: '14'...\nEnter JWT:\n[INFO] ID: 14, Name: Test Query, Created_At: 2025-11-29T15:05:37.546016Z, Updated_At: 2025-11-29T18:02:40.993889Z, User_id: 0f916532-08f7-47f4-bf1b-37b2317cce1b, Description: Testing, Query: \"match(a:ExampleUser)\\nwhere a.objectid = 'Bob'\\nreturn a\"\n[INFO] Done.\n$\n```\n\n### Upload Operation\n#### Upload Custom Node Type Model\nUpload example-model.json\n```\n$ python houndtrainer.py upload --type node --url http://127.0.0.1:8080 --file examples\\example-model.json\n[INFO] Uploading model from file: examples\\example-model.json...\nEnter JWT:\n[INFO] Model uploaded successfully.\n[INFO] Operation 'upload' for type 'node' with file examples\\example-model.json was successful.\n[INFO] Done.\n$\n```\nConfirm upload success\n```\n$ python houndtrainer.py list --type node --url http://127.0.0.1:8080\n[INFO] Listing all custom types...\nEnter JWT:\n[INFO] ID: 282, Kind Name: ExampleUser\n[INFO] ID: 283, Kind Name: ExampleRole\n[INFO] Done.\n$\n```\nReferences: \n* [examples/example-model.json](examples/example-model.json)\n\n#### Upload Single Cypher Query\nCheck the list of Cypher Queries\n```\n$ python houndtrainer.py list --type cypher --url http://127.0.0.1:8080\n[INFO] Listing all cypher queries under scope: 'owned'...\nEnter JWT:\n[INFO] No cypher queries found.\n[INFO] Done.\n```\nUpload the example cypher query file ```examples\\example-cypher.json```\n```\n$ python houndtrainer.py upload --type cypher --url http://127.0.0.1:8080 --file examples\\example-cypher.json\n[INFO] Uploading query JSON from file: examples\\example-cypher.json...\nEnter JWT:\n[INFO] Cypher query uploaded successfully.\n[INFO] Operation 'upload' for type 'cypher' with file examples\\example-cypher.json was successful.\n[INFO] Done.\n```\nCheck the list of Cypher Queries\n```\n$ python houndtrainer.py list --type cypher --url http://127.0.0.1:8080\n[INFO] Listing all cypher queries under scope: 'owned'...\nEnter JWT:\n[INFO] ID: 17, Query: Test\n[INFO] Done.\n$\n```\nReferences: \n* [examples/example-cypher.json](examples/example-cypher.json)\n\n#### Upload Cypher Query Pack (ZIP)\nUpload a Cypher Query Pack \n```\n$ python houndtrainer.py upload --type cypher --url http://127.0.0.1:8080 --file examples\\example-cypher-pack.zip\n[INFO] Uploading query zip from archive: examples\\example-cypher-pack.zip...\nEnter JWT:\n[INFO] Query ZIP uploaded successfully.\n[INFO] Operation 'upload' for type 'cypher' with file examples\\example-cypher-pack.zip was successful.\n[INFO] Done.\n$\n```\nCheck the list of Cypher Queries\n```\n$ python houndtrainer.py list --type cypher --url http://127.0.0.1:8080\n[INFO] Listing all cypher queries under scope: 'owned'...\nEnter JWT:\n[INFO] ID: 22, Query: Test\n[INFO] ID: 23, Query: Another Test\n[INFO] ID: 24, Query: Find Helpdesk Admins\n[INFO] ID: 25, Query: Find DA Users\n[INFO] Done.\n$\n```\n\n### Export Operation\n#### Export a Custom Node Type\nExport a Custom Node Type by kind name (--name)\n```\n$ python houndtrainer.py export --type node --url http://127.0.0.1:8080 --name ExampleRole --file examples\\example-custom-type.json\n[INFO] Listing custom type for kind_name 'ExampleRole'...\nEnter JWT:\nSuccess: Data written to examples\\example-custom-type.json\n[INFO] Successfully wrote 'node' data to file 'examples\\example-custom-type.json'.\n[INFO] Done.\n$\n```\nReferences: \n* [examples/example-custom-type.json](examples/example-custom-type.json)\n#### Export All Custom Node Types\nExport all Custom Node Types into one JSON file\n```\n$ python houndtrainer.py export --type node --url http://127.0.0.1:8080 --all --file examples\\example-custom-types.json\n[INFO] Exporting all custom types...\n[INFO] Listing all custom types...\nEnter JWT:\n[INFO] kindName found: ExampleUser.\n[INFO] kindName found: ExampleRole.\n[INFO] Successfully exported 'node' data to file 'examples\\example-custom-types.json'.\n[INFO] Done.\n$\n```\nReferences: \n* [examples/example-custom-type.json](examples/example-custom-type.json)\n#### Export a Cypher Query\nExport cypher query by ID (--id)\n```\n$ python houndtrainer.py export --type cypher --url http://127.0.0.1:8080 --id 16 --file examples\\example-cypher.json\n[INFO] Exporting cypher query ID '16'...\nEnter JWT:\nSuccess: Data written to examples\\example-cypher.json\n[INFO] Successfully wrote 'cypher' data to file 'examples\\example-cypher.json'.\n[INFO] Done.\n$\n```\nReferences:\n* [examples/example-cypher.json](examples/example-cypher.json)\n\n#### Export All Cypher Queries\nExport all cypher queries to a ZIP (--file)\n```\n$ python houndtrainer.py export --type cypher --url http://127.0.0.1:8080 --all --file examples\\example-cypher-pack.zip\n[INFO] Exporting cypher queries for scope 'owned'...\nEnter JWT:\n[INFO] Saving cypher archive as: 'examples\\example-cypher-pack.zip'\n[INFO] Successfully exported 'cypher' data to file 'examples\\example-cypher-pack.zip'.\n[INFO] Done.\n$\n```\n\n### Delete Operation\n#### Delete a Custom Node Type by kind name\nDelete a Custom Node Type by kind name (--name)\n```\n$ python houndtrainer.py delete --type node --url http://127.0.0.1:8080 --name ExampleUser\n[INFO] Deleting custom type: ExampleUser\nEnter JWT:\n[INFO] Deleted custom type: ExampleUser\n[INFO] Successfully completed delete for node.\n[INFO] Done.\n$\n```\nConfirm deletion\n```\n$ python houndtrainer.py list --type node --url http://127.0.0.1:8080\n[INFO] Listing all custom types...\nEnter JWT:\n[INFO] ID: 283, Kind Name: ExampleRole\n[INFO] Done.\n$\n```\n#### Delete a Cypher Query by ID\nDelete Cypher Query by ID (--id)\n```\n$ python houndtrainer.py delete --type cypher --url http://127.0.0.1:8080 --id 14\n[INFO] Deleting cypher query ID: '14'\nEnter JWT:\n[INFO] Deleted custom type: 14\n[INFO] Successfully completed operation 'delete' for cypher.\n[INFO] Done.\n$\n```\nConfirm deletion\n```\n$ python houndtrainer.py list --type cypher --url http://127.0.0.1:8080\n[INFO] Listing all cypher queries under scope: 'owned'...\nEnter JWT:\n[INFO] No cypher queries found.\n[INFO] Done.\n$\n```\n\n### Deleteall Operation\n#### Delete all Custom Node Types\nDelete all Custom Types\n```\n$ python houndtrainer.py list --type node --url http://127.0.0.1:8080\n[INFO] Listing all custom types...\nEnter JWT:\n[INFO] ID: 280, Kind Name: ExampleUser\n[INFO] ID: 281, Kind Name: ExampleRole\n[INFO] Done.\n$\n\n$ python houndtrainer.py deleteall --type node --url http://127.0.0.1:8080\n[INFO] Running operation 'deleteall' for type 'node'.\nEnter JWT:\n[INFO] Operation deleteall requires confirmation.\nEnter 'Y' to continue and 'N' to cancel: Y\n[INFO] Deleting all custom types...\n[INFO] Listing all custom types...\n[INFO] Deleting custom type: ExampleUser\n[INFO] Deleted custom type: ExampleUser\n[INFO] Deleting custom type: ExampleRole\n[INFO] Deleted custom type: ExampleRole\n[INFO] Successfully completed operation 'deleteall' for type 'node'.\n$\n\n$ python houndtrainer.py list --type node --url http://127.0.0.1:8080\n[INFO] Listing all custom types...\nEnter JWT:\n[INFO] No custom kinds found.\n[INFO] Done.\n$\n```\n\n#### Delete all Cypher Queries\n```\n$ python houndtrainer.py deleteall --type cypher --url http://127.0.0.1:8080\nEnter JWT: \n[INFO] Deleting all custom types...\n[INFO] Listing custom types...\n[INFO] Deleting custom type: ExampleUser\n[INFO] Deleted custom type: ExampleUser\n[INFO] Deleting custom type: ExampleSecurityUser\n[INFO] Deleted custom type: ExampleSecurityUser\n[INFO] Deleting custom type: ExampleGroup\n[INFO] Deleted custom type: ExampleGroup\n[INFO] Deleting custom type: ExampleClass\n[INFO] Deleted custom type: ExampleClass\n[INFO] Done.\n$\n\n$ python houndtrainer.py list --type cypher --url http://127.0.0.1:8080\nEnter JWT: \n[INFO] Listing custom types...\n[INFO] No custom kinds found.\n[INFO] Done.\n$\n```\n\n## Authentication\n* This script uses a JWT for authentication and expects the value to be provided during runtime.\n* To obtain a JWT (legally) login to your BHE or CE instance and view the 'Network' tab in the 'Developer Tools' in your browser of choice.\n* This approach aligns with the recommendation from SpecterOps for quick API calls  \nhttps://bloodhound.specterops.io/integrations/bloodhound-api/working-with-api#use-a-jwt%2Fbearer-token\n\n## API Reference\nAll operations utilize the following endpoints\n| Operation Type | Endpoint |\n| ---- | ---- |\n| node| custom-nodes |\n| cypher | saved-queries |\n\n## TODO\n* ~~Print all custom type details to STDOUT~~ Added 11/29/25\n* ~~Output node data to a file~~ Added 11/29/25\n* Support for authentication with an API key\n* Ability to pass a list of IDs or Kind Names for get/export operations\n* Validate operation to validate icon and OG schemas\n\n## Shoutouts\n* [c0kernel](https://github.com/C0KERNEL): for help with testing, documentation updates and suggestions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoneillcodes%2Fhoundtrainer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftoneillcodes%2Fhoundtrainer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoneillcodes%2Fhoundtrainer/lists"}