Doctrine artifact kinds
Doctrine is the layered set of governed content that shapes how missions and agents behave in a Spec Kitty project — the rules directives enforce, the techniques tactics teach, the personas agent profiles define, and so on. Everything in doctrine is one of a fixed set of kinds. This page explains what each kind is for, with a real example drawn from this repository's own built-in doctrine.
Single source of truth
The kind list on this page is not invented for the docs — it is read directly from
src/charter/activation/kind_vocabulary.py
and src/charter/offering/artifact_kinds.py,
and cross-checked against the running CLI. You can reproduce the same list yourself:
# Passing an invalid kind makes the CLI print the full valid list back at you
spec-kitty charter activate bogus-kind some-id
# Error: Unknown kind 'bogus-kind'. Valid kinds: agent-profile, directive,
# glossary-pack, mission-step-contract, mission-type, paradigm, procedure,
# skill, styleguide, tactic, toolguide.
Strip mission-type from that list (it is a mission concept, not a doctrine artifact kind —
see the mission system) and you have the ten charter-activatable
doctrine artifact kinds: directive, tactic, styleguide, toolguide, paradigm, procedure,
agent_profile, mission_step_contract, glossary_pack, skill. Those ten are the activation vocabulary;
they are part of a larger thirteen-member ArtifactKind enum — the remaining three
(template, asset, anti_pattern) are real kinds handled specially, not separately activated
(see the note below and the schema overview). All thirteen are documented on
this page.
Schema at a glance
The ArtifactKind vocabulary below is generated from the frozen enum
(src/charter/offering/artifact_kinds.py) via list(ArtifactKind) and kept honest by the drift guard
(tests/docs/diagram_drift/, FR-004) — the thirteen members are introspected, never hand-typed, so
this list cannot silently fall out of step with the code (as the stale "eight" prose once did).
Most kinds are a thin marker with a small governed body; the richest schema is the agent
profile, so it earns a full diagram. AgentProfileSchema is a Pydantic model with kebab-case
aliases (the guard normalizes each field via FieldInfo.alias or name) and a genuinely nested
value object, AgentSpecialization — the diagram expands that sub-map so the guard exercises its
transitive-recursion path on real, shipped content.
The three unexpanded nested value objects (collaboration,
specialization-context, self-review-protocol) are shown as typed references rather than inlined —
a deliberate diagram-author choice, like drawing a foreign key instead of copying the whole table.
Reserved language tokens in applies_to_languages. The applies_to_languages field scopes an
artifact to project languages. Three tokens are reserved and never name a real language:
anyandallare rejected when you author an artifact (spec-kitty charter validate). If one reaches runtime anyway, the artifact is treated as unscoped and loads for every project.unknownis rejected at authoring time as well. At runtime it is ignored on both sides of the match, so an artifact scoped only tounknownnever loads. Spec Kitty itself writesunknowninto a project's active languages when the project declares a language that no installed doctrine recognises (see the catalog-languages ADR).
A note on
template,asset, andanti_pattern(the three non-activatable kinds). If you readsrc/charter/offering/artifact_kinds.pydirectly, you will see three members of theArtifactKindenum beyond the ten activatable kinds:template,asset, andanti_pattern— the exact set in_NON_AUGMENTATION_ELIGIBLE_KINDS. All three are real and handled by the doctrine system — but none is one of the ten activatable kinds above, and the CLI error message above is the proof:templateandassetdo not appear in the "Valid kinds" list because they are explicitly excluded fromCHARTER_KIND_TOKENS(the setcharter activate/deactivate/list/context --includeoperate over).templateis mission-scoped (it ships as part of a mission type's own template set, not as a standalone artifact you activate —spec-kitty charter list --allreports it as "mission-scoped — not separately activated").assetis a loose-contract kind (a sidecar*.asset.yamlmanifest describing a blob — an image, font, template fixture, or a shipped script — that is resolved to a path, never parsed or schema-validated). It ships one built-in artifact today:common-docs-structural-lint, the structural docs lint (packs/built-in/assets/docs_structural_lint.py, declared bydocs_structural_lint.py.asset.yaml). Resolve it — from any installation, no charter step required — withspec-kitty doctrine asset path common-docs-structural-lint(or list every resolvable asset and its source tier withspec-kitty doctrine asset list). Both are worth knowing exist; neither is part of the ten-kind activation vocabulary this page and its companion how-to cover — see The asset kind below for how to author and resolve one, and Delivery verdicts: which kinds reach a mission for why the shipped asset arrives without being activated.anti_patternis the third: it is a DRG node kind (NodeKind.ANTI_PATTERN) with no backing artifact schema — a marker node thatrejectsedges point at — documented under Anti-pattern below. Audit note:templatewas reviewed for a dedicated schema diagram and consciously left as this note — it is mission-scoped file selection, not a standalone authored schema, so it carries no@startyamlmodel diagram (its shape is "a file in a mission type's template set").
The asset kind
The ten activatable kinds are the activation vocabulary — you author one, charter activate it,
and it becomes eligible for injection into governed mission context. The asset kind sits outside
that vocabulary on purpose. An asset is not a rule, a technique, or a persona; it is a blob —
a file whose bytes are the payload (an image, a font, a template fixture, or a shipped script such
as a lint). Spec Kitty never parses or schema-validates the blob itself. Instead each blob is
described by a small YAML sidecar manifest placed alongside it, and it is the manifest — not
the blob — that carries the validated contract (id, mime, path, optional title).
Why a project would ship one. review-gates.md forbids
shipped doctrine from naming a repo-local script or CI path a consumer does not have. The
canonical way to hand executable logic (or any blob) to a downstream repo is precisely the asset
kind: the blob travels inside the pack under its assets/ tree, and downstream code resolves it
by identifier through spec-kitty doctrine asset path <id> rather than reaching for a path that
only exists in our source tree. The one built-in asset, common-docs-structural-lint, is exactly
this pattern — a lint script shipped as an asset instead of as a scripts/… reference.
To author and resolve an asset end to end, follow the asset section of Create a doctrine artifact.
Delivery verdicts: which kinds reach a mission
"Activatable" and "delivered" are two different questions. A kind is delivered when its
resolved artifacts reach the rendered doctrine bundle a mission action consumes. The delivery rail
records a verdict for every NodeKind in one total table (_ACTION_BUNDLE_DELIVERY_BY_KIND in
src/charter/activation/context.py),
with two columns — the bundle slot the kind feeds, and the gate that filters it. The gate is a
total function over kinds, so there are three categories, not two:
| Category | Kinds | Gate | What reaches the mission |
|---|---|---|---|
| Delivered, activation-gated | directive, tactic, styleguide, toolguide, procedure | ACTIVATED |
activated(kind) ∩ reachable — only the ones you activated and the DRG reaches |
| Delivered, not activation-gated | asset | ALL |
reachable alone — every asset a reachable source pulls in, no activation list consulted |
| Not bundle-delivered (stated reason) | paradigm, agent_profile, mission_step_contract, glossary_pack, anti_pattern, template, skill | — | excluded, each with a recorded reason (e.g. template is mission-scoped file selection; agent_profile ships through the profile channel) |
Assets are the third category — delivered but not activation-gated. This matters because an
asset has no activated_assets list to appear on: activated(asset) is empty by construction, so
gating an asset on activated ∩ reachable would ship "no assets, ever" and quietly pass. Instead
the gate for assets is ALL, meaning delivery is reachable alone — an asset arrives when a
reachable artifact points at it through a requires/suggests edge. That is how the shipped
common-docs-structural-lint reaches a mission without anyone activating it. (template shares
the ALL gate but has no bundle slot — its selection is mission-scoped file resolution, a stated
exclusion rather than asset's untreated twin.)
The doctrine artifact kinds
Directive
Purpose. A constraint-oriented governance rule that applies across flows or phases. Directives encode required or advisory expectations and can reference lower-level tactics for execution. Directives are the "must/should" layer of doctrine — the rule, not the recipe for following it.
Location. packs/built-in/directives/*.directive.yaml (project overlay:
.kittify/doctrine/directive/).
Example. DIRECTIVE_001 — "Architectural Integrity Standard"
(packs/built-in/directives/001-architectural-integrity-standard.directive.yaml).
Its intent requires that "system designs must maintain clear separation of concerns and
well-defined component boundaries," and its procedures/integrity_rules/validation_criteria
fields spell out how a reviewer checks compliance — without prescribing exactly how to
decompose any given system (that's a tactic's job).
Tactic
Purpose. A reusable behavioral execution pattern that defines how work is performed. Tactics are operational and agent-consumable, and can be selected by directives and mission context. Where a directive says "you must," a tactic says "here is how, step by step."
Location. packs/built-in/tactics/**/*.tactic.yaml (project overlay:
.kittify/doctrine/tactic/).
Example. problem-decomposition
(packs/built-in/tactics/architecture/problem-decomposition.tactic.yaml). Its steps
walk an agent through stating a problem in one sentence, enumerating contributing factors,
clustering them into independent sub-problems, and validating completeness — a concrete,
followable procedure for a specific recurring situation (breaking down an ambiguous problem
before committing to a solution).
Styleguide
Purpose. A doctrine artifact defining cross-cutting quality and consistency conventions (for example coding, documentation, or testing style) that apply across missions and templates. Styleguides are about how things should look and read, not about a specific procedure.
Location. packs/built-in/styleguides/*.styleguide.yaml (project overlay:
.kittify/doctrine/styleguide/).
Example. plain-language
(packs/built-in/styleguides/plain-language.styleguide.yaml). Its principles govern
this very kind of page: write for the named audience, prefer the short common word, one idea per
sentence, active voice, define a term once and reuse it, show rather than only tell. This page
was written under that styleguide.
Toolguide
Purpose. A doctrine artifact defining tool-specific operational guidance, syntax, and constraints (for example a particular diagramming tool's conventions) used by agents and contributors during execution. Toolguides are scoped to one external tool, not to a general technique.
Location. packs/built-in/toolguides/*.toolguide.yaml, each pointing at a
companion guide_path (project overlay: .kittify/doctrine/toolguides/).
Example. mermaid-diagramming
(packs/built-in/toolguides/mermaid-diagramming.toolguide.yaml), which points at
MERMAID_DIAGRAMMING.md for syntax patterns, theming, and rendering conventions when a mission
needs a diagram-as-code artifact.
Paradigm
Purpose. A worldview-level framing for how work is approached in a domain. Paradigms influence the selection and interpretation of directives and tactics but are not executable step recipes themselves — they are the lens, not the checklist.
Location. packs/built-in/paradigms/*.paradigm.yaml (project overlay:
.kittify/doctrine/paradigms/).
Example. domain-driven-design
(packs/built-in/paradigms/domain-driven-design.paradigm.yaml). Its summary frames
software design around a deep model of the business domain (Bounded Contexts, Ubiquitous
Language, Aggregates); its directive_refs link it to DIRECTIVE_001, DIRECTIVE_031, and
DIRECTIVE_032, and it authors rejects DRG edges naming the anti-patterns it warns against
(for example the anemic-domain-model anti-pattern node) so the consistency-check and rendered
agent context can surface "avoid this" targets. (This replaces the retired opposed_by field —
see ADR 2026-07-21-1.)
Procedure
Purpose. A reusable doctrine subworkflow that a step contract may delegate to for part of a mission action. Procedures are structured, stateful playbooks with defined entry/exit conditions — unlike tactics (small composable techniques), procedures orchestrate multi-step flows that can be paused, resumed, and validated. They are not tracked missions and not runtime sessions.
Location. packs/built-in/procedures/*.procedure.yaml (project overlay:
.kittify/doctrine/procedure/).
Example. adversarial-squad-deployment
(packs/built-in/procedures/adversarial-squad-deployment.procedure.yaml). Its
entry_condition is "a work product has reached a review point-cut... and an independent
multi-lens assessment would reduce the risk of a costly miss"; its steps cover choosing the
point-cut, selecting complementary profiles, running the delegates in parallel, and
synthesizing a verdict — a bounded, resumable workflow, not a single technique.
Agent Profile
Purpose. A structured logical collaborator identity and behavior guidance, identified by a stable profile ID, that governs assignment, handoff, role-scoped behavior, and tool-native custom-agent/subagent projection. An agent profile is who is doing the work and how they are allowed to operate — roles, capabilities, directive references, and collaboration rules — not a technique or a rule in isolation.
Location. packs/built-in/agent_profiles/*.agent.yaml (project overlay:
.kittify/doctrine/agent_profiles/; key field is profile-id, not id).
Example. doctrine-daphne
(packs/built-in/agent_profiles/doctrine-daphne.agent.yaml) — the profile this very page
was authored under. Its roles are curator and onboarding-guide; its capabilities include
artifact-kind-classification and pack-artifact-authoring; its directive-references name specific directives (003, 018,
032, 043, 044) so the agent has the right doctrine loaded before curating more of it.
Mission step contract
Purpose. A structured contract for one mission action, including step sequencing, guard evaluation, prompt binding, and delegation hooks. Mission step contracts are what turn a mission type's abstract action sequence (specify → plan → tasks → implement → review) into concrete, executable steps — each step can delegate to a directive, tactic, or procedure.
Location. packs/built-in/missions/built_in_step_contracts/*.step-contract.yaml
(project overlay: .kittify/doctrine/mission_step_contracts/).
Example. specify action, software-dev mission
(packs/built-in/missions/built_in_step_contracts/specify.step-contract.yaml). Its bootstrap
step loads charter context; capture_intent delegates to directives
010-specification-fidelity-requirement and 037-living-documentation-sync; map_examples
delegates to the example-mapping-workshop procedure; validate_requirements delegates to the
requirements-validation-workflow tactic. This is the contract that makes /spec-kitty.specify
pull in exactly that doctrine, in that order.
Glossary pack
Purpose. A bundled set of canonical terminology — term definitions, aliases, and the scopes
they apply in — activated as a unit so a mission speaks one precise vocabulary. Where a single
term lives on a glossary node and its applicability on a glossary_scope node in the DRG, a
glossary pack is the activatable artifact that packages a coherent group of them (a
member of the charter-activation vocabulary — it is charter-activatable via the glossary-pack
token, unlike template/asset/anti_pattern).
Location. packs/built-in/glossary_packs/*.glossary-pack.yaml (project overlay:
.kittify/doctrine/glossary_packs/). Activate it like any other kind: spec-kitty charter activate glossary-pack <id>.
Why it is a pack, not loose terms. Terminology drifts fastest when definitions are scattered; bundling the canonical terms for a domain into one activatable pack keeps a mission's language internally consistent and lets the glossary integrity pipeline check the group as a whole.
Skill
Purpose. A thin, parameterised entry point a team types into its AI tool (a "pack skill"),
shared through a pack instead of private per-user copies. A skill carries no substance of its own:
it requires the procedures and directives that do (DRG edges), and its rendered SKILL.md
fetches them at run time with spec-kitty charter context --include <urn>. Forms: prompt (a
body file) or wrapper (a thin shorthand over a spec-kitty.* command or spec-kitty argv).
Location. Org packs: <pack>/skills/*.skill.yaml (packs/internal never ships); project:
.kittify/doctrine/skills/. packs/built-in/skills/ is empty at present. Activate it with
spec-kitty charter activate skill <id>; when activated_skills is absent, only the org packs'
required_skills are in force (never every available skill). Activated skills are rendered as
<skill_namespace>-<id> into each configured tool's project skill root and owned by
.kittify/skills-manifest.json; spec-kitty doctor skills reports drift, staleness and orphaned
copies. Not bundle-delivered: a skill reaches the agent through its skill root, not the mission
context bundle. See ADR 2026-09-27-1.
Anti-pattern
Purpose. A named bad practice or smell that good doctrine should steer away from. Unlike the
ten activatable kinds, an anti-pattern is not an authored artifact schema you activate — it is
a DRG node kind (NodeKind.ANTI_PATTERN) with no backing model class: a marker node that
other artifacts point at with rejects edges (see Doctrine relationships).
A paradigm such as domain-driven-design, for example, authors rejects edges naming the
anemic-domain-model anti-pattern node.
Not to be confused with styleguides AntiPattern. The styleguide models define an inline
AntiPattern example type (src/charter/offering/styleguides/models.py) — a small structured example
embedded in a styleguide body. That is a different concept from the DRG anti_pattern kind: the
styleguide AntiPattern is a backed Pydantic example type inside another artifact; the DRG
anti_pattern is a bare node kind (a string, no class) that exists only as a graph target. The
drift guard binds each separately so the two are never conflated.
Where to go next
- To author and activate a new artifact of any of these kinds, follow Create a doctrine artifact.
- For how built-in, org, and project doctrine layers combine and override each other, see Understanding the Org Doctrine Layer.
- For the canonical glossary definitions these purpose statements are grounded in, see the doctrine context glossary and the Agent Profile / step contract entries.