Create, validate, and publish AILANG packages with correct conventions. Use when user asks to create a new package, fix package errors, add dependencies, publish to registry, or import packages. Also use when encountering `IMP010`, `LDR001`, `MOD010`, or `export type` errors during package development.
Installs into .claude/skills of the current project.
Are you the author of Ailang Packages?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/sunholo-data-ailang-packages-ailang)
---
name: ailang-packages
description: Create, validate, and publish AILANG packages with correct conventions. Use when user asks to create a new package, fix package errors, add dependencies, publish to registry, or import packages. Also use when encountering `IMP010`, `LDR001`, `MOD010`, or `export type` errors during package development.
---
# AILANG Package Development
Create, validate, and publish AILANG packages with correct conventions. Use when user asks to create a new package, fix package errors, add dependencies, publish to registry, or import packages. Also use when encountering `IMP010`, `LDR001`, `MOD010`, or `export type` errors during package development.
## When to Use This Skill
- User wants to create a new AILANG package
- User encounters package-related errors (IMP010, LDR001, MOD010, type unification across packages)
- User asks about `ailang.toml`, `ailang.lock`, package imports, or package publishing
- User wants to add dependencies between packages
- User asks "how do I import from another package" or "how do I export types"
- Code has `import pkg/` or `import ./` paths that aren't resolving
## Start with the installed binary
Read `ailang docs package-authoring` first. If unavailable on an older binary,
read the **whole** `ailang prompt`, including its contracts, testing and package
sections. Use `ailang docs --all-functions <term>` and `ailang pkg-docs --help`
before web search or guessing APIs. Verify historic limitations with a minimal
reproducer against the installed version.
## Native quality evidence
Separate pure logic from effectful adapters. Use ADTs for closed states/errors,
meaningful requires/ensures for pure functions, boundary/invalid examples in
native tests and properties for algebraic invariants. Declare minimal effect
ceilings and bounded effect counts with @limit where meaningful. Never add
vacuous contracts just to satisfy a count.
Run `ailang pkg quality --strict .` for the package quality report: compile,
contracts, interface, effects, docs, style, and attested *_test.ail tests and
smoke. It does **not** run inline test blocks in source modules, and it is not
coverage or proof. Older binaries lacking this command require a manual
evidence review; report that limitation explicitly.
`ailang test --package .` only discovers *_test.ail. Run source modules with
inline tests explicitly (`ailang test module.ail`) too. A plain function named
test_* is not a native test declaration. Report actual totals, failures and skips;
zero discovered tests does not validate behavior. Use `ailang verify --help` for
SMT verification and report proved/unknown/skipped outcomes separately.
## Quick Reference
### Create a Package
```bash
ailang init package --name vendor/name
ailang init package --name sunholo/mylib --module-prefix mylib --dep sunholo/config
```
### Install Dependencies
```bash
ailang install sunholo/auth # Install latest version (resolves from registry)
ailang install sunholo/auth@latest # Same as above
ailang install sunholo/auth@0.1.0 # Install exact version
```
`@latest` resolves once and writes the **exact version** to `ailang.toml`. Semver ranges (`^`, `~`, `>=`) are not supported — AILANG requires exact versions in manifests for determinism.
### Package Lifecycle
```bash
ailang lock # Resolve dependencies → ailang.lock
ailang check --package . # Type-check all modules (cross-module resolution)
ailang test --package . # Run *_test.ail files
ailang pkg quality --strict . # Inventory missing authoring evidence
ailang publish --dry-run # Packaging preview, not remote validation or proof
ailang publish # Publish to registry
```
## Critical Rules (learned from production)
### 1. Module names use underscores, never hyphens
Hyphens parse as subtraction. Directory names can have hyphens, but module paths must use underscores.
```
Directory: packages/billing-store/
Module: module sunholo/billing_store/customers_repo
Import: import pkg/sunholo/billing_store/customers_repo (getCustomer)
```
### 2. Use `./` for intra-package sibling imports
Three-way import distinction — locality is explicit at the point of use:
```ailang
import ./plan (Plan, lookupPlan) -- LOCAL: sibling in same package
import pkg/sunholo/firestore/client (getDoc) -- EXTERNAL: different package
import std/result (Ok, Err) -- STDLIB: bundled
```
`./` resolves in **module namespace** (not filesystem): if current module is `sunholo/billing_entitlements/entitlement`, then `./plan` normalizes to `sunholo/billing_entitlements/plan`.
```ailang
import ./plan (Plan, lookupPlan, freePlan) -- sibling
import ./sub/helpers (validate) -- child directory
```
`pkg/` self-imports also work (backward compatible) but `./` is preferred.
### 3. Cross-package types MUST use `export type`
Types used by other packages need `export type`, not just `type`. Without it, consumers get `IMP010: symbol not exported`.
```ailang
-- WRONG: only visible within this module
type Customer = { name: string, email: string }
-- CORRECT: visible to importing packages
export type Customer = { name: string, email: string }
```
This applies to record types AND ADTs:
```ailang
export type ProposalStatus = PendingApproval | AwaitingPayment | Approved
export type RequestedBy = Human | Agent(string)
```
### 4. Always import `Ok` and `Err` explicitly
They are NOT in the auto-imported prelude:
```ailang
import std/result (Ok, Err)
```
### 5. Package name is vendor/name format (exactly 2 segments)
```toml
[package]
name = "sunholo/firestore" # CORRECT
name = "firestore" # WRONG — single segment
name = "sunholo/billing/store" # WRONG — 3 segments
```
### 6. Use `module_prefix` for existing apps adopting packages
If your project uses `module myapp/...` but you want to publish as `sunholo/myapp`:
```toml
[package]
name = "sunholo/myapp"
module_prefix = "myapp"
[exports]
modules = ["myapp/services/api", "myapp/handlers/parse"]
```
Zero source changes needed — existing `module myapp/...` declarations work as-is.
### 7. Publishing rewrites path deps automatically
`ailang publish` automatically rewrites path deps (`{ path = "../firestore" }`) to registry version strings (`"0.1.0"`) in the tarball. Your local `ailang.toml` is restored after. You don't need to change deps manually before publishing.
**Publish in dependency order**: packages with no deps first, then packages that depend on already-published packages.
## ailang.toml Reference
See [resources/manifest_reference.md](resources/manifest_reference.md) for full field documentation.
```toml
[package]
name = "sunholo/billing_store"
version = "0.2.0"
edition = "1"
ailang = ">=0.9.5" # optional: minimum AILANG version
module_prefix = "myapp" # optional: for existing apps
description = "Firestore CRUD for billing records"
license = "Apache-2.0"
[exports]
modules = [
"sunholo/billing_store/customers_repo",
"sunholo/billing_store/subscriptions_repo"
]
[dependencies]
# Path deps (local development):
"sunholo/firestore" = { path = "../firestore" }
# Git deps (version pinned):
# "sunholo/firestore" = { git = "https://github.com/sunholo-data/ailang-packages", subdir = "packages/firestore", tag = "main" }
# Registry deps (published packages — use exact versions only, no ranges):
# "sunholo/firestore" = "0.1.0"
# Install latest: ailang install sunholo/firestore
[effects]
max = ["Net", "FS", "Env"] # effect ceiling — functions can't exceed this
[metadata]
tags = ["billing", "firestore"]
ai_summary = "Firestore CRUD for billing records"
[stability]
level = "experimental" # experimental | stable | frozen
[bin] # optional: commands `ailang install` shims onto PATH (~/.ailang/bin)
billing = "cli" # module sunholo/billing_store/cli, entry main, caps auto
# billing = { module = "cli", entry = "main", caps = "IO,Env", run_flags = ["--process-timeout", "5m"] }
```
### Shipping a command (`[bin]`, v0.40.1)
Never write a `scripts/` or `bin/` launcher that `cd`s into a checkout and `ailang run`s a
file — that is exactly what `[bin]` replaces. Declare the module; `ailang install` writes the
package's lock beside its cached manifest and a shim that runs it from any cwd.
```bash
ailang install --path . # developer loop: shim THIS checkout, no publish
ailang bin list # (= ailang pkg bin list) installed shims with package@version
ailang bin uninstall billing
```
The entry reads its arguments with `std/env` `getArgs()`; `ailang publish` refuses a bin
whose module is missing or whose entry is not exported.
### Lock File Portability
Registry and git lock entries resolve from the local cache (`~/.ailang/cache/`). Path dependencies are recorded relative to the depending `ailang.toml` (forward slashes), so a lock stays valid when the whole tree is cloned or moved — but only if the dependency is inside that tree (a sibling repo is not in a CI clone). `ailang lock --check` verifies the committed lock without writing; it flags a lock from an older ailang that still names an absolute path, and `ailang lock` rewrites it relative.
**Docker workflow:**
```dockerfile
COPY ailang.toml ailang.lock .
RUN ailang install sunholo/auth # Populates cache from lock file versions
```
**Key facts:**
- Lock file stores: name, version, content hash, source type, git URL/rev
- Registry/git entries do not need absolute cache paths; local path entries are workspace-specific
- `ailang install` populates the cache; `ailang lock` resolves + downloads
- Old lock files with stored paths still work (backward compatible)
### Version Conflict Detection
The resolver enforces **flat dependencies** — one version per package name. If a transitive dependency requires a different version than the root manifest pins, `ailang lock` fails with a structured error:
```
version conflict: sunholo/firestore
root requires: 0.2.0
already resolved: 0.1.0
transitive requires: 0.1.0 (via sunholo/billing_store)
resolution aborted
suggestion:
- republish sunholo/billing_store against sunholo/firestore@0.2.0
- or change root dependency to sunholo/firestore@0.1.0 explicitly
```
**Resolution rules:**
- Direct dependencies in the root `ailang.toml` are **authoritative**
- Transitive dependencies must match the direct pin exactly
- If they conflict, the resolver fails (never silently downgrades)
- Same version from multiple sources is fine (silently deduplicated)
**How to fix version conflicts:**
1. Republish the transitive package against the version you need
2. Or change your root `ailang.toml` to match the transitive version
3. The error message tells you exactly which package introduced the conflict
## Common Error Solutions
See [resources/error_solutions.md](resources/error_solutions.md) for full troubleshooting guide.
| Error | Cause | Fix |
|-------|-------|-----|
| `version conflict: pkg` | Direct and transitive deps disagree on version | Republish transitive dep or change root pin (see error message) |
| `IMP010: symbol not exported` | Type missing `export` keyword | Add `export type Foo = ...` |
| `LDR001: module not found` | Missing dependency or wrong import path | Add dep to ailang.toml + `ailang lock` |
| `cannot unify type constructor X with TRecord` | Type alias not exported across packages | Add `export type` to the defining module |
| `package not found in ailang.lock` | Dependencies not resolved | Run `ailang lock` |
| `PAR_HYPHEN_IN_MODULE` | Hyphen in module path | Use underscores: `billing_store` not `billing-store` |
| `Key has already been defined` | Duplicate dep entry in ailang.toml | Remove duplicate, keep one format |
## Publishing Checklist
1. All modules pass: `ailang check --package .`
2. Dependencies are listed in `[dependencies]` (path deps OK — publish rewrites them)
3. Exported types have `export type`
4. `[exports].modules` lists all public modules
5. `[effects].max` includes all effects used
6. `AGENT.md` exists with usage guide
7. Native tests/properties have been executed with totals and skips reviewed; source inline tests run explicitly
8. Meaningful contracts and effect budgets reviewed; proof outcomes recorded separately
9. `ailang pkg quality --strict .` reports no missing evidence, or gaps are explicitly documented (do not claim the strict gate passed)
10. Publish in dependency order (leaf packages first)
`publish --dry-run` returns before remote registry validation. It is packaging evidence, not a test or proof gate.
## Registry Validator
The registry validator (`/version` endpoint shows deployed version):
- Runs `ailang check --package .` on uploaded tarballs
- Rewrites any remaining path deps to registry versions (safety net for older clients)
- Runs `ailang lock` to download deps from registry before checking
- Validates compilation, effect ceilings, and contracts
## Workflow
1. **Read** [resources/manifest_reference.md](resources/manifest_reference.md) for ailang.toml details
2. **Read** [resources/error_solutions.md](resources/error_solutions.md) when encountering errors
3. **Run** `scripts/validate_package.sh` after creating a package
4. **Follow** the critical rules above — they prevent the most common failures