Skip to content

The built-in Kinds — a commented catalog

Kinds — identity & composition explains the mechanics of a Kind; this page is the commented catalog of the composition-plane Kinds that ship with the SDK beyond the core prompt family, grouped by what they are for. Two–four honest sentences each: what it is, its role, when you would reach for it. Field-by-field schemas live in the generated Kinds reference, which cannot drift from the source.

The core prompt-composition family — Genome, Agent, Skill, Soul, AgentDefinition, Guardrail, KindDefinition and friends — is covered in Kinds and the first-Kind tutorial. The record-plane SDLC family (Story, Feature, Issue, …) is covered in Your git log is your SDLC. What follows is everything else.

Composition mechanics

Hook

A Hook (helix-hook) is a declarative lifecycle interceptor: it attaches to a kernel hook point such as pre_build_prompt and runs an action — inject_fields merges YAML key-value pairs into the prompt context, log emits a structured message, script executes inline code. Hooks are stored as hooks/<name>/HOOK.md bundles and auto-register when ManifestInstance.apply_hooks() is called. Use one when behavior around prompt building must change without a deploy — injecting a feature flag or contextual field into every prompt is the canonical case.

Background automation

Automation

An Automation (dna-automation) declares background work as data: on says when it fires and runner says what runs. One doc, zero deploy — adding, retargeting or pausing an automation is a YAML edit, not a code change. The Kind is a direct port of the internal SDK's unification of three structurally identical trigger Kinds (async-tool job / event hook / cron schedule) into one schema discriminated by on.type:

  • cron — a 5-field cron expression (0 10 * * 1,3,5). The write path parses it with a zero-dependency validator (numbers, *, ranges, lists, steps; no JAN/MON name aliases), so 61 * * * * is vetoed at write time, not discovered at 3 a.m.
  • hook — a kernel lifecycle hook name (post_save, post_build_prompt, …). The name must belong to the kernel's typed vocabulary (KNOWN_HOOK_NAMES): a misspelled hook would be declared, listed and silently never fire, so an unknown name is a veto, not a warning.
  • tool — an async dispatch tool the host exposes to the model (tool_name + a declared input_schema + primary_input), for "fire-and-forget from a conversation" work like deep research.

Validation happens at the write, not at scan: the write guard runs the Kind's schema (per-trigger required fields, runner enum) and the semantic checks above before anything persists, so a broken Automation is vetoed while the author is still present. One authoring note for hand-edited YAML: prefer quoting the trigger key ('on':) — YAML 1.1 parsers such as PyYAML read a bare on as a boolean. The Python write path heals the boolean-key form before validating, and docs emitted by the SDK are always quoted, so the round-trip is safe either way.

The runner is a reference to a real Kind — an Agent (kind: agent) or a Tool (kind: tool) by name — plus the shared directive surface: agent_directive (the dispatch instruction, with {arg} placeholders), input (structured context), result_kind/result_spec_template (deterministic persistence of the output), running_message/done_message (user-facing copy) and a safety block (debounce, cooldown, rate cap, fan-out cap, idempotency key) that the host enforces as loop protection. Automation is an inheritable _lib default: declare the fleet once in the library scope, let every scope inherit it, and let a tenant override one doc in its overlay.

Contrast with Hook: a Hook is an in-process interceptor the SDK itself runs around prompt building; an Automation is out-of-process work — a report at 03:00, reindexing after a save — that only a host runtime can execute.

The execution extension point

Deliberately, execution does not ship in the SDK — there is no scheduler, bus or worker in a notation library. The contract is split the same way as the CLI's post-transition hooks (dna_cli.sdlc_cmd.register_post_transition_hook, where the CLI declares the hook point and the host registers the executor): the SDK declares, validates and lists; the host reads and runs. The read side is the query helpers automations_for(instance, trigger_type) and trigger_key(doc) (automationsFor / triggerKey in TypeScript), built on the blessed instance query surface. A minimal cron runner is ~20 lines:

# host_runner.py — a minimal cron executor over declared Automations
import time

from dna.kernel import Kernel
from dna.extensions.automation import automations_for, trigger_key

mi = Kernel.quick("my-scope")

while True:
    for doc in automations_for(mi, "cron"):  # enabled-only by default
        if cron_matches_now(trigger_key(doc)):  # your cron matcher
            runner = doc.spec["runner"]
            run_agent(                           # your agent runtime
                name=runner["ref"],
                directive=doc.spec.get("agent_directive", ""),
                inputs=doc.spec.get("input", {}),
            )
    time.sleep(60)

