Skip to content

Packs

The pack format primitives. For the conceptual model and the authoring workflow see the Authoring packs guide.

The shipped reference pack is Diligence.

Pack declaration

A frozen bundle of pack contents.

Equality and hashing are by (name, version) — NOT by deep field comparison. Behaviors and tools are dataclasses (not hashable); full structural equality would not work and isn't what users care about. The identity that matters is "is this the same pack name and version" — that's what idempotent loading hinges on.

prompt_manifest()

The pack.loaded payload's prompts block. Maps prompt name to {"version", "hash"}. CONTRACT v0.9 #10.

A typed object the pack contributes.

schema is a Pydantic BaseModel subclass. When the pack is loaded, graph.add_object(name, data=...) validates against it. Validation applies only to objects created AFTER the pack loads (CONTRACT v0.9 #5).

A typed relation the pack contributes.

source_types and target_types are tuples of object type names; empty means "any".

A policy declared by a pack.

requires_approval: tuple of object type names whose add_object is gated until runtime.approve(...) is called.

A versioned, content-hashed prompt.

version is the declared human-readable version (for changelogs and operator messages). content_hash is the SHA-256 of the body truncated to 16 hex chars; this is the replay contract (the hash, not the version — see CONTRACT v0.9 #10).

Bases: BaseModel

For packs with no configurable settings. The default settings_schema.

A Pydantic model with zero fields, so no-settings packs flow through the same typed-injection machinery as configurable ones (CONTRACT v0.9 #7) — behaviors can still ask for settings and get a real instance rather than a None special case.

Discovery

Enumerate installed packs via the activegraph.packs entry point group. Cached per process; call clear_discovery_cache() to force a re-scan.

Find a discovered pack by name.

Resolves against the discover() scan of installed entry-point packs and returns the :class:Pack object — pass it to runtime.load_pack to actually load it. Raises PackNotFoundError (a LookupError) naming the installed packs when the name doesn't resolve.

Reset the cached entry-point scan.

discover() memoizes its result for the life of the process (installed packages don't change under a normal run). Tests that install or mock packages dynamically call this between cases; normal usage never needs it.

Scan a directory of *.md prompt files with TOML frontmatter.

Each file MUST start with:

---
version = "1.0.0"
name = "optional_name"   # defaults to filename without .md
---
<body>

Returns a tuple of PackPrompt sorted by name. Content hash is computed over the body (everything after the second --- line and one separating newline), exactly as it will appear at runtime.

Errors
  • missing/malformed frontmatter -> PackPromptLoadError
  • missing required version field -> PackPromptLoadError
  • duplicate prompt name -> PackPromptLoadError
  • I/O failure -> PackPromptLoadError

A pack discovered via Python entry points but not yet loaded.

What discover() yields per installed distribution that registers the activegraph.packs entry-point group: the pack's name / version, the entry-point string it came from, and the :class:Pack object itself. Discovery imports the pack module but changes no runtime state — loading is a separate, explicit runtime.load_pack call.

Approvals + policies

Declared write/tool allowlists for a behavior.

behavior names the behavior the lists scope to; the can_* fields enumerate the object types, relation types, patches, and tool names it may touch, and requires_approval routes matching writes through the pending-approval flow. v0 semantics stand: fields are recorded with the run for audit; the actively enforced gate today is approval routing (pack policies, CONTRACT v0.9), with broader enforcement reserved for a hardening pass.

An object creation that's gated behind a policy approval.

The id is unique within the runtime instance and is reused as the eventual object id once approved. kind is "object" in v0.9; the field exists so v1.0 can extend it to relations or patches without breaking the API.