Kit Authoring And Distribution¶
A Cruxible kit is a versioned bundle with a cruxible-kit.yaml manifest,
an entry config, provider code, optional data, and a bundled
cruxible.lock.yaml.
For runnable examples, see Kit Walkthroughs.
Operation-Style Relationship Axes¶
Kits that model work, reviews, investigations, remediation, agent operations,
or project execution should not collapse every relationship into one generic
related_to or blocks edge. Start with explicit axes so readiness, critical
path, review, and roll-up queries can keep their meanings separate.
Use these defaults when the kit has work-like entities:
| Axis | Relationship Shape | Meaning |
|---|---|---|
| Sequencing | work_item_depends_on_work_item |
Direction: from depends on to. The target must land, be decided, or stabilize first. |
| Impediment | risk_blocks_work_item, open_question_blocks_work_item |
A durable unresolved threat or uncertainty blocks or materially delays work. |
| Resolution | work_item_mitigates_risk, work_item_answers_open_question, decision_answers_open_question |
Work or a decision resolves the impediment without pretending the impediment was sequencing. |
| Composition | work_item_part_of_work_item |
Child work is part of a larger scope. This is roll-up, not order. |
| Lineage | work_item_spawned_from_work_item |
A follow-up came out of earlier work. This is provenance, not a prerequisite. |
| Replacement | work_item_supersedes_work_item, decision_supersedes_decision |
The source replaces the target. This is not general lineage. |
| Review gate | review_request_for_work_item plus a mutation guard |
A work item cannot move to a guarded lifecycle value until the review request is approved. |
| Interpretation history | StateNote plus typed note-about relationships |
Durable corrections, field notes, implementation notes, and review notes without bloating current entity fields. |
Do not make these hidden Cruxible defaults. Put the relationships in the kit config with domain-specific names when needed, because the ontology is the contract agents and reviewers inspect.
Use direct relationships for deterministic placement and roll-up. Use governed proposal policies for interpretive claims such as dependencies, blockers, mitigations, answers, supersession, and decision impact. Documents, chats, review reports, and source sections should be evidence references for those claims, not modeled entities.
Minimal operation-axis scaffold:
enums:
work_status:
values: [planned, active, blocked, watching, closed, deferred, superseded]
work_priority:
values: [critical, high, medium, low]
note_kind:
values: [correction, field_note, rationale_update, implementation_note, review_note]
entity_types:
WorkItem:
properties:
work_item_id: {primary_key: true}
title: {required: true}
status: {enum_ref: work_status, required: true}
priority: {enum_ref: work_priority}
summary: {}
Risk:
properties:
risk_id: {primary_key: true}
title: {required: true}
status: {}
OpenQuestion:
properties:
question_id: {primary_key: true}
title: {required: true}
status: {}
Decision:
properties:
decision_id: {primary_key: true}
title: {required: true}
status: {}
ReviewRequest:
properties:
review_request_id: {primary_key: true}
title: {required: true}
status: {required: true}
summary: {}
review_notes: {}
StateNote:
properties:
state_note_id: {primary_key: true}
note_kind: {enum_ref: note_kind, required: true}
noted_at: {required: true}
body: {required: true}
relationships:
- name: work_item_depends_on_work_item
description: "Sequencing: from depends on to."
from: WorkItem
to: WorkItem
proposal_policy:
signals:
source_evidence: {role: required, always_review_on_unsure: true}
maintainer_judgment: {role: advisory, always_review_on_unsure: true}
- name: risk_blocks_work_item
description: "Impediment: a risk blocks or materially delays work."
from: Risk
to: WorkItem
proposal_policy:
signals:
source_evidence: {role: required, always_review_on_unsure: true}
maintainer_judgment: {role: advisory, always_review_on_unsure: true}
- name: open_question_blocks_work_item
description: "Impediment: an unresolved question blocks or delays work."
from: OpenQuestion
to: WorkItem
proposal_policy:
signals:
source_evidence: {role: required, always_review_on_unsure: true}
maintainer_judgment: {role: advisory, always_review_on_unsure: true}
- name: work_item_part_of_work_item
description: "Composition and roll-up, not sequencing."
from: WorkItem
to: WorkItem
- name: work_item_spawned_from_work_item
description: "Lineage and follow-up provenance, not sequencing."
from: WorkItem
to: WorkItem
- name: work_item_supersedes_work_item
description: "Replacement: source supersedes target."
from: WorkItem
to: WorkItem
proposal_policy:
signals:
source_evidence: {role: required, always_review_on_unsure: true}
maintainer_judgment: {role: advisory, always_review_on_unsure: true}
- name: review_request_for_work_item
from: ReviewRequest
to: WorkItem
- name: state_note_about_work_item
from: StateNote
to: WorkItem
Add named queries around the axes rather than broad text search: active work queue, blocked work with blocker context, work-item change context, roll-up context, lineage context, pending reviews, and recent state notes. Add quality checks or mutation guards only where they protect real operating discipline, such as one composition parent, review requests attached to work, and closing work only after an approved review.
Minimal manifest:
schema_version: cruxible.kit.v1
kit_id: kev-triage
version: 0.2.0
role: overlay
target_state: kev-reference
entry_config: config.yaml
provider_paths:
- providers
copy_paths:
- data
- skills
- README.md
requires_extras: []
Rules:
roleisstandaloneoroverlay.role: overlayrequirestarget_state.role: standalonemust not settarget_state.- 0.2 supports one
entry_configper kit. requires_extrasis metadata only. Cruxible does not install kit dependencies automatically.
Provider refs use kit://:
kit:// paths are relative to the materialized kit root. Absolute paths,
.., symlinks, and paths outside declared provider_paths are rejected.
Python providers run in the current Cruxible Python environment and may import
stdlib, cruxible_core, installed Cruxible dependencies or extras, and files
under declared provider paths.
Bundle behavior:
- The bundle digest covers every non-junk regular file in sorted POSIX-relative order, including path and bytes.
- Junk such as
__pycache__/,*.pyc,.DS_Store,.ruff_cache/, and.pytest_cache/is ignored. - Symlinks are rejected.
- Bundles are cached under
CRUXIBLE_KIT_CACHE_DIRor${XDG_CACHE_HOME:-~/.cache}/cruxible/kits. - Cache installs are locked and atomic by bundle digest.
- Materialization copies the cached kit into the instance root.
- Kit bundles carry
cruxible.lock.yamlat the kit root as a portable bundle artifact. - Initialized Cruxible instances execute workflows from
.cruxible/cruxible.lock.yaml; kit-backed initialization imports the bundled lock there when it matches the active config, or regenerates the instance-local lock when an active runtime config has been composed from the bundle. - Runtime workflow execution does not fall back to arbitrary config-root locks.
- Consumers should not silently regenerate published bundled locks. Rebuild the kit lock before publishing or distributing a changed kit.
Standing Views And Decision Surfaces¶
A domain kit's read surface has three tiers, and shipping all three is what makes a kit feel alive rather than inert:
- At least one standing "requiring action" view — a parameterless
mode: collectionquery over the state that needs attention now (open incident impacts, postures requiring action, upcoming deadlines). This is the queue surface: it renders in UIs with no input and answers "what needs a decision today?" Order it by the fields a triager would sort by, usingorderedenums. - Parameterized decision queries — traversal queries anchored on the
entity a decision is about (
entry_point), supplying the evidence a decision report pulls: scope, exposure, alternatives, obligations. - Proposal workflows — where interpretive claims enter as governed candidates. The queue view tells you which entity needs judgment; the decision queries justify it; the proposal/resolution flow records it.
Reference kits (published state that consumers subscribe to) ship no standing views: the actionable views belong to the overlay that composes local judgment over the reference, not to the reference itself.
Keep each query in its layer: a query touching only operating-layer types (work items, reviews, actors) belongs in the operating-state kit; queries joining domain types to operating types must live in the overlay, since only the overlay can see both vocabularies.
Seed Data Is A Worked Example¶
A kit's data/ ships as a pinned workflow artifact (lock-covered,
digest-attested), and for demo kits it is fictional: a worked example so the
kit runs end to end in minutes, not a starter dataset to build on. Adopting a
kit for real use means replacing the seed with your own exports — the
ingest workflows are the interface, the seed files are just one example input:
- Point the ingest/refresh workflows at your own exports (or swap the pinned artifact for your data directory and re-lock).
- Do not run seed workflows (
build_seed_stateand friends) against an instance that already carries real state; they exist to demonstrate the pipeline shape. - Real reference data (a public catalog snapshot) is the exception: that is kit content, not an example, and updates with the kit version.
Published Kit Bundles¶
Installed distributions resolve built-in aliases such as kev-reference from
digest-pinned release bundles, so cruxible init --kit <name> works without a
source checkout. scripts/build_kit_bundles.py builds a deterministic
dist/kits/<id>-<version>.tar.gz for every kits/<id>/ (byte-identical across
runs: sorted members, zeroed timestamps and ownership, normalized permissions)
and regenerates src/cruxible_core/kit_distribution/manifest.json, which ships
in the wheel and pins each bundle by tarball sha256 and by the extracted
directory digest — the same compute_path_sha256 discipline kit locks use.
The tarballs are uploaded as release assets on the v<version> tag; the
regenerated manifest is committed before tagging, and CI asserts it matches a
fresh digest of every kits/<id> directory (like the kit lock freshness
check).
Alias resolution order:
- Local source-checkout
kits/directories always win (development). - Published release bundles from the packaged manifest: the tarball sha256 is
verified before extraction, members are safe-extracted (files and
directories only, no absolute paths,
.., or links), the extracted tree must match the pinned directory digest, and the verified kit is installed atomically into the kit cache keyed by that digest. Any mismatch deletes the artifacts and refuses; a cache hit skips the network entirely. - Shipped
oci://refs cover aliases absent from the packaged manifest.
An overlay kit's target_state base resolves through the same order, so a
fetched overlay composes over its fetched base with no local kits present.
CRUXIBLE_KIT_MANIFEST_URL_BASE overrides the manifest's release base_url
(pre-publish smoke runs against a local file server); asset names and digests
still come from the packaged manifest.
Refresh a bundled lock directly from the kit root before publishing:
The lock pins the kit's own config layer only — its providers and artifacts,
with URIs kept relative to the kit root — so an overlay kit locks without its
target_state base present. Base-layer content is pinned by the base kit's
own lock. CI asserts every bundled kit's committed lock matches a fresh regen,
so run this after any config, provider, or seed-data change.
Vocabulary:
- Use overlay for a local instance tracking a published upstream state.
- Use clone for a point-in-time state copy from a snapshot.
- Use local for customer-owned seeded or runtime state.
- Do not use clone for kit distribution. Use pull, cache, materialize, or install.