A hook-triggered executor is the same pattern on the kernel's own event channel: for each doc from automations_for(mi, "hook"), subscribe kernel.hooks.on(trigger_key(doc), ...) and dispatch the runner from the listener. Whatever the trigger, honor spec.safety before firing — the doc declares the loop protection, the host enforces it.

Collaboration

Comment

A Comment (collab-comment) is a remark, status change or assignment attached to any other document via target_ref (Kind:name). It is how discussion and history become data: the SDLC timelines, review notes on an eval finding, or an agent narrating its work all land as Comment documents. Reach for it whenever "who said what about this doc, when" needs to be queryable rather than buried in chat.

Canvas

A Canvas (helix-canvas) is a shared whiteboard between a voice/chat agent and the user, backed by a serialized tldraw snapshot in spec. The user draws; the agent reads the shapes as JSON (or vision-interprets free strokes) and writes back through discrete shape tools. It exists as a Kind — rather than ephemeral UI state — so boards are persisted, searchable and embeddable like any other document. It is a product-facing Kind: useful when you build an assistant UI on DNA, irrelevant for headless setups.

Safety & governance

SafetyPolicy

A SafetyPolicy (helix-safety-policy) declares runtime enforcement rules for agent input and/or output: PII, content safety, topic restriction, prompt injection, banned words, custom regex. Tier 1 (regex — CPF/CNPJ/email/phone/credit card plus injection heuristics) is built in; ML and LLM-judge tiers are opt-in extras. The action decides what happens on a hit: mask redacts inline, block rejects the message, log passes through with violation metadata. This is the Kind to write when compliance asks "prove nothing personal reaches the model".

Recognizer

A Recognizer (presidio-recognizer) is a Presidio ad-hoc PII recognizer as data: an entity type (say BR_CPF), regex patterns with scores, deny lists and context words. SafetyPolicy documents reference Recognizers via dep_filters, and the runtime exports them to the Presidio engine. Write one when the built-in entities miss a domain-specific identifier — an internal employee ID format, a country-specific document number.

EvidencePolicy

An EvidencePolicy (evidence-policy) controls which event types are automatically captured as immutable Evidence documents — the content-level audit trail. It declares the event list to watch, whether auto-capture is on, and the retention period. Use it to tune the audit surface per scope: capture everything in a regulated project, only writes elsewhere.

UserRoleAssignment

A UserRoleAssignment (audit-userroleassignment) maps a user identity to a role list within a tenant — the document name is the user id. It backs role-gated endpoints in a hosting platform's admin surface and is the persistent mirror of IdP group membership. You only touch it when running DNA multi-user behind auth; single-user local setups never see one.

MCPFederation

An MCPFederation (federation-mcp) declares an external MCP server whose tools agents may consume: transport (stdio command or streamable HTTP URL), an allowed_tools bound, and an enabled: false kill switch. An Agent lists the doc's name in spec.mcp_servers and the runtime loads the remote tools as first-class agent tools — zero code, zero deploy. Secrets never live in the doc: the auth block carries env-var names, read at connect time.

Model registry

ModelProfile

A ModelProfile (modelreg-model-profile) records one LLM model's hard limits and capabilities — instruction_token_cap, context_window, tools_cap, max_output_tokens, modalities, cost — as first-class data instead of implicit knowledge scattered through code. Profiles are GLOBAL and live in the _lib scope (model-profiles/<model_id>.yaml); resolve one with kernel.model_profile(id_or_alias) (modelProfile in TypeScript), which matches model_id first and the aliases list second, regardless of the caller's scope.

The registry exists for one contract: never hardcode token caps. The kernel's write path enforces it — when an Agent that declares a model (or a voice_persona) is written, the prompt-budget guard estimates the instruction's token count and compares it against the profile's instruction_token_cap. A strict model — a voice persona write, or any profile with realtime: true — over the cap vetoes the write with a didactic error; a chat model over the cap writes but warns loud; an Agent with no declared model, or a model with no profile, passes untouched (enforcement is opt-in: writing a profile with a cap arms the guard). The estimate is a deliberate over-count (chars ÷ 3.5), so the guard never under-blocks; DNA_PROMPT_BUDGET_ENFORCE=0 is the ops kill-switch that downgrades the veto to a warning. This ports a lesson paid for in a real outage: a 17,269-token voice persona silently exceeded a realtime model's 16,384-token session-instructions cap because the cap lived in nobody's code.

# _lib/model-profiles/gpt-realtime-2.yaml
apiVersion: github.com/ruinosus/dna/modelreg/v1
kind: ModelProfile
metadata:
  name: gpt-realtime-2
