Catalog & Package System

How the package ecosystem works — format specification, dependency resolution, multi-registry architecture, signing, and air-gapped distribution.

System Overview

.hpkg Package Format

A .hpkg file is a deterministic tar.gz archive containing:

package-name-1.0.0.hpkg (tar.gz)
├── MANIFEST.toml        ← always first (streamable extraction)
├── SIGNATURE.ed25519    ← ed25519 signature (optional)
├── README.md            ← documentation (optional)
├── LICENSE              ← license text (optional)
├── sbom.json            ← software bill of materials (optional)
└── payload/             ← package contents (sorted recursively)
    ├── COMPETENCY.md    ← markdown with YAML frontmatter (the artifact)
    ├── references/      ← optional reference docs
    ├── assets/          ← optional templates, schemas
    └── ...

Markdown-First Payload Format

The .md file IS the package artifact. YAML frontmatter carries structured metadata, the markdown body carries the prompt/instructions. One .md file per package type:

Package TypePayload FileRequired Frontmatter
SkillSKILL.mdname, description
CompetencyCOMPETENCY.mdid, name, description, category, skills
ToolTOOL.mdname, description, runtime, entry
AgentTemplateAGENT.mdname, description
WorkflowTemplateWORKFLOW.mdname, description
IntegrationINTEGRATION.mdname, description, transport

Example SKILL.md:

---
name: rust-expert
description: "Rust programming expert"
tags: [rust, systems, async]
runtime: prompt-only
---

# Rust Expert

You are an expert Rust developer...

The platform translates .md payloads to kernel-native format (e.g., skill.toml) only at the install boundary — never in the archive, never in the registry.

Determinism

Archives are reproducible:

  • Files sorted lexicographically by path
  • Fixed timestamp: 2024-01-01 00:00:00 UTC (hardcoded)
  • Same input always produces same output (byte-identical)

Size Limit

Maximum package size for upload: 50 MB (enforced client-side before publish).

MANIFEST.toml Schema

[package]
type = "competency"                    # tool | skill | competency | agent-template | workflow-template | integration
name = "claims-intake"                 # kebab-case, 3-64 chars
version = "1.2.0"                      # semver 2.0
description = "FNOL processing"        # ≤500 chars
license = "MIT"                        # SPDX identifier
min_platform_version = "0.5.0"         # minimum Hoziron version

[package.author]
name = "Insurance Corp"
email = "platform@company.com"         # optional
url = "https://company.com"            # optional

[package.metadata]
repository = "https://github.com/..."  # optional, must be http(s)
homepage = "https://..."               # optional
keywords = ["insurance", "claims"]     # max 20, each ≤50 chars
categories = ["insurance/claims"]      # taxonomy paths
regions = ["us", "uk"]                 # deployment regions (empty = all)

[dependencies]
document-ocr = "^1.0"                  # semver constraint
postgresql-connector = ">=2.0.0, <3.0.0"

[optional-dependencies]
email-skill = "^1.2"

[peer-dependencies]
guidewire-claimcenter = "^3.0"         # must be installed separately

[standards]
mcp_compatible = true                  # exposes MCP tool interface
openapi_spec = "payload/openapi.yaml"  # only for tool/skill/integration

[signing]
publisher_key = "ed25519:mK3xR7..."    # populated by `package sign`
content_hash = "sha256:a1b2c3d4..."    # populated by `package build`

Package Types

TypeContainsUse Case
toolSingle tool implementationPython/WASM/Node/Shell script
skillTool bundle + configMulti-tool skill package
competencyCOMPETENCY.toml + prompts + knowledgeAgent behavior definition
agent-templateFull agent configPre-configured agent
workflow-templateWorkflow JSON + agent refsMulti-agent pipeline
integrationMCP server implementationExternal service connector

Validation Rules

FieldRule
nameLowercase, digits, hyphens only. No leading/trailing/consecutive hyphens. 3–64 chars.
versionValid semver (MAJOR.MINOR.PATCH, optional pre-release)
descriptionNon-empty, ≤500 characters
licenseNon-empty SPDX identifier
dependenciesEach constraint must be a valid semver range
standards.openapi_specOnly valid for tool, skill, integration types
standards.mcp_compatibleOnly valid for tool, skill, integration types

Cryptographic Signing

Key Generation

hoziron package keygen
  • Algorithm: Ed25519
  • Private key: 32 random bytes (OS RNG), stored base64-encoded at $HOZIRON_HOME/keys/default.key
  • Public key format: ed25519:<base64-of-32-bytes>
  • File permissions: 0600 (owner read/write only)

Signing Flow

Verification Flow

Content Hash (Merkle Root)

The content hash is a deterministic SHA-256 over the payload:

For each file in payload/ (sorted lexicographically by relative path):
    entry_hash = SHA-256(relative_path_bytes + file_content_bytes)

content_hash = SHA-256(entry_hash_1 + entry_hash_2 + ... + entry_hash_N)

Dependency Resolution

Algorithm

Semver Constraints

SyntaxMeaningExample
*Any versionMatches everything
1.2.3Caret (same as ^1.2.3)>=1.2.3, <2.0.0
^1.2.3Compatible updates>=1.2.3, <2.0.0
~1.2.3Patch-level only>=1.2.3, <1.3.0
=1.2.3Exact matchOnly 1.2.3
>=1.0.0, <2.0.0RangeCompound constraint
>1.0.0Greater thanComparison

Conflict Detection

When two packages require incompatible versions of the same dependency:

