From honeydew-ai
Use after creating or modifying ANY Honeydew object (metric, attribute, entity, domain). Provides type-specific validation logic to ensure objects work correctly and return sensible results.
npx claudepluginhub honeydew-ai/honeydew-ai-coding-agents-plugins --plugin honeydew-aiThis skill uses the workspace's default tool permissions.
**This skill is MANDATORY after creating or modifying any Honeydew object.**
Guides you step-by-step through defining a business metric (aggregation) on a Honeydew entity. Covers SQL expression building and pushes to Honeydew via the MCP tools.
Manages DataHub data quality: create or run assertions, check outcomes, raise or resolve incidents, create notification subscriptions, diagnose health across assets.
Browses, searches, and displays metric definitions including formulas, source tables, dimensions, guardrails, and validations from active dataset's metric dictionary via /metrics commands.
Share bugs, ideas, or general feedback.
This skill is MANDATORY after creating or modifying any Honeydew object.
Validation ensures:
Step 1: Execute the metric
Call get_data_from_fields with:
metrics: ["<entity>.<metric_name>"]If the tool call fails (API error, permission denied, timeout), report the error to the user before proceeding. Do not confuse a tool error with suspicious data.
Step 2: Sanity checks
| Check | What to Look For | Action if Failed |
|---|---|---|
| Returns data | Not NULL, not empty | Check SQL syntax, entity references |
| Magnitude | Reasonable for business context | Verify calculation logic |
| Sign | Positive for revenue/counts (usually) | Check for inverted logic |
| Related metrics | Parts sum to whole | Query related metrics together and verify consistency |
| Ratios | Between 0-100% (usually) | Check numerator and denominator metrics independently |
Step 3: Cross-validation
If the new metric is a filtered subset of an existing metric, or a ratio of existing metrics, query them together to verify consistency:
Call get_data_from_fields with both metrics:
metrics: ["<entity>.<filtered_metric>", "<entity>.<total_metric>"]Alert user if:
Step 1: Execute the attribute
If the attribute references a related entity (multi-entity attribute), first verify the relation exists using get_entity on the source entity.
If the relation is missing, report that before attempting to query the attribute.
Sample rows — call get_data_from_fields with:
attributes: ["<entity>.<attribute_name>"]For boolean attributes, check distribution — call get_data_from_fields with:
attributes: ["<entity>.<boolean_attribute>"]metrics: ["<entity>.count"]Step 2: Sanity checks by attribute type
| Attribute Type | Valid Range | Red Flags |
|---|---|---|
| Age/Duration | 0 to reasonable max | Negative values, >150 years |
| Boolean | TRUE/FALSE mix | All TRUE or all FALSE |
| Percentage | 0-100 (usually) | Negative, >100 (unless growth rate) |
| Date | Past to near future | Year 1900, year 2099, all NULLs |
| Category/Bucket | Expected labels | 95%+ in "Unknown" or NULL |
| Rank | Starts at 1, consecutive | Starts at 0, gaps, all same value |
| Running total | Monotonically increasing | Decreases, resets unexpectedly |
| Any type | Mix of values | >50% NULLs warrants investigation |
Alert user if:
Step 1: Verify entity was created
Use list_entities and filter results for the new entity name.
Step 2: Verify data flows
Call get_data_from_fields with:
metrics: ["<entity>.count"]Also call with a list of attributes to verify they are accessible:
attributes: ["<entity>.<attribute1>", "<entity>.<attribute2>", "<entity>.<attribute3>"]Step 3: Sanity checks
| Check | What to Look For | Action if Failed |
|---|---|---|
| Entity exists | Shows in list_entities results | Check create_entity call |
| Has rows | Count > 0 | Verify source table path |
| Key is unique | Count = count distinct of key | Fix key or add composite key |
| Attributes accessible | Can query attributes | Check dataset definition |
Alert user if:
Relations are not standalone objects — they are defined within an entity's YAML. Validate them as part of the entity that contains them.
Step 1: Verify relation exists
Use get_entity on the source entity and check its relations list for the new relation.
Step 2: Test the join works
Call get_data_from_fields with a cross-entity query:
attributes: ["<target_entity>.<attribute>"]metrics: ["<source_entity>.<metric>"]Step 3: Sanity checks
| Check | What to Look For | Action if Failed |
|---|---|---|
| Relation exists | Shows in get_entity results | Check update_object call |
| Join works | Cross-entity query succeeds | Verify join keys match |
| No fan-out | Counts don't explode | Check cardinality (many-to-one vs many-to-many) |
| NULLs reasonable | Some NULLs OK for left join | Too many NULLs = bad join key |
Alert user if:
Step 1: Verify domain exists
Use search_model (with search_mode: EXACT) to find the new domain by name.
Step 2: Test with a scoped query
Call get_data_from_fields with the domain parameter to verify entities are accessible and filters apply:
metrics: ["<entity>.count"]domain: "<domain_name>"Step 3: Verify filters apply
If the domain has semantic or source filters, compare results with and without the domain to confirm filters reduce the data as expected:
Step 4: Sanity checks
| Check | What to Look For | Action if Failed |
|---|---|---|
| Domain exists | Found via search_model | Check create_object call and YAML syntax |
| Entities accessible | Scoped query returns data | Verify entity names match existing entities |
| Filters apply | Scoped count <= unscoped count | Check filter SQL and entity.field references |
| Field selectors work | Excluded fields not returned in query | Verify selector patterns and order |
| No errors | Query executes without compilation errors | Check filter SQL syntax, fully qualified refs |
Alert user if:
When modifying an existing object, compare before and after:
revenue changed from $1,234,567 to $1,198,432 after applying the discount logic."This confirms the change had the intended effect and helps catch unintended regressions.
If a tool call fails, distinguish between:
| Situation | Meaning | Action |
|---|---|---|
| Tool returns an error | API error, permission denied, timeout, invalid YAML | Report the error message to the user. Do not treat as a validation failure — the object may not have been created. |
| Tool returns empty/NULL data | Object was created but returns no results | Proceed with sanity checks — likely a data or SQL issue. |
| Tool returns unexpected values | Object works but results look wrong | Report findings and ask user before attempting a fix. |
When results seem wrong, report to the user with:
Do not silently fix issues — always surface findings and ask before making changes.
| Object | Execute With | Key Checks |
|---|---|---|
| Metric | get_data_from_fields with metrics list | Value, magnitude, sign, consistency |
| Attribute | get_data_from_fields with attributes list | Range, distribution, NULLs |
| Entity | list_entities + get_data_from_fields | Exists, has rows, key unique |
| Relation | get_entity + cross-entity field query | Exists, joins work, no fan-out (validated as part of entity) |
| Domain | search_model + get_data_from_fields with domain | Exists, filters apply, fields scoped |