spec:
  model_id: gpt-realtime-2
  provider: openai
  realtime: true            # strict: over-cap Agent writes are vetoed
  context_window: 32768
  instruction_token_cap: 16384
  modalities: [text, audio]
  aliases: [gpt-realtime-2-2026-05-07]

Preferences & personalization

Setting

A Setting (helix-setting) is a reusable configuration snippet — env vars plus nested config plus setup prose for one domain ("configure Vertex AI", "corporate proxy"). Selected Settings compose into a coding agent's settings.json or the runtime env. Atomic and idempotent by design, so a "complete workstation setup" is just a scope of docs.

Theme

A Theme (helix-theme) declares a UI color palette — primary/accent/success in light and dark HSL — plus optional typography and radius overrides, applied as CSS variables at runtime with no rebuild. Because it is a document, a tenant ships its brand by publishing themes/brand.yaml in its overlay. Only meaningful when a web UI sits on top of DNA.

UserProfile

A UserProfile (helix-user-profile) holds per-user personalization data — display name, language, communication style, opt-in personal context — that an agent may inject into its prompt. It is consent-gated: without consent.profile_used_in_prompts: true (or without a doc at all) the agent treats the user as anonymous, and each user can read/write only their own profile. Use it when an agent should remember who it is talking to across sessions.

Testkit

TestGuide

A TestGuide (testkit-test-guide) is a declarative test script: an ordered list of steps (action → expected, optionally where in the product) that verifies one or more work items via verifies refs. It turns the test roteiro that used to live in chat into a versioned, schema-validated, re-runnable document. Write one per feature you expect a human (or agent) to smoke again later.

TestRun

A TestRun (testkit-test-run) records one execution of a TestGuide: outcome (pass/fail/partial/blocked), who ran it, per-step results and evidence. A passing run whose verifies points at a work item drives that item's verify phase in the derived journey — it is the proof, where the guide is the promise.

Evaluation

Four Kinds make evaluation authoring data — ported from the internal SDK's eval extension minus its runtime (the upstream runner was a Temporal worker driving live agents through LLM judges; none of that belongs in a notation library). What ships instead is a local, synchronous, offline runner whose default target is the kernel itself: composing a prompt is a deterministic function of the declared documents, so "does my agent compose the prompt I expect?" is a real evaluation of declarative config — no LLM required. The evaluating agents guide walks the full workflow, including how a host registers an LLM target (EvalTargetPort — the same declare-here/execute-in-the-host split as Automation runners).

EvalCase

An EvalCase (eval-eval-case) is one scenario: a target (what produces the text under test — default {type: prompt, agent: X}, the composed system prompt) and a list of deterministic checks (contains, not_contains, regex, not_regex, equals, min_length, max_length) that ALL must pass. Upstream fields that presuppose a live agent loop (trajectory matching, HITL policies, judge engines) deliberately did not travel.

EvalSuite

An EvalSuite (eval-eval-suite) groups cases and configures the run: the cases list (empty = every EvalCase in the scope), a default target the cases inherit, and stop_on_fail. Execute it with dna eval run <suite> — offline, in seconds, in CI.

EvalRun

An EvalRun (eval-eval-run) is the persisted ledger of one execution: counts, timestamps, the resolved target and per-case results with the outcome of every declared check. dna eval run --save writes it; being a document, runs are queryable, diffable and versioned like everything else.

EvalBaseline

An EvalBaseline (eval-eval-baseline) pins one EvalRun as the "known good" reference for a suite (dna eval pin <run>). Future runs compared against it (dna eval run <suite> --baseline <name>) report regressions, improvements and unchanged cases — and exit non-zero only on a regression, so a pre-existing failure doesn't re-fail your CI.

Domain content

Doc

A Doc (dna-doc) is one page of in-product documentation: a markdown body plus sidebar metadata (icon, order, locale, Diátaxis kind_of, free-form category), authored as a docs/<name>/DOC.md bundle and read back by dna docs list/show — so a DNA-based product serves its own help pages straight from the kernel. It is a record-plane Kind shipped as a pure descriptor (content as data, no port class), ported from the internal SDK's doc extension minus its product-specific help-center machinery (live data/diagram placeholders, landing-page curation, asset aggregation).

Lesson

A Lesson (lesson-lesson) is a short, structured educational activity an agent can run with a pre-reader child — subject, target concepts, spoken prompts — born in an AAC (augmentative and alternative communication) product built on DNA. It is deliberately data, not code, so caregivers and therapists curate content in a UI without code review. It doubles as the reference example of a narrow domain Kind carried by an extension: your equivalent might be Recipe or Workout.


Run dna kind list for the live registry in your install, and dna kind describe <Kind> for the exact schema the write boundary enforces — the CLI tour shows both in action.