# Openhound Entity Panels

> Add, migrate, review, or validate BloodHound OpenGraph entity-panel definitions for OpenHound node and relationship kinds on template-capable targets. Covers consolidated descriptions, mandatory direct-traversable relationship summaries, node-specific dynamic Cypher Explore links derived from graph evidence and saved searches, and upload-safe Markdown. Do not use for documentation-only edits that do not change entity panels.

- Skill: `specterops/openhound-entity-panels` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add specterops/openhound-entity-panels`
- Raw SKILL.md: https://api.skillmd.com/api/skills/specterops/openhound-entity-panels/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: specterops (https://skillmd.com/u/specterops)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/specterops/openhound-entity-panels

---


# OpenHound Entity Panels

Use this skill to update an OpenHound extension's `extension/schema.json` with
curated `info` panels.

For implementation, read
[references/panel-authoring.md](references/panel-authoring.md). For a
repository-wide migration, also read
[references/entity-agent-contract.md](references/entity-agent-contract.md).
Read [GUIDE.md](GUIDE.md) for installation, orchestration, and runtime testing.

## Required Outcome

Unless the user narrows the scope, update every object in `node_kinds` and
`relationship_kinds`.

Every node kind must have:

1. `description`, titled `Description`, at position 1.
2. `inbound_traversable_relationships`, titled `Inbound Traversable <Platform>
   Relationships`, at position 2.
3. `outbound_traversable_relationships`, titled `Outbound Traversable
   <Platform> Relationships`, at position 3.
4. One or more node-specific Cypher investigation items at later contiguous
   positions.

Put all useful source-description sections in the single Description item and
retain their section titles as level-two Markdown headers. Do not create one
accordion per prose section.

The two relationship-summary items are mandatory even when one direction has no
edges. Their query must cover every direct relationship of the extension that
is traversable in the stated direction. Render only one guarded dynamic Explore
link in the success state; do not add a prose
introduction or visible edge inventory. Record the exact inventory in fragment
metadata so completeness remains reviewable. An empty direction still gets a
link whose selected-node query deliberately returns no paths. Derive the
platform label from repository metadata, preferring the configured extension
short name and then the schema namespace.

Each later investigation item covers one concrete investigation goal for the
selected node. Derive its title, scope, and query from the node description,
incident relationships, and relevant files under `extension/saved_searches`.
Prefer two or more items when evidence supports distinct goals; do not
manufacture filler merely to reach a count.

For a role-like node, useful separation might be:

- `Role Assignments and Grant Sources`, anchored on inbound assignment and
  grant paths.
- `Accessible Resources`, anchored on outbound resource-access paths.
- `Administrative Capabilities`, when distinct
  administrative edges justify a separate investigation.

These are examples of investigation design, not universal titles. Use concise
noun phrases or short action labels, following BloodHound conventions such as
`Active Assignments`, `Approvers`, `Members`, and `Roles`. Investigation titles
must not be questions: do not end them with `?` or lead with question forms such
as `Who`, `What`, `Which`, `Where`, `When`, `Why`, `How`, `Can`, `Does`, `Is`,
or `Are`. A request, session, connector, resource, token, or other node kind
needs labels specific to its own graph semantics. Never create `Related
Entities`.

Unlike nodes, relationship descriptions are divided by source section. Every
level-two (`##`) heading becomes one relationship accordion in the same order.
Map `## General Information` (or `## General`) to `general`, titled `General`,
at position 1. Use the other H2 text as the panel title and a lowercase
URL-compatible semantic key such as `abuse_info`, `opsec_considerations`, or
`references`. Remove the H2 line from the panel body while retaining H3 and
deeper subsections, including cleanup or reverting instructions, inside their
parent panel. Do not merge separate H2 sections, create an empty panel, or
leave an H2 heading inside relationship panel Markdown. Preserve source order,
use contiguous positions, and never create a relationship `related_entities`
item or generated node-selection query.

## Evidence Priority

Inspect these sources for each kind:

1. Its complete object in `extension/schema.json`.
2. Its matching file under `descriptions/nodes` or `descriptions/edges`.
3. Every relevant JSON file under `extension/saved_searches`.
4. Supplemental graph documentation under `docs/graph`, when present.
5. Kind declarations and collector/model code that emits the entity.
6. Tests and other saved Cypher that establish graph semantics.

Use descriptions as canonical prose. Use saved-search names, descriptions, and
queries as evidence for investigative questions, path shapes, predicates,
optional context, and useful limits. Search the saved-search directory by node
kind, incident relationship kind, neighboring kind, and concepts named in the
description.

Do not copy a global saved search unchanged. Reframe the relevant slice around
the selected node instance, preserve meaningful predicates, remove unrelated
branches, and keep the resulting panel focused on one question. Multiple saved
searches may support one panel, and one broad saved search may inspire several
selected-node panels.

Do not invent behavior, properties, endpoints, or graph semantics. Record
missing or contradictory evidence as an assumption. Do not copy
repository-relative `.md` links or Mermaid blocks into panel Markdown.

## Node Query Design

Before drafting a node fragment:

1. Inventory the node's incident relationships, direction, neighboring kinds,
   and `is_traversable` values.
2. Inspect saved searches that contain the node or those relationships.
3. Populate the mandatory inbound and outbound summaries with every direct
   traversable extension relationship, including an explicit empty state.
4. Write down the distinct investigation goals a user would have after
   selecting this node.
5. Group relationships by goal and intent, not one accordion per edge.
6. Select the smallest query shape that serves each goal while keeping the
   selected node visible in the returned path.

A query item must:

- have a semantic key and human title specific to the node kind;
- use a concise non-question title;
- use ordinary words in its Explore-link text to explain what the view returns,
  without exposing node-kind or relationship-kind identifiers;
