create-evlog-enricher

v2026.09.24

Create a new built-in evlog enricher to add derived context to wide events. Use when adding a new enricher (e.g., for deployment metadata, tenant context, feature flags, etc.) to the evlog package. Covers source code, tests, and all documentation.

GitHub
Install command
npx skhub add evloghq/create-evlog-enricher
Markdown
SKILL.md

Create evlog Enricher

Add a new built-in enricher to evlog. Every enricher is built on the public toolkit primitive defineEnricher from evlog/toolkit, so a community enricher has the same shape as a built-in one.

PR Title

feat(core): add the {name} enricher

Enrichers live in the core package surface (evlog/enrichers), so use the core scope unless a dedicated scope exists.

Touchpoints Checklist

#FileAction
1packages/evlog/src/enrichers/index.tsAdd enricher source (one defineEnricher call)
2Same file: createDefaultEnrichers()Decide whether the enricher belongs in the default composition (see below)
3packages/evlog/test/toolkit/enrichers.test.tsAdd tests (one describe block per enricher)
4apps/docs/content/5.use-cases/5.enrichers.mdAdd a section for the enricher + update the import list and, if applicable, the "All built-in enrichers" default composition text
5skills/review-logging-patterns/SKILL.mdAdd the enricher to the Built-in: line in the Enrichers section
6packages/evlog/README.mdAdd the enricher to the Built-in Enrichers section (root README.md is a symlink to it)
7.changeset/{name}-enricher.mdCreate changeset (minor)

Important: Do NOT consider the task complete until all 7 touchpoints have been addressed.

Should it join createDefaultEnrichers()?

createDefaultEnrichers() composes user agent, geo, request size, and trace context via composeEnrichers (from ../shared/compose). Add the new enricher to the composition only if it is universally applicable and reads nothing but the request (headers/env). Anything requiring service-specific setup or extra cost stays opt-in. Changing the default composition is a behavior change for every existing createDefaultEnrichers() user: call it out explicitly in the changeset.

Naming Conventions

PlaceholderExample (UserAgent)Usage
{name}userAgentcamelCase for event field key
{Name}UserAgentPascalCase in function/interface names
{DISPLAY}User AgentHuman-readable display name

Step 1: Enricher Source: built on defineEnricher

Add the enricher to packages/evlog/src/enrichers/index.ts. Read references/enricher-template.md for the full annotated template.

The contract is defineEnricher<T>({ name, field, compute }, options?). You only ship one piece of logic:

  • compute(ctx): return the computed value (typed as T) or undefined to skip.

defineEnricher handles the rest:

  • merging via mergeEventField (respecting options.overwrite, default false)
  • error isolation (throws are caught and logged, never propagated)
  • skipping when compute returns undefined

Key rules:

  • Use the toolkit helpers: getHeader() for case-insensitive header lookup, normalizeNumber() for numeric strings. Both from ../shared/headers (re-exported by evlog/toolkit).
  • Single event field: each enricher writes one top-level field on ctx.event. If the enricher must additionally pin top-level fields (like createTraceContextEnricher does for event.traceId / event.spanId), wrap the defineEnricher result in a closure, see that enricher for the pattern.
  • Factory pattern: create{Name}Enricher(options: EnricherOptions = {}) returns the result of defineEnricher(...), directly in the normal case, or through the thin closure wrapper when the enricher also pins top-level fields (see the single-event-field rule above).
  • No side effects: never throw, never log; rely on defineEnricher's built-in error handling if something goes wrong.
  • Export the Info type: {Name}Info describing the field shape, exported alongside the factory.

Step 2: Tests

Add tests to packages/evlog/test/toolkit/enrichers.test.ts, following the existing structure (one describe block per enricher) and packages/evlog/test/README.md conventions.

Required test categories:

  1. Sets the field from its source: verify the enricher populates the event field correctly, reading whatever it actually reads (ctx.request, ctx.response, process.env, ctx.event, or headers)
  2. Skips when source data missing: verify no field is set when the required input is absent
  3. Preserves existing data: verify overwrite: false (default) doesn't replace user-provided fields
  4. Overwrites when requested: verify overwrite: true replaces existing fields
  5. Handles edge cases: empty strings and malformed values, plus case-insensitive lookup for a header-based enricher
  6. Default composition: if the enricher joined createDefaultEnrichers(), extend that composition's tests

Step 3: Update the Enrichers Docs Page

Edit apps/docs/content/5.use-cases/5.enrichers.md:

  1. Add the enricher to the import list at the top
  2. Add a ## {DISPLAY} section following the structure of the existing ones:
## {DISPLAY}

[One-sentence description of what the enricher does.]

**Sets:** `event.{name}`

\`\`\`typescript
const enrich = create{Name}Enricher()
\`\`\`

**Output shape:**

\`\`\`typescript
interface {Name}Info {
  // fields
}
\`\`\`

**Example output:**

\`\`\`json
{
  "{name}": {
    // example values
  }
}
\`\`\`
  1. If the enricher joined the default composition, update the "All built-in enrichers" section text listing what createDefaultEnrichers() composes.

Custom-enricher authoring docs live separately at apps/docs/content/6.extend/5.custom-enrichers.md, with no change needed there unless the toolkit contract itself changed.

Step 4: Update the Public Skill

In skills/review-logging-patterns/SKILL.md (published on evlog.dev), find the Enrichers section and add the new enricher to the Built-in: line.

Step 5: Update README

Add the enricher to the Built-in Enrichers section in packages/evlog/README.md (the root README.md is a symlink to it).

Step 6: Changeset

Create .changeset/{name}-enricher.md with a minor bump describing what the enricher sets and when to use it. Mention explicitly if the default composition changed.

Verification

cd packages/evlog
pnpm run lint
pnpm run typecheck
pnpm run test
pnpm run build
Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

MIT

Source path

.agents/skills/create-enricher

Default branch

main

Latest commit

e073860

Tree SHA

5a31685