Package A requires C@^1.0.0 (resolves to 1.x)
Package B requires C@^2.0.0 (resolves to 2.x)
→ No single version of C satisfies both → VersionConflict error

The error reports which packages imposed which constraints:

version conflict for package 'pkg-c':
  - pkg-a requires pkg-c@^1.0.0
  - pkg-b requires pkg-c@^2.0.0

Cycle Detection

DFS with visited/stack sets. When a back-edge is found, the full cycle path is reported:

dependency cycle detected: pkg-a → pkg-b → pkg-c → pkg-a

Diamond Dependencies

Handled correctly — the resolver selects the highest version that satisfies all constraints:

A requires C@^1.0.0
B requires C@^1.5.0
Available: C@1.0.0, C@1.5.0, C@1.8.0
→ Resolves C to 1.8.0 (satisfies both ^1.0.0 and ^1.5.0)

Lockfile (packages.lock)

Ensures reproducible installs by recording exact resolved versions:

[metadata]
generated_at = "2026-06-04T10:00:00Z"
resolver_version = 1

[[package]]
name = "claims-intake"
version = "1.2.0"
source = "https://catalog.hoziron.com"
content_hash = "sha256:a1b2c3d4..."
dependencies = ["document-ocr", "postgresql-connector"]

[[package]]
name = "document-ocr"
version = "1.4.0"
source = "https://catalog.hoziron.com"
content_hash = "sha256:e5f6a7b8..."
dependencies = []

Behavior

  • If lockfile exists and all constraints are satisfied → use locked versions (no network)
  • If --force-resolve or lockfile is stale → re-resolve and rewrite
  • Supports merge (incremental installs) and remove (uninstalls)

Multi-Registry Architecture

Configuration

[catalog]
verify_signatures = true
packages_dir = "packages"
cache_ttl_secs = 3600
default_publish_registry = "internal"

[[catalog.registries]]
name = "internal"
url = "https://packages.internal.company.com"
priority = 1
auth_token_env = "INTERNAL_REGISTRY_TOKEN"
enabled = true

[[catalog.registries]]
name = "hoziron"
url = "https://catalog.hoziron.com"
priority = 100
enabled = true

[catalog.scopes]
internal = "https://packages.internal.company.com"
hoziron = "https://catalog.hoziron.com"

Scoped Packages

@scope/name syntax pins a package to a specific registry:

# This ONLY queries the registry mapped to "internal"
hoziron catalog install @internal/proprietary-claims-tool

Scope rules:

  • Scope names: lowercase alphanumeric + hyphens
  • Must be mapped in [catalog.scopes] → error if unknown scope
  • Bypasses priority-order resolution entirely
  • Prevents name collisions between registries

Publish Target Resolution

When publishing, the target registry is resolved:

  1. Explicit --registry <name> flag
  2. Scope-based routing (if package name has @scope/ prefix)
  3. default_publish_registry config field
  4. Error: "no publish target specified"

Collections

Curated, self-contained sets of packages for quick onboarding.

COLLECTION.toml

name = "insurance-starter"
display_name = "Insurance Starter Kit"
description = "Everything needed to start processing claims"
version = "1.0.0"
license = "MIT"
featured = true
tags = ["insurance", "claims", "starter"]
icon = "shield-check"

[author]
name = "Hoziron Team"

[[packages]]
name = "claims-intake"
version = "1.2.0"
package_type = "competency"
is_dependency = false

[[packages]]
name = "document-ocr"
version = "1.4.0"
package_type = "tool"
is_dependency = true

[[packages]]
name = "postgresql-connector"
version = "2.1.0"
package_type = "tool"
is_dependency = true

Closure Invariant

A collection must include ALL transitive dependencies of every package it contains. Installing a collection never requires fetching packages outside the collection.

Validated by validate_collection_closure() — reports which package is missing which dependency.

Installation

hoziron collection install insurance-starter
# Installs all packages, skipping any already installed

Collections are additive — users can install multiple, overlapping packages are deduplicated.

Air-Gapped Transfer

For environments without network access:

  • Export creates a plain tar of the installed package directory
  • Import extracts, reads the manifest, and records installation
  • No network required on the air-gapped side
  • Content hash verified locally after import

Taxonomy

Packages are categorized using a hierarchical taxonomy:

Domain → Subdomain → Function → Variants

Structure (Insurance domain example)

insurance/
├── claims/
│   ├── fnol (variants: auto, property, liability, workers-comp, marine, aviation)
│   ├── adjudication
│   ├── subrogation
│   ├── reserving
│   ├── litigation
│   ├── catastrophe (variants: weather, wildfire, earthquake, flood)
│   └── total-loss
├── fraud/
│   ├── detection (variants: claims, application, premium)
│   ├── investigation
│   ├── prevention
│   └── network-analysis
├── underwriting/
│   ├── risk-assessment
│   ├── rating
│   ├── quoting
│   └── submission-intake
├── policy-admin/
│   ├── issuance
│   ├── endorsements
│   ├── renewals
│   └── cancellations
└── ... (actuarial, distribution, compliance, billing, reinsurance, LOB)

Additional Domains

  • Banking & Financial Services — lending, payments, KYC/AML
  • Healthcare — clinical, revenue cycle
  • Document Processing — extraction, generation
  • General — productivity, development, data

Taxonomy Versioning (ADR-004)

  • Append-only (nodes added, never removed)
  • Semver versioned (patch = description changes, minor = new nodes, major = structural)
  • Compiled into the binary as offline fallback
  • Registry serves canonical version at runtime
  • Unknown nodes gracefully degrade (display raw ID, never hard error)