Commit 7f06c771e05562d1f20e03e296606540c11a5e0e

Commits
[COMMIT BEGIN]
commit 7f06c771e05562d1f20e03e296606540c11a5e0e
Author: 0x4248 <[email protected]>
Date:   Fri Mar 6 14:05:10 2026 +0000

    npkg: init

diff --git a/npkg-testing/README.md b/npkg-testing/README.md
new file mode 100644
index 0000000..2ea743a
--- /dev/null
+++ b/npkg-testing/README.md
@@ -0,0 +1,43 @@
+# NPKG Testing Workspace
+
+Flat, dev-first workspace for package migration experiments.
+
+The package CLI is `./npkg`, with package build artifacts in `./npkg-build/`.
+Implementation modules live in `tools/npkg/*.py`.
+Code and package folders live directly here so development stays simple.
+
+## Category Layout
+
+- `bin/` - user-facing binaries
+- `sbin/` - admin/service binaries
+- `toolkits/` - toolkit code and utilities
+- `lib/public/` - public/installable libraries
+- `lib/private/` - personal/internal libraries
+- `lab/` - unstable prototypes
+- `systems/` - system/platform-specific things (configs, patches, scripts)
+
+## Demo Package
+
+`bin/hello_world` builds a C binary and packages it as `/bin/hello-world`.
+
+## Commands
+
+From repository root:
+
+```bash
+./npkg list
+./npkg installed
+./npkg build hello-world
+./npkg install hello-world
+./npkg install-prebuilt --file ./npkg-build/packages/hello-world-0.1.0.tar.gz
+./npkg uninstall hello-world
+```
+
+If `/opt/npkg` is not writable for your user, run install/uninstall with `sudo`.
+
+To run as `npkg ...` directly, symlink once:
+
+```bash
+mkdir -p ~/.local/bin
+ln -sf "$PWD/npkg" ~/.local/bin/npkg
+```
diff --git a/npkg-testing/lab/README.md b/npkg-testing/lab/README.md
new file mode 100644
index 0000000..23fe5f7
--- /dev/null
+++ b/npkg-testing/lab/README.md
@@ -0,0 +1,3 @@
+# lab
+
+Unstable and in-progress experiments.
diff --git a/npkg-testing/lib/private/README.md b/npkg-testing/lib/private/README.md
new file mode 100644
index 0000000..8c180b1
--- /dev/null
+++ b/npkg-testing/lib/private/README.md
@@ -0,0 +1,3 @@
+# private lib
+
+Internal/personal libraries not intended as public API.
diff --git a/npkg-testing/lib/public/README.md b/npkg-testing/lib/public/README.md
new file mode 100644
index 0000000..f2b8c0b
--- /dev/null
+++ b/npkg-testing/lib/public/README.md
@@ -0,0 +1,3 @@
+# public lib
+
+Installable/public-facing libraries.
diff --git a/npkg-testing/npkg b/npkg-testing/npkg
new file mode 100755
index 0000000..c8fedb9
--- /dev/null
+++ b/npkg-testing/npkg
@@ -0,0 +1,9 @@
+#!/usr/bin/env python3
+
+import sys
+
+from tools.npkg.cli import main
+
+
+if __name__ == "__main__":
+    raise SystemExit(main(sys.argv[1:]))
\ No newline at end of file
diff --git a/npkg-testing/npkg-build/README.md b/npkg-testing/npkg-build/README.md
new file mode 100644
index 0000000..a382c82
--- /dev/null
+++ b/npkg-testing/npkg-build/README.md
@@ -0,0 +1,89 @@
+# NPKG tools
+
+Package tooling lives here.
+
+Implementation modules are in `tools/npkg/*.py` and loaded by the root `./npkg` entrypoint.
+
+- `../npkg` - CLI entrypoint (`list`, `build`, `install`, `uninstall`)
+- `work/` - staging work dirs
+- `packages/` - built package archives
+
+## Quick start
+
+```bash
+./npkg list
+./npkg installed
+./npkg build hello-world
+./npkg install hello-world
+./npkg install-prebuilt --file ./npkg-build/packages/hello-world-0.1.0.tar.gz
+./npkg uninstall hello-world
+```
+
+Default install root is `/opt/npkg` and default prefix is `/` (so binaries land under `/opt/npkg/bin`, etc).
+If `/opt/npkg` is not writable for your user, run install/uninstall with `sudo`.
+
+## Package metadata
+
+Packages are discovered by scanning these directories for one metadata file per package directory:
+
+- `npkg.conf` (preferred)
+- `npkg.ini`
+- `npkg.toml` (compatibility)
+- `npkg.json` (legacy compatibility)
+
+If more than one metadata file exists in a package directory, `npkg` errors to avoid ambiguity.
+
+Scan roots:
+
+- `bin/`
+- `sbin/`
+- `toolkits/`
+- `lib/public/`
+- `lib/private/`
+- `lab/`
+- `systems/`
+
+Minimal `npkg.conf` example:
+
+```toml
+name = "hello-world"
+version = "0.1.0"
+description = "Tiny demo C package"
+
+[build]
+command = "make -C {package_dir} all"
+
+[stage]
+command = "make -C {package_dir} install DESTDIR={stage_dir} PREFIX={prefix}"
+
+[capabilities]
+installable = true
+```
+
+INI equivalent:
+
+```ini
+[package]
+name = hello-world
+version = 0.1.0
+description = Tiny demo C package
+
+[build]
+command = make -C {package_dir} all
+
+[stage]
+command = make -C {package_dir} install DESTDIR={stage_dir} PREFIX={prefix}
+
+[capabilities]
+installable = true
+```
+
+Notes:
+
+- Optional defaults:
+  - `name` defaults to folder name (with `_` converted to `-`)
+  - `version` defaults to `0.1.0`
+  - `description` defaults to empty
+  - `capabilities.installable` defaults to `true` if `stage.command` is set, else `false`
+- `build.command` remains optional.
+- `stage.command` is required only for installable packages.
diff --git a/npkg-testing/sbin/README.md b/npkg-testing/sbin/README.md
new file mode 100644
index 0000000..e31a12c
--- /dev/null
+++ b/npkg-testing/sbin/README.md
@@ -0,0 +1,3 @@
+# sbin
+
+Admin/service-oriented binaries for migration testing.
diff --git a/npkg-testing/toolkits/README.md b/npkg-testing/toolkits/README.md
new file mode 100644
index 0000000..74fb3f5
--- /dev/null
+++ b/npkg-testing/toolkits/README.md
@@ -0,0 +1,3 @@
+# toolkits
+
+Toolkit projects and shared utilities for migration testing.
diff --git a/npkg-testing/tools/__init__.py b/npkg-testing/tools/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/npkg-testing/tools/npkg/__init__.py b/npkg-testing/tools/npkg/__init__.py
new file mode 100644
index 0000000..ed32c05
--- /dev/null
+++ b/npkg-testing/tools/npkg/__init__.py
@@ -0,0 +1,3 @@
+from .cli import main
+
+__all__ = ["main"]
diff --git a/npkg-testing/tools/npkg/archive.py b/npkg-testing/tools/npkg/archive.py
new file mode 100644
index 0000000..12c4dc6
--- /dev/null
+++ b/npkg-testing/tools/npkg/archive.py
@@ -0,0 +1,89 @@
+import re
+import shutil
+import subprocess
+import tarfile
+from pathlib import Path
+from typing import Dict, List, Optional
+
+from .console import info, ok
+from .paths import package_archive_path, package_stage_dir, workspace_root
+from .types import Package
+
+
+def command_context(pkg: Package, stage_dir: Optional[Path] = None) -> Dict[str, str]:
+    context = {
+        "workspace_root": str(workspace_root()),
+        "npkg_root": str(workspace_root()),
+        "npkg_build_root": str(workspace_root() / "npkg-build"),
+        "package_dir": str(pkg.package_dir),
+    }
+    if stage_dir is not None:
+        context["stage_dir"] = str(stage_dir)
+    return context
+
+
+def render_command(template: str, context: Dict[str, str]) -> str:
+    return template.format(**context)
+
+
+def run_shell(command: str, cwd: Path) -> None:
+    result = subprocess.run(command, cwd=str(cwd), shell=True)
+    if result.returncode != 0:
+        raise RuntimeError(f"Command failed with exit code {result.returncode}: {command}")
+
+
+def ensure_package_archive(pkg: Package, prefix: str) -> Path:
+    if not pkg.installable:
+        raise RuntimeError(f"Package '{pkg.name}' is not installable")
+    if not pkg.stage_command:
+        raise RuntimeError(f"Package '{pkg.name}' does not define stage.command")
+
+    stage_dir = package_stage_dir(pkg)
+    archive_path = package_archive_path(pkg)
+
+    shutil.rmtree(stage_dir, ignore_errors=True)
+    stage_dir.mkdir(parents=True, exist_ok=True)
+
+    context = command_context(pkg, stage_dir=stage_dir)
+    context["prefix"] = prefix
+    stage_command = render_command(pkg.stage_command, context)
+
+    info(f"staging {pkg.name} with: {stage_command}")
+    run_shell(stage_command, cwd=workspace_root())
+
+    archive_path.parent.mkdir(parents=True, exist_ok=True)
+    with tarfile.open(archive_path, "w:gz") as tar:
+        for item in sorted(stage_dir.iterdir()):
+            tar.add(item, arcname=item.name)
+
+    ok(f"packaged {pkg.name} -> {archive_path}")
+    return archive_path
+
+
+def extract_archive_into_root(archive_path: Path, install_root: Path) -> List[str]:
+    try:
+        with tarfile.open(archive_path, "r:gz") as tar:
+            member_names = [member.name for member in tar.getmembers() if member.name and member.name != "."]
+            try:
+                tar.extractall(path=install_root, filter="data")
+            except TypeError:
+                tar.extractall(path=install_root)
+    except (tarfile.TarError, OSError) as error:
+        raise RuntimeError(f"failed to install archive: {error}") from error
+    return member_names
+
+
+def infer_package_from_archive(archive_path: Path) -> tuple[str, str]:
+    base = archive_path.name
+    if base.endswith(".tar.gz"):
+        base = base[:-7]
+    elif base.endswith(".tgz"):
+        base = base[:-4]
+    else:
+        base = archive_path.stem
+
+    match = re.match(r"^(?P<name>.+)-(?P<version>\d+\.\d+\.\d+.*)$", base)
+    if match:
+        return match.group("name"), match.group("version")
+
+    return base, "prebuilt"
diff --git a/npkg-testing/tools/npkg/cli.py b/npkg-testing/tools/npkg/cli.py
new file mode 100644
index 0000000..f472665
--- /dev/null
+++ b/npkg-testing/tools/npkg/cli.py
@@ -0,0 +1,97 @@
+import argparse
+
+from .commands import (
+    cmd_build,
+    cmd_install,
+    cmd_install_prebuilt,
+    cmd_installed,
+    cmd_list,
+    cmd_uninstall,
+)
+from .console import fail
+
+
+def build_parser() -> argparse.ArgumentParser:
+    parser = argparse.ArgumentParser(
+        prog="npkg",
+        description="Nexus package helper",
+        formatter_class=argparse.RawDescriptionHelpFormatter,
+        epilog=(
+            "Examples:\n"
+            "  npkg list\n"
+            "  npkg installed\n"
+            "  npkg build hello-world\n"
+            "  npkg install hello-world\n"
+            "  npkg install-prebuilt --file ./npkg-build/packages/hello-world-0.1.0.tar.gz\n"
+            "  npkg uninstall hello-world"
+        ),
+    )
+
+    sub = parser.add_subparsers(dest="command", required=True)
+
+    list_parser = sub.add_parser("list", help="List available packages")
+    list_parser.set_defaults(func=cmd_list)
+
+    installed_parser = sub.add_parser("installed", help="List installed packages from manifest database")
+    installed_parser.add_argument(
+        "--root",
+        default="/opt/npkg",
+        help="Installation root directory (default: /opt/npkg)",
+    )
+    installed_parser.set_defaults(func=cmd_installed)
+
+    build_parser = sub.add_parser("build", help="Build a package")
+    build_parser.add_argument("package", help="Package name or package directory path")
+    build_parser.set_defaults(func=cmd_build)
+
+    install_parser = sub.add_parser("install", help="Install a package")
+    install_parser.add_argument("package", help="Package name or package directory path")
+    install_parser.add_argument(
+        "--root",
+        default="/opt/npkg",
+        help="Installation root directory (default: /opt/npkg)",
+    )
+    install_parser.add_argument(
+        "--prefix",
+        default="/",
+        help="Prefix passed to package stage command (default: /)",
+    )
+    install_parser.set_defaults(func=cmd_install)
+
+    install_prebuilt_parser = sub.add_parser("install-prebuilt", help="Install from a prebuilt tarball")
+    install_prebuilt_parser.add_argument(
+        "--file",
+        required=True,
+        help="Path to .tar.gz or .tgz package archive",
+    )
+    install_prebuilt_parser.add_argument(
+        "--package",
+        help="Package name override (defaults to name inferred from archive filename)",
+    )
+    install_prebuilt_parser.add_argument(
+        "--root",
+        default="/opt/npkg",
+        help="Installation root directory (default: /opt/npkg)",
+    )
+    install_prebuilt_parser.set_defaults(func=cmd_install_prebuilt)
+
+    uninstall_parser = sub.add_parser("uninstall", help="Uninstall a package")
+    uninstall_parser.add_argument("package", help="Package name")
+    uninstall_parser.add_argument(
+        "--root",
+        default="/opt/npkg",
+        help="Installation root directory (default: /opt/npkg)",
+    )
+    uninstall_parser.set_defaults(func=cmd_uninstall)
+
+    return parser
+
+
+def main(argv: list[str] | None = None) -> int:
+    parser = build_parser()
+    args = parser.parse_args(argv)
+    try:
+        return int(args.func(args))
+    except ValueError as error:
+        fail(str(error))
+        return 2
diff --git a/npkg-testing/tools/npkg/commands.py b/npkg-testing/tools/npkg/commands.py
new file mode 100644
index 0000000..dd09ed2
--- /dev/null
+++ b/npkg-testing/tools/npkg/commands.py
@@ -0,0 +1,171 @@
+from pathlib import Path
+
+from .archive import command_context, ensure_package_archive, extract_archive_into_root, infer_package_from_archive, render_command, run_shell
+from .console import fail, info, ok, style, warn
+from .install_db import load_installed_rows, uninstall_from_manifest, write_install_manifest, write_prebuilt_manifest
+from .metadata import discover_packages, select_package
+from .paths import workspace_root
+
+
+def cmd_list(_args) -> int:
+    packages = discover_packages()
+    print(style("NPKG packages", bold=True))
+    if not packages:
+        warn("no packages found")
+        return 0
+
+    for pkg in packages.values():
+        flags = []
+        flags.append("build" if pkg.build_command else "no-build")
+        if pkg.installable and pkg.stage_command:
+            flags.append("install")
+        elif pkg.installable and not pkg.stage_command:
+            flags.append("no-stage")
+        else:
+            flags.append("build-only")
+
+        rel_dir = pkg.package_dir.relative_to(workspace_root())
+        print(
+            f"  {style(pkg.name, bold=True)} {pkg.version}  "
+            f"[{', '.join(flags)}]  {rel_dir}"
+        )
+        if pkg.description:
+            print(f"    {pkg.description}")
+
+    return 0
+
+
+def cmd_build(args) -> int:
+    packages = discover_packages()
+    try:
+        pkg = select_package(packages, args.package)
+    except KeyError:
+        fail(f"package not found: {args.package}")
+        return 2
+
+    if not pkg.build_command:
+        fail(f"package '{pkg.name}' does not define build.command")
+        return 2
+
+    command = render_command(pkg.build_command, command_context(pkg))
+    info(f"building {pkg.name} with: {command}")
+    try:
+        run_shell(command, cwd=workspace_root())
+    except RuntimeError as error:
+        fail(str(error))
+        return 1
+
+    ok(f"built {pkg.name}")
+    return 0
+
+
+def cmd_install(args) -> int:
+    packages = discover_packages()
+    try:
+        pkg = select_package(packages, args.package)
+    except KeyError:
+        fail(f"package not found: {args.package}")
+        return 2
+
+    install_root = Path(args.root).expanduser().resolve()
+    prefix = args.prefix
+
+    try:
+        archive_path = ensure_package_archive(pkg, prefix=prefix)
+    except RuntimeError as error:
+        fail(str(error))
+        return 2
+
+    install_root.mkdir(parents=True, exist_ok=True)
+    info(f"installing {pkg.name} into {install_root}")
+    try:
+        member_names = extract_archive_into_root(archive_path, install_root)
+    except RuntimeError as error:
+        fail(str(error))
+        return 1
+
+    write_install_manifest(pkg, install_root, member_names)
+
+    ok(f"installed {pkg.name} -> {install_root}")
+    return 0
+
+
+def cmd_install_prebuilt(args) -> int:
+    archive_path = Path(args.file).expanduser().resolve()
+    if not archive_path.exists() or not archive_path.is_file():
+        fail(f"archive not found: {archive_path}")
+        return 2
+
+    install_root = Path(args.root).expanduser().resolve()
+    install_root.mkdir(parents=True, exist_ok=True)
+
+    inferred_name, inferred_version = infer_package_from_archive(archive_path)
+    package_name = (args.package or inferred_name).strip()
+    package_version = inferred_version
+
+    if not package_name:
+        fail("unable to determine package name; pass --package")
+        return 2
+
+    info(f"installing prebuilt {package_name} from {archive_path} into {install_root}")
+    try:
+        member_names = extract_archive_into_root(archive_path, install_root)
+    except RuntimeError as error:
+        fail(str(error))
+        return 1
+
+    write_prebuilt_manifest(
+        package_name=package_name,
+        version=package_version,
+        install_root=install_root,
+        members=member_names,
+        source_archive=archive_path,
+    )
+
+    ok(f"installed prebuilt {package_name} -> {install_root}")
+    return 0
+
+
+def cmd_uninstall(args) -> int:
+    packages = discover_packages()
+    pkg_name = args.package
+    if pkg_name in packages:
+        pkg_name = packages[pkg_name].name
+    else:
+        try:
+            pkg_name = select_package(packages, args.package).name
+        except KeyError:
+            pkg_name = args.package
+
+    install_root = Path(args.root).expanduser().resolve()
+    info(f"uninstalling {pkg_name} from {install_root}")
+    try:
+        uninstall_from_manifest(pkg_name, install_root)
+    except RuntimeError as error:
+        fail(str(error))
+        return 2
+
+    ok(f"uninstalled {pkg_name} from {install_root}")
+    return 0
+
+
+def cmd_installed(args) -> int:
+    install_root = Path(args.root).expanduser().resolve()
+    rows = load_installed_rows(install_root)
+
+    print(style(f"Installed packages in {install_root}", bold=True))
+    if not rows:
+        warn("no installed packages found")
+        return 0
+
+    for row in rows:
+        if row.get("error"):
+            warn(f"skipping invalid manifest {row['manifest'].name}: {row['error']}")
+            continue
+
+        print(
+            f"  {style(row['package'], bold=True)} {row['version']}  "
+            f"({row['path_count']} paths)"
+        )
+
+    return 0
diff --git a/npkg-testing/tools/npkg/console.py b/npkg-testing/tools/npkg/console.py
new file mode 100644
index 0000000..d76d3b8
--- /dev/null
+++ b/npkg-testing/tools/npkg/console.py
@@ -0,0 +1,41 @@
+import os
+import sys
+
+
+RESET = "\033[0m"
+BOLD = "\033[1m"
+GREEN = "\033[32m"
+YELLOW = "\033[33m"
+RED = "\033[31m"
+BLUE = "\033[34m"
+
+
+def use_color() -> bool:
+    return sys.stdout.isatty() and os.environ.get("NO_COLOR") is None
+
+
+def style(text: str, color: str = "", bold: bool = False) -> str:
+    if not use_color():
+        return text
+    prefix = ""
+    if bold:
+        prefix += BOLD
+    if color:
+        prefix += color
+    return f"{prefix}{text}{RESET}"
+
+
+def info(message: str) -> None:
+    print(f"[{style('>', BLUE)}] {message}")
+
+
+def ok(message: str) -> None:
+    print(f"[{style('+', GREEN)}] {message}")
+
+
+def warn(message: str) -> None:
+    print(f"[{style('!', YELLOW)}] {message}")
+
+
+def fail(message: str) -> None:
+    print(f"[{style('x', RED)}] {message}", file=sys.stderr)
diff --git a/npkg-testing/tools/npkg/install_db.py b/npkg-testing/tools/npkg/install_db.py
new file mode 100644
index 0000000..e9be84b
--- /dev/null
+++ b/npkg-testing/tools/npkg/install_db.py
@@ -0,0 +1,126 @@
+import json
+from pathlib import Path
+from typing import Any, Dict, List
+
+from .paths import list_manifest_paths, manifest_root, package_manifest_path
+from .types import Package
+
+
+def write_install_manifest(pkg: Package, install_root: Path, members: List[str]) -> None:
+    db_dir = manifest_root(install_root)
+    db_dir.mkdir(parents=True, exist_ok=True)
+    manifest = {
+        "package": pkg.name,
+        "version": pkg.version,
+        "install_root": str(install_root),
+        "paths": members,
+    }
+    manifest_path = package_manifest_path(pkg.name, install_root)
+    with manifest_path.open("w", encoding="utf-8") as handle:
+        json.dump(manifest, handle, indent=2)
+
+
+def write_prebuilt_manifest(
+    package_name: str,
+    version: str,
+    install_root: Path,
+    members: List[str],
+    source_archive: Path,
+) -> None:
+    db_dir = manifest_root(install_root)
+    db_dir.mkdir(parents=True, exist_ok=True)
+    manifest = {
+        "package": package_name,
+        "version": version,
+        "install_root": str(install_root),
+        "source_archive": str(source_archive),
+        "paths": members,
+    }
+    manifest_path = package_manifest_path(package_name, install_root)
+    with manifest_path.open("w", encoding="utf-8") as handle:
+        json.dump(manifest, handle, indent=2)
+
+
+def read_install_manifest(pkg_name: str, install_root: Path) -> Dict[str, Any]:
+    manifest_path = package_manifest_path(pkg_name, install_root)
+    if not manifest_path.exists():
+        raise RuntimeError(f"package '{pkg_name}' is not installed in {install_root}")
+    with manifest_path.open("r", encoding="utf-8") as handle:
+        data = json.load(handle)
+    if not isinstance(data, dict):
+        raise RuntimeError(f"invalid manifest for package '{pkg_name}'")
+    return data
+
+
+def uninstall_from_manifest(pkg_name: str, install_root: Path) -> None:
+    data = read_install_manifest(pkg_name, install_root)
+    raw_paths = data.get("paths", [])
+    if not isinstance(raw_paths, list):
+        raise RuntimeError(f"invalid manifest path list for package '{pkg_name}'")
+
+    unique_paths = []
+    seen = set()
+    for item in raw_paths:
+        if not isinstance(item, str):
+            continue
+        normalized = item.strip().lstrip("/")
+        if not normalized or normalized in seen:
+            continue
+        seen.add(normalized)
+        unique_paths.append(normalized)
+
+    for rel_path in sorted(unique_paths, key=lambda value: (value.count("/"), len(value)), reverse=True):
+        target = install_root / rel_path
+        if target.is_symlink() or target.is_file():
+            target.unlink(missing_ok=True)
+        elif target.is_dir():
+            try:
+                target.rmdir()
+            except OSError:
+                pass
+
+    for rel_path in sorted(unique_paths, key=lambda value: value.count("/"), reverse=True):
+        current = (install_root / rel_path).parent
+        while current != install_root and current.exists():
+            try:
+                current.rmdir()
+            except OSError:
+                break
+            current = current.parent
+
+    manifest_path = package_manifest_path(pkg_name, install_root)
+    manifest_path.unlink(missing_ok=True)
+
+    db_dir = manifest_root(install_root)
+    try:
+        db_dir.rmdir()
+    except OSError:
+        pass
+
+
+def load_installed_rows(install_root: Path) -> List[Dict[str, Any]]:
+    rows: List[Dict[str, Any]] = []
+    for manifest_path in list_manifest_paths(install_root):
+        try:
+            with manifest_path.open("r", encoding="utf-8") as handle:
+                data = json.load(handle)
+        except (OSError, json.JSONDecodeError) as error:
+            rows.append(
+                {
+                    "manifest": manifest_path,
+                    "error": str(error),
+                }
+            )
+            continue
+
+        rows.append(
+            {
+                "manifest": manifest_path,
+                "package": str(data.get("package") or manifest_path.stem),
+                "version": str(data.get("version") or "unknown"),
+                "path_count": len(data.get("paths", [])) if isinstance(data.get("paths", []), list) else 0,
+                "error": None,
+            }
+        )
+
+    return rows
diff --git a/npkg-testing/tools/npkg/metadata.py b/npkg-testing/tools/npkg/metadata.py
new file mode 100644
index 0000000..f5cc75b
--- /dev/null
+++ b/npkg-testing/tools/npkg/metadata.py
@@ -0,0 +1,205 @@
+import configparser
+import json
+import os
+from pathlib import Path
+from typing import Any, Dict, Optional
+
+try:
+    import tomllib
+except ModuleNotFoundError:
+    tomllib = None
+
+from .paths import workspace_root
+from .types import Package
+
+
+def normalize_command(raw: Optional[str]) -> Optional[str]:
+    if raw is None:
+        return None
+    command = raw.strip()
+    if not command:
+        return None
+    return command
+
+
+def as_dict(value: Any) -> Dict[str, Any]:
+    return value if isinstance(value, dict) else {}
+
+
+def parse_bool(value: Any, default: bool) -> bool:
+    if value is None:
+        return default
+    if isinstance(value, bool):
+        return value
+    if isinstance(value, (int, float)):
+        return bool(value)
+    raw = str(value).strip().lower()
+    if raw in {"1", "true", "yes", "on"}:
+        return True
+    if raw in {"0", "false", "no", "off"}:
+        return False
+    return default
+
+
+def load_json_package(meta_path: Path) -> Dict[str, Any]:
+    with meta_path.open("r", encoding="utf-8") as handle:
+        return json.load(handle)
+
+
+def load_toml_package(meta_path: Path) -> Dict[str, Any]:
+    if tomllib is None:
+        raise ValueError("TOML metadata requires Python 3.11+ (tomllib not available)")
+    with meta_path.open("rb") as handle:
+        parsed = tomllib.load(handle)
+    if not isinstance(parsed, dict):
+        raise ValueError(f"Invalid metadata in {meta_path}: expected top-level table")
+    return parsed
+
+
+def load_ini_package(meta_path: Path) -> Dict[str, Any]:
+    parser = configparser.ConfigParser()
+    parser.optionxform = str
+    read_ok = parser.read(meta_path, encoding="utf-8")
+    if not read_ok:
+        raise ValueError(f"Unable to read metadata: {meta_path}")
+
+    package: Dict[str, Any] = {}
+    build: Dict[str, Any] = {}
+    stage: Dict[str, Any] = {}
+    capabilities: Dict[str, Any] = {}
+
+    if parser.has_section("package"):
+        section = parser["package"]
+        package["name"] = section.get("name")
+        package["version"] = section.get("version")
+        package["description"] = section.get("description")
+
+    if parser.has_section("build"):
+        build["command"] = parser["build"].get("command")
+
+    if parser.has_section("stage"):
+        stage["command"] = parser["stage"].get("command")
+
+    if parser.has_section("capabilities"):
+        capabilities["installable"] = parser["capabilities"].get("installable")
+
+    package["build"] = build
+    package["stage"] = stage
+    package["capabilities"] = capabilities
+    return package
+
+
+def load_raw_package(meta_path: Path) -> Dict[str, Any]:
+    name = meta_path.name.lower()
+    suffix = meta_path.suffix.lower()
+    if name == "npkg.conf":
+        try:
+            data = load_toml_package(meta_path)
+        except ValueError:
+            data = load_ini_package(meta_path)
+    elif suffix == ".json":
+        data = load_json_package(meta_path)
+    elif suffix == ".toml":
+        data = load_toml_package(meta_path)
+    elif suffix == ".ini":
+        data = load_ini_package(meta_path)
+    else:
+        raise ValueError(f"Unsupported metadata format: {meta_path.name}")
+
+    if not isinstance(data, dict):
+        raise ValueError(f"Invalid metadata in {meta_path}: expected object/table")
+    return data
+
+
+def load_package(meta_path: Path) -> Package:
+    data = load_raw_package(meta_path)
+
+    default_name = meta_path.parent.name.replace("_", "-")
+    name = str(data.get("name") or default_name).strip()
+    version = str(data.get("version") or "0.1.0").strip()
+    description = str(data.get("description") or "").strip()
+    build = as_dict(data.get("build", {}))
+    stage = as_dict(data.get("stage", {}))
+    capabilities = as_dict(data.get("capabilities", {}))
+
+    if not name or not version:
+        raise ValueError(f"Invalid metadata in {meta_path}: missing name/version")
+
+    build_command = normalize_command(build.get("command"))
+    stage_command = normalize_command(stage.get("command"))
+    installable_default = stage_command is not None
+    installable = parse_bool(capabilities.get("installable"), default=installable_default)
+
+    return Package(
+        name=name,
+        version=version,
+        description=description,
+        package_dir=meta_path.parent,
+        build_command=build_command,
+        stage_command=stage_command,
+        installable=installable,
+    )
+
+
+def metadata_file_in_dir(package_dir: Path) -> Optional[Path]:
+    candidates = [
+        package_dir / "npkg.conf",
+        package_dir / "npkg.toml",
+        package_dir / "npkg.ini",
+        package_dir / "npkg.json",
+    ]
+    found = [path for path in candidates if path.exists()]
+    if len(found) > 1:
+        names = ", ".join(path.name for path in found)
+        raise ValueError(f"Multiple metadata files in {package_dir}: {names}")
+    return found[0] if found else None
+
+
+def discover_packages() -> Dict[str, Package]:
+    root = workspace_root()
+    packages: Dict[str, Package] = {}
+    search_roots = [
+        root / "bin",
+        root / "sbin",
+        root / "toolkits",
+        root / "lib" / "public",
+        root / "lib" / "private",
+        root / "lab",
+        root / "systems",
+    ]
+
+    for top in search_roots:
+        if not top.exists():
+            continue
+        for dirpath, _, filenames in os.walk(top):
+            filename_set = set(filenames)
+            if not ({"npkg.conf", "npkg.toml", "npkg.ini", "npkg.json"} & filename_set):
+                continue
+            package_dir = Path(dirpath)
+            meta = metadata_file_in_dir(package_dir)
+            if meta is None:
+                continue
+            package = load_package(meta)
+            if package.name in packages:
+                first = packages[package.name].package_dir
+                raise ValueError(
+                    f"Duplicate package name '{package.name}' in {first} and {package.package_dir}"
+                )
+            packages[package.name] = package
+
+    return dict(sorted(packages.items(), key=lambda item: item[0]))
+
+
+def select_package(packages: Dict[str, Package], selector: str) -> Package:
+    if selector in packages:
+        return packages[selector]
+
+    root = workspace_root()
+    normalized = selector.strip().strip("/")
+    if normalized:
+        selector_path = (root / normalized).resolve()
+        for pkg in packages.values():
+            if pkg.package_dir.resolve() == selector_path:
+                return pkg
+
+    raise KeyError(selector)
diff --git a/npkg-testing/tools/npkg/paths.py b/npkg-testing/tools/npkg/paths.py
new file mode 100644
index 0000000..3029adf
--- /dev/null
+++ b/npkg-testing/tools/npkg/paths.py
@@ -0,0 +1,39 @@
+from pathlib import Path
+from typing import List
+
+from .types import Package
+
+
+def workspace_root() -> Path:
+    return Path(__file__).resolve().parents[2]
+
+
+def npkg_build_root() -> Path:
+    return workspace_root() / "npkg-build"
+
+
+def out_root() -> Path:
+    return npkg_build_root()
+
+
+def package_stage_dir(pkg: Package) -> Path:
+    return out_root() / "work" / pkg.name / "stage"
+
+
+def package_archive_path(pkg: Package) -> Path:
+    return out_root() / "packages" / f"{pkg.name}-{pkg.version}.tar.gz"
+
+
+def manifest_root(install_root: Path) -> Path:
+    return install_root / ".npkg-db"
+
+
+def package_manifest_path(pkg_name: str, install_root: Path) -> Path:
+    return manifest_root(install_root) / f"{pkg_name}.json"
+
+
+def list_manifest_paths(install_root: Path) -> List[Path]:
+    db_dir = manifest_root(install_root)
+    if not db_dir.exists() or not db_dir.is_dir():
+        return []
+    return sorted(db_dir.glob("*.json"))
diff --git a/npkg-testing/tools/npkg/types.py b/npkg-testing/tools/npkg/types.py
new file mode 100644
index 0000000..3d31325
--- /dev/null
+++ b/npkg-testing/tools/npkg/types.py
@@ -0,0 +1,14 @@
+from dataclasses import dataclass
+from pathlib import Path
+from typing import Optional
+
+
+@dataclass
+class Package:
+    name: str
+    version: str
+    description: str
+    package_dir: Path
+    build_command: Optional[str]
+    stage_command: Optional[str]
+    installable: bool
[COMMIT END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.