- contain exactly one Cypher query;
- anchor the selected node by exact label and stable `objectid`, using one
  escaped `%s` substitution in the dynamic query;
- use only schema-defined node and relationship identifiers;
- bind and return at least one path variable so Explore can visualize results;
- retain evidence-backed `WHERE`, variable-length, or `OPTIONAL MATCH`
  behavior when it materially answers the question; and
- put each Cypher operation such as `MATCH`, `OPTIONAL MATCH`, `WHERE`,
  `RETURN`, and `LIMIT` on a new line in the query string; and
- end with `LIMIT 500`.

An evidence-backed query may include a non-traversable descriptive relationship
when it provides useful investigation context. Do not describe it as an attack
path or traversable edge.

## Dynamic Explore Panels

The schema authoring surface supports `markdown.content`. Template execution
inside that string is a separate target-runtime capability. Schema upload does
not prove template support; a target without template execution can display
`{{ ... }}` literally. This skill authors dynamic Cypher panels only. Verify
the exact target with the entity-detail rendering probe in
`panel-authoring.md` before deployment. If the target is unavailable or fails
the probe, stop and report that dynamic entity panels cannot be validated; do
not create a fenced-query fallback.

Every relationship summary and investigation item must provide a guarded
Explore link generated from the selected node's `.Properties.objectid`:

- never use `.NodeID` as an `id`, `node_id`, or `objectid` property;
- normalize `objectid`, guard the blank case, and escape backslashes before
  single quotes;
- construct the complete query before `b64enc | urlquery`;
- put each Cypher operation on its own line by using `\n` inside the `printf`
  string;
- use the exact node label on the selected node and every endpoint whose kind
  is unambiguous from graph evidence; when an endpoint spans several kinds,
  use their verified common platform/base label if one exists, and leave it
  unlabeled only when no safe common label exists;
- end every query with `LIMIT 500`;
- use `/ui/explore` with `exploreSearchTab=cypher`, `searchType=cypher`,
  and `cypherSearch`; and
- render a useful fallback when the stable identifier is absent;
- render no success-state text except one Markdown Explore link; and
- write the link label in ordinary product/domain words rather than graph
  identifiers.

## Repository-Wide Orchestration

Use one agent per node kind and one agent per relationship kind. Never assign
multiple kinds to one entity agent. Waves may be needed for concurrency.

1. Read repository instructions and inventory the extension:

   ```bash
   python3 docs/og-docs-automation/skills/openhound-entity-panels/scripts/entity_panel_tool.py inventory --repo-root .
   ```

2. Create an isolated temporary run directory with one fragment path per kind.
3. Spawn one entity agent per inventory item using
   `references/entity-agent-contract.md`.
4. Review each node agent's complete direct-traversable relationship inventory,
   investigation goals, saved-search evidence, and panel metadata.
5. Assemble into a candidate, never over the source schema:

   ```bash
   python3 docs/og-docs-automation/skills/openhound-entity-panels/scripts/entity_panel_tool.py assemble \
     --schema extension/schema.json \
     --fragments <run-directory> \
     --output <candidate-schema.json>
   ```

6. Validate and inspect the candidate before applying it through the normal
   repository editing workflow.
7. Re-run validation and the extension's schema consistency and test commands.

The coordinator owns inventory, prompt consistency, target capability evidence,
cross-node query quality, merge, and final validation. Each entity agent owns
exactly one kind.

## Supported Schema and Markdown

Each accordion uses only:

- a lowercase URL-compatible section key;
- a non-empty `title`;
- a unique positive integer `position`; and
- `markdown.content`.

Do not emit section-level `query` or `props`, or put `position` inside
`markdown`.

Use the upload-safe Markdown subset in `panel-authoring.md`: no raw HTML or
comments, tag-shaped placeholders, fenced-code info strings, GFM task lists,
aligned tables, unsafe link schemes, or ordered-list blocks beginning above 1.
Node Cypher panels must use the guarded dynamic Explore-link form; fenced
Cypher queries are not supported by this skill.

## Scope Boundaries

- Change only entity panels and directly related skill, test, or validation
  files.
- Do not rewrite source descriptions to simplify generation.
- Do not change graph kinds, IDs, direction, traversability, collector behavior,
  or emitted properties without a separate request.
- Preserve unrelated and user-authored work.

## Validation

Run:

```bash
python3 docs/og-docs-automation/skills/openhound-entity-panels/scripts/entity_panel_tool.py validate --schema extension/schema.json
git diff --check
pwsh docs/og-docs-automation/scripts/Test-SchemaConsistency.ps1
```

Also run repository-specific tests in the instructed isolated environment.

Validation must establish:

- every node has Description at position 1, mandatory inbound and outbound
  traversable platform summaries at positions 2 and 3, and at least one later
  node-specific Cypher investigation item;
- both relationship-summary queries cover every direct traversable extension
  edge in their direction, with empty inventories proven by fragment metadata;
- investigation titles are concise semantic labels rather than questions;
- every verified dynamic query is anchored to the exact selected node label,
  binds and returns a path, uses known relationship kinds, puts operations on
  separate lines, and ends with `LIMIT 500`;
- each node fragment's `query_panels` metadata exactly matches its sections,
  query relationship kinds, purpose, and repository evidence;
- relationship panels map every source H2 section to exactly one accordion in
  source order, contain General first, retain deeper subsections within their
  parent, and contain no `related_entities`;
- panel fields, Markdown, JSON, schema consistency, and repository tests pass.

The validator requires dynamic links for every node summary and investigation.
Also prove hydrated content has no literal template delimiters or
`template_error`, decode generated links, and execute representative queries.
Without runtime evidence, do not claim dynamic-link validation or substitute
fenced queries.

