Instance & ManifestInstance¶
Instance is the universal wrapper for every manifest instance —
doc.kind, doc.name, doc.spec, doc.metadata, doc.typed,
doc.origin. ManifestInstance is the blessed query surface: the one
documented read API (all, one, root, default_agent, find_agent,
build_prompt, resolve) that the guides and examples teach.
Instance¶
dna.kernel.instance.Instance ¶
Instance(
api_version: str,
kind: str,
name: str,
metadata: dict[str, Any] | None = None,
spec: dict[str, Any] | None = None,
raw: dict[str, Any] | None = None,
typed: Any | None = None,
origin: str = "local",
)
Bases: Generic[SpecT]
Universal wrapper. Works for parsed BaseKind AND raw dict.
doc.spec and doc.metadata always return SpecDict at runtime
— a dict subclass with attribute access. When typed via
Instance[MySpec], the type checker treats doc.spec as MySpec,
enabling autocomplete + typo detection at edit time without a
runtime cast.
The typed model is still available via doc.typed.
metadata
cached
property
¶
Always returns SpecDict — typed metadata when available, raw dict otherwise.
spec
cached
property
¶
Always returns SpecDict — typed spec when available, raw dict otherwise.
status
property
¶
The DERIVED status block, or None when there is nothing to report.
Never authored and never stored (the write path strips it): the kernel
computes it at read time from the Kind's current state. Today it says
exactly one thing — that this instance's Kind was REVOKED, so the
instance is no longer valid (i-085). See :mod:dna.kernel.validity.
is_valid
property
¶
Whether the kernel has anything AGAINST this instance.
True is "nothing to report", not "verified" — absence of a status is
the ordinary case for every instance of every Kind. It goes False
when the Kind has been revoked, and back to True the moment it is
approved again, because validity follows the Kind's CURRENT state and
is never a stamp on the instance.
from_raw
classmethod
¶
Create an Instance from a raw dict.
Returns Instance[Any] because the spec type is determined at
the call site by the consumer's annotation; the factory itself
cannot infer it. Consumers using typed access:
doc: Instance[PageIndexSpec] = Instance.from_raw(raw)
get the right type via the annotation.
ManifestInstance¶
dna.kernel.manifest.ManifestInstance ¶
ManifestInstance(
scope: str,
instances: list[Instance],
kinds: dict[tuple[str, str], KindPort],
source: SourcePort | None = None,
resolve_errors: list[str] | None = None,
kernel: Any = None,
profiles: list | None = None,
lazy: bool = False,
)
Facade over a loaded manifest scope.
Marco B (s-lazy-manifest-instance-class, 2026-05-14): supports a LAZY mode where the constructor only receives bootstrap docs (Genome + KindDefinition + LayerPolicy + UA index ~30 docs) instead of the full scope (often 1500+). In lazy mode:
one(kind, name)→ delegates tokernel.get_instance(L2 cached, ~5ms).all(kind)→ delegates tokernel.query(~10ms indexed).instances→ triggers_ensure_loaded()which materializes the full scope. Emits a DeprecationWarning when called in lazy mode — callers should use one/all or kernel.query directly.
Bootstrap kinds (always eager) keep mi.root, mi.kind_for,
namespace getters (mi.composition, mi.nav) functional
cheaply. Heavy operations like mi.summary() /
mi.composition.validate() that iterate the full scope still
force the materialization, but that's the explicit ask.
To enable lazy mode: pass lazy=True to the constructor (the
Kernel does this when DNA_LAZY_MI=1). When lazy=False
(default), ManifestInstance behaves exactly as before — full
back-compat for tests, agent paths, and external callers.
instances
property
writable
¶
Materialized list of all docs. In lazy mode, accessing this
triggers a full load (the only way to honor list semantics).
Prefer one(kind, name) or all(kind) which stay lazy.
Emits a DeprecationWarning in lazy mode the first time the full set is materialized.
root
cached
property
¶
The manifest's root instance (the Genome), or None when the
scope has no doc whose KindPort is marked is_root.
composition_result
cached
property
¶
Validate cross-kind references. Returns resolved + missing + warnings.
all ¶
Return all docs of kind — DEPRECATED, will be removed in 1.0.
s-blessed-query-surface: the blessed query surface is
mi.instances (in-memory, filter by d.kind) plus
kernel.query(scope, kind) for indexed / record-plane reads.
This method survives as a warning shim until 1.0.
all_async
async
¶
Async-native variant of all() — bridge for callers
migrating to await kernel.query(scope, kind).
f-mi-class-extinction (Story s-mi-async-bridge, 2026-05-14):
new API that callers should target during the MI sweep. Returns
the same list[Instance] shape as sync all() but uses
await kernel.query end-to-end — no thread, no asyncio.run,
no loop-mismatch with asyncpg pools.
Bootstrap kinds (Genome, KindDefinition, LayerPolicy) are
served from the in-memory self._instances (no query).
Lazy-cached kinds (already materialized by a previous call)
are served from self._lazy_kind_cache.
Tenant note: does not auto-apply tenant overlay from this
MI's resolved layer context. Callers that need tenant filtering
should pass tenant via kernel.query(..., tenant=...)
directly. The MI overlay-merge is applied at doc content level
and is observable via this method only when the underlying
layer storage already filters by tenant (Postgres adapter does).
all_where ¶
Return all instances whose registered KindPort satisfies a predicate. Forces full materialization in lazy mode (cross-kind walk requires the whole scope).
one_async
async
¶
Async-native variant of one() — bridge for callers
migrating to await kernel.get_instance(scope, kind, name).
f-mi-class-extinction (Story s-mi-async-bridge, 2026-05-14):
new API that callers should target during the MI sweep. Same
return shape as sync one(). Bootstrap kinds + lazy-cached
kinds short-circuit; otherwise delegates to
await kernel.get_instance (L2 cached).
one ¶
Lookup single doc by (kind, name) — DEPRECATED, will be removed in 1.0.
s-blessed-query-surface: the blessed query surface is
mi.instances (in-memory, search by d.kind/d.name)
plus kernel.get_instance(scope, kind, name) for indexed /
record-plane reads. This method survives as a warning shim
until 1.0.
read_spec ¶
Read a single field from instance.spec.
read_metadata ¶
Same contract as read_spec but reads from instance.metadata.
read_spec_list ¶
Read a list-typed spec field, returning [] when missing or None.
default_agent ¶
The agent Instance the root Genome names as its default
(spec.default_agent via the root KindPort), or None when
there is no root or no such agent.
list_kinds ¶
Sorted list of the distinct Kind names present in this manifest's loaded instances.
consumers_of ¶
Walk the manifest and return every doc that references this one.
is_root_doc ¶
Public alias for _is_root_doc — part of the blessed public surface.
kind_for ¶
Return the KindPort registered for kind (by kind name), or None.
kind_for_alias ¶
Return the KindPort whose alias matches, or None.
iter_doc_deps ¶
Iterate an instance's declared dep_filters dynamically.
get ¶
List instances as light {kind, name, apiVersion} dicts —
all of them, or only those of kind. For full Instances use
instances / all() instead.
describe ¶
Human-readable description of one instance (metadata, spec highlights, relationships) — delegates to the Navigator.
summary ¶
Plain-text overview of the manifest (scope + the instances loaded, grouped by kind) — delegates to the Navigator.
inventory ¶
Structured inventory of everything loaded in this manifest.
dependency_tree ¶
Build a dependency tree for every instance that has dep_filters.
ref ¶
Resolve a file reference via source, or return value as-is.
Sync entry-point. Use this from CLI / tests / sync workers
whose top-level entry is asyncio.run. Async callers MUST
use meth:
ref_async — running this from inside an event
loop with a postgres source orphans the asyncpg pool.
ref_async
async
¶
Async variant of meth:
ref.
Use from inside the harness event loop (lifespan, request
handlers, async middleware). Awaits source.resolve_ref
directly on the caller's loop, which is the same loop that
owns the asyncpg pool — no cross-loop dispatch needed.
build_prompt ¶
build_prompt(
agent: str | None = None,
context: dict[str, Any] | None = None,
enabled_skills: list[str] | None = None,
enabled_guardrails: list[str] | None = None,
enabled_slots: dict[str, list[str]] | None = None,
) -> str
Build system prompt via template cascade.
Sync — uses _run_sync_helper to await source ref()
coroutines. Callers inside an async event loop must use
build_prompt_async to avoid the "called from inside a
running loop" guard.
build_prompt_async
async
¶
build_prompt_async(
agent: str | None = None,
context: dict[str, Any] | None = None,
enabled_skills: list[str] | None = None,
enabled_guardrails: list[str] | None = None,
enabled_slots: dict[str, list[str]] | None = None,
) -> str
Async variant of meth:
build_prompt. Use from
inside an async caller (test, middleware, etc.) so the
ref_async path keeps the source pool's loop binding
intact.
explain_prompt ¶
explain_prompt(
agent: str | None = None,
*,
context: dict[str, Any] | None = None,
enabled_skills: list[str] | None = None,
enabled_guardrails: list[str] | None = None,
enabled_slots: dict[str, list[str]] | None = None,
tenant: str | None = None
) -> "PromptExplanation"
Compose agent AND return per-section provenance.
The prompt field is byte-identical to meth:
build_prompt;
sections attributes each composed section (instruction, soul,
skills, guardrails) to its source artifact, hash, version, and
layer/overlay origin. Sync — see meth:
build_prompt.
explain_prompt_async
async
¶
explain_prompt_async(
agent: str | None = None,
*,
context: dict[str, Any] | None = None,
enabled_skills: list[str] | None = None,
enabled_guardrails: list[str] | None = None,
enabled_slots: dict[str, list[str]] | None = None,
tenant: str | None = None
) -> "PromptExplanation"
Async variant of meth:
explain_prompt.
find_agent ¶
Find the best prompt-target instance matching name.
Considers prompt_target_priority when multiple kinds match. Public API — use this instead of _find_agent().
resolve ¶
Apply layer overlays (sync). Delegates to Kernel.resolve_layers().
Memoizes per-layers so repeated mi.resolve({"tenant": X}) calls
from request handlers reuse the same merged instance instead of
re-reading every doc from disk. Cache lives on the base mi;
MIHolder.reload() swaps the base instance, which discards
this cache transparently.
From inside an event loop, prefer await mi.resolve_async(layers)
— the sync path falls back to a ThreadPool/asyncio.run dance
that orphans pool-based source adapters.
resolve_async
async
¶
Async variant of resolve. Use from inside an event loop
(request handlers, lifespan, EventBus consumer) so the source
pool stays tied to the caller's loop.
apply_hooks ¶
Ask every loaded extension to activate the instances it owns.
Historically this method WAS the activation: it read Hook.spec
field by field (target/type/action/fields/body,
exec()-ing the body, branching on the middleware/event and
inject_fields/log/script enums), then read
SafetyPolicy.spec (scope/action/rules) and built a
dna.safety.scanner.ScannerPipeline. Two Kinds' schemas, parsed in
the kernel, while the extensions that register those Kinds did nothing
but kernel.kind(...) — the dependency pointing the wrong way.
i-112 (board dna) inverted it, and MOVED rather than declared: a trait
would have swapped two strings and left every field read exactly where
it was, which is the shape i-109 refused because it makes the boundary
LOOK fixed. The behaviour now lives in HookExtension and
SafetyPolicyExtension via
:class:~dna.kernel.protocols.ManifestActivator; what is left here is
the entry point, and it names no Kind.
The NAME stays apply_hooks: it is published API (the golden port
surface, docs/concepts/builtin-kinds.md, and HookKind.docs
itself all say a Hook is registered "when
ManifestInstance.apply_hooks() is called"). A rename here would
have been the cleanup that breaks every caller for a nicer word.