# Packages A Deft **package** is a directory of modules with a `package.dft` manifest. Packages are the unit of distribution: install via `pkg/install`, reference by `owner/name`, import from any module. ## Package Identity Every package has a canonical **`owner/name`** id (e.g. `deft/editor`). Owners are globally unique on the registry; `deft` is reserved for official packages. The id is passed as a single string to every registry operation:
 [pkg/install "deft/editor"]
[pkg/info    "deft/editor"]
[pkg/uninstall "deft/editor"] 
## Importing Package Modules The `owner/name` id is also the import path prefix. Packages under a `:pkgs` search root (or installed by `pkg/install`) are mounted automatically as `owner/name`, so modules import without any configuration:
 import "deft/ui/components/button" as button 
Pin an exact version with `@version` after the name:
 import "deft/ui@0.1.0/components/button" as button 
- Unpinned `owner/name/...` resolves through the `:pkgs` roots in listed order — the first root providing the package wins. For installed packages the version comes from the `latest` pointer written by `pkg/install`, else the highest installed semver. - `owner/name@latest/...` is an explicit alias for unpinned. - A pin that matches a dev checkout's manifest version resolves to the dev tree (same root-order rules); otherwise it matches an installed version directory. - A missing pin errors with the list of available versions; a bare package prefix (e.g. `ui/...`) errors with a `did you mean "owner/name/..."?` hint. Dev checkouts, installed trees, and the legacy versioned layouts are all honoured — the difference between "working on a package" and "using a package" is only which root provides it, not the import syntax. ## The Manifest (`package.dft`) The manifest declares the package's identity, version, dependencies, and entry point:
 def manifest %Package{
    :owner       "alice"
    :name        "math-lib"
    :version     "1.0.0"
    :description "Personal math helpers"
    :entry       "src/main.dft"
    :deps @{
        %Dep{ :owner "deft" :name "stdext" :version "0.2.0" }
    |
    }
    :capabilities %PackageCapabilities{
        :ffi false
        :tui false
    |
    }
} 
`[pkg/read-manifest "path/to/dir"]` reads and validates a manifest, returning `%Package{ ... }` or `%Err{ ... }`. ## `pkg/*` Stdlib functions | Function | Returns | Purpose | |---|---|---| | `[pkg/set-registry $url]` | nil | Set registry URL (nil resets to local) | | `[pkg/get-registry]` | url or nil | Current registry | | `[pkg/install "owner/name" ?version]` | summary map or `%Err` | Install | | `[pkg/install-bytes "owner/name" $ver $bytes]` | summary map | Install pre-fetched tarball | | `[pkg/uninstall "owner/name"]` | bool or `%Err` | Uninstall | | `[pkg/list]` | list | Packages across all search roots | | `[pkg/list-paths]` | list of strings | Search roots | | `[pkg/available]` | list | Packages in the current registry | | `[pkg/info "owner/name" ?version]` | map | Package detail | | `[pkg/fetch "owner/name" ?version]` | bytes or Future | Download tarball | | `[pkg/read-manifest $dir]` | `%Package` or `%Err` | Read manifest | | `[pkg/mount $export-path $dir]` | nil | Register an import mount | ## Install Locations Installs always target the first search root (canonical: `.deft/packages/`), producing the owner-scoped versioned layout: ``` .deft/packages////package.dft .deft/packages////src/... ``` `pkg/install` also writes a `latest` text pointer beside the version directories (`.deft/packages///latest`) so unpinned `owner/name` imports have a defined target. ## Search Paths At startup every `:pkgs` root is scanned and each package found is auto-mounted as `owner/name` (plus `owner/name@version` pins and the `@latest` alias). Roots are scanned in listed order — the first root providing a package wins, so a dev tree listed before `.deft/packages/` shadows the installed copies. Explicit prelude `:mounts` entries always win over the auto-scan. Use `[pkg/list-paths]` to see the active search roots:
 [pkg/list-paths]
# => @{ ".deft/packages" } 
All on-disk layouts are honoured: - Flat (dev): `//package.dft` - Legacy versioned: `///package.dft` - Owner-scoped dev: `///package.dft` - Owner-scoped installed: `////package.dft` ## Registries Two registry transports: - **`dir://`** (default) — tarballs live under `virt-pkg/packages///.tar.gz`. A `latest` symlink or text file is honoured. Good for local development and airgapped environments. - **`http(s)://`** — tarballs fetched from `/packages///.tar.gz`. Set the URL with `[pkg/set-registry $url]` or the `--url` CLI flag. The `latest` file is honoured.
 pkg/set-registry "https://packages.example.com"
echo [pkg/get-registry]
# => https://packages.example.com

pkg/set-registry nil                           # reset to local virt-pkg 
The active registry URL is persisted in `prelude.dft`'s `:registry` field, so subsequent `deft` invocations pick it up automatically. ## Installing a Package
 def result [pkg/install "deft/editor"]
# => %{ :owner "deft" :name "editor" :version "1.5.0" :path ".deft/packages/deft/editor/1.5.0" }

def specific [pkg/install "deft/editor" "1.4.0"] 
`pkg/install` is **synchronous** — it blocks until the fetch and extract complete. Failures return `%Err{ :message ... }`. ### Manual fetch + install If you've already fetched the tarball bytes yourself (e.g. through a proxy), use `pkg/install-bytes`:
 set bytes [my-fetch "https://.../editor-1.5.0.tar.gz"]
pkg/install-bytes "deft/editor" "1.5.0" $bytes 
## Mounting a Package Manually Package auto-discovery covers everything under the `:pkgs` roots. `[pkg/mount $name $dir]` is the escape hatch for directories outside them (or for pointing a name at a specific checkout):
 pkg/mount "alice/mylib" "/home/alice/dev/mylib"
import "alice/mylib/helpers" as helpers 
Mount names may be multi-segment (`alice/mylib`) — imports resolve the longest matching mount prefix first. ## Creating a Package 1. Lay out the directory: ``` my-package/ ├── package.dft └── src/ ├── main.dft └── helpers.dft ``` 2. Write the manifest (`package.dft`):
    def manifest %Package{
       :owner       "alice"
       :name        "my-package"
       :version     "0.1.0"
       :description "An example package."
       :entry       "src/main.dft"
       :deps @{}
   |
   } 
3. (Optional) Test it locally by adding the parent directory to search paths and importing:
    pkg/mount "alice/my-package" "/path/to/my-package"
   import "alice/my-package/src/main" as mp 
4. Publish to your registry (tarball the directory; upload to your HTTP registry or place under `virt-pkg/packages///`). ## Capabilities A package can declare capabilities it needs (FFI, TUI, etc.) in the manifest:
 :capabilities %PackageCapabilities{
    :ffi true
    :tui false
|
} 
The runtime uses these to surface compatibility warnings when a package is loaded into a runtime missing a required capability. ## Quick Reference | Form | Purpose | |---|---| | `[pkg/install "owner/name" ?ver]` | Install | | `[pkg/uninstall "owner/name"]` | Uninstall | | `[pkg/list]` | List installed | | `[pkg/available]` | List in registry | | `[pkg/info "owner/name" ?ver]` | Show detail | | `[pkg/set-registry $url]` | Switch registry | | `[pkg/fetch "owner/name" ?ver]` | Download tarball | | `[pkg/mount $export-path $dir]` | Register a mount | | `[pkg/read-manifest $dir]` | Read a `package.dft` |