Package Ecosystem Specification
Overview
Deterministic, content-addressed package system for the Boruna platform. No remote registries, no version ranges, no dynamic loading. All resolution is exact and reproducible.
Package Manifest (package.ax.json)
Every package has a manifest at its root:
{
"name": "example.package",
"version": "0.1.0",
"description": "Short description",
"dependencies": {
"other.package": "0.2.1"
},
"required_capabilities": ["net.fetch", "db.query"],
"exposed_modules": ["core", "utils"],
"integrity": "sha256:<hex>"
}
Fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Dotted package name (e.g. std.collections) |
version | string | yes | Semver (MAJOR.MINOR.PATCH) |
description | string | yes | Human-readable description |
dependencies | map | no | Package name → exact version |
required_capabilities | array | no | Capability strings from boruna-bytecode::Capability |
exposed_modules | array | yes | Module names this package exposes |
integrity | string | computed | Content hash, set by boruna-pkg publish |
Validation Rules
namemust match^[a-z][a-z0-9]*(\.[a-z][a-z0-9]*)*$versionmust be valid semver:MAJOR.MINOR.PATCHdependenciesmust specify exact versions (no ranges, no wildcards)required_capabilitiesmust be valid capability names fromboruna-bytecode::Capabilityexposed_modulesmust contain at least one entryintegrityis computed at publish time; absent in development
Lockfile (ax.lock.json)
Generated only by the resolver. Never hand-edited.
{
"lockfile_version": 1,
"resolved": {
"[email protected]": {
"integrity": "sha256:abc123...",
"dependencies": {
"other.package": "0.2.1"
}
},
"[email protected]": {
"integrity": "sha256:def456...",
"dependencies": {}
}
}
}
Rules
- Generated by
boruna-pkg resolve - Execution must use lockfile exclusively
- Missing or invalid lockfile is a hard error at build/run time
- Lockfile must be committed to version control
- Changing lockfile requires reviewer approval (orchestrator gate)
Package Storage (Local Registry)
Content-addressed layout:
packages/
registry/
<package-name>/
<version>/
package.ax.json
src/
<module>.ax
bytecode/
<module>.axbc
HASH
Content Hash
The HASH file contains sha256:<hex> computed over:
- All source files (
src/**/*.ax) sorted by path - The manifest (
package.ax.json) withintegrityfield removed - Dependency hashes (sorted by package name)
This produces a Merkle-like hash: changing any transitive dependency changes the root hash.
Publish Flow
- Validate manifest
- Compile all exposed modules to bytecode
- Compute content hash
- Set
integrityfield in manifest - Copy to registry under
<name>/<version>/
Resolver
Algorithm
- Parse root manifest dependencies
- For each dependency, load its manifest from registry
- Recursively resolve transitive dependencies
- Topological sort (Kahn’s algorithm)
- Detect circular dependencies → hard error
- Detect conflicts (two versions of same package) → hard error
- Generate lockfile with all resolved packages and their hashes
Invariants
- Same manifest + same registry → identical lockfile (deterministic)
- No version range resolution
- No SAT solver
- Fail fast on any ambiguity
Capability Enforcement
When building an application:
- Parse root manifest’s
required_capabilities - For each dependency (transitively), collect
required_capabilities - Union all capabilities
- Check against application policy
- If any dependency requires a forbidden capability → compile error
Policy Format
Application policy is specified in the root manifest or a separate policy.ax.json:
{
"allowed_capabilities": ["net.fetch", "time.now"],
"denied_capabilities": ["fs.write", "random"]
}
If allowed_capabilities is present, only those are permitted.
If denied_capabilities is present, those are blocked.
Cannot specify both. If neither, all capabilities are allowed.
CLI Commands
| Command | Description |
|---|---|
boruna-pkg init | Create package.ax.json in current directory |
boruna-pkg add <pkg> <version> | Add dependency to manifest |
boruna-pkg remove <pkg> | Remove dependency from manifest |
boruna-pkg resolve | Generate ax.lock.json from manifest + registry |
boruna-pkg install | Resolve + verify all packages exist in registry |
boruna-pkg publish | Compile, hash, copy to local registry |
boruna-pkg verify | Verify all installed packages match their hashes |
boruna-pkg tree | Print dependency tree |
Orchestrator Integration
When a patch bundle touches package.ax.json or ax.lock.json:
- Gate adapter re-runs
boruna-pkg resolveand verifies lockfile matches - Lockfile changes require reviewer approval (two-person rule)
- Capability changes in dependencies trigger policy re-evaluation
Security Model (MVP)
- Local registry only (no remote fetch)
- No auto-download
- Manual publish/install
- Hash verification mandatory on every install/build
- No code execution during install
Non-Goals (MVP)
- Remote package registry
- Version range resolution
- Optional dependencies
- Platform-specific packages
- Pre/post install scripts
- Binary distribution