# Extension Development API\n\nThis document provides comprehensive guidance for developing extensions for provisioning, including providers, task services, and cluster configurations.\n\n## Overview\n\nProvisioning supports three types of extensions:\n\n1. **Providers**: Cloud infrastructure providers (AWS, UpCloud, Local, etc.)\n2. **Task Services**: Infrastructure components (Kubernetes, Cilium, Containerd, etc.)\n3. **Clusters**: Complete deployment configurations (BuildKit, CI/CD, etc.)\n\nAll extensions follow a standardized structure and API for seamless integration.\n\n## Extension Structure\n\n### Standard Directory Layout\n\n```\nextension-name/\n├── manifest.toml # Extension metadata\n├── schemas/ # Nickel configuration files\n│ ├── main.ncl # Main schema\n│ ├── settings.ncl # Settings schema\n│ ├── version.ncl # Version configuration\n│ └── contracts.ncl # Contract definitions\n├── nulib/ # Nushell library modules\n│ ├── mod.nu # Main module\n│ ├── create.nu # Creation operations\n│ ├── delete.nu # Deletion operations\n│ └── utils.nu # Utility functions\n├── templates/ # Jinja2 templates\n│ ├── config.j2 # Configuration templates\n│ └── scripts/ # Script templates\n├── generate/ # Code generation scripts\n│ └── generate.nu # Generation commands\n├── README.md # Extension documentation\n└── metadata.toml # Extension metadata\n```\n\n## Provider Extension API\n\n### Provider Interface\n\nAll providers must implement the following interface:\n\n#### Core Operations\n\n- `create-server(config: record) -> record`\n- `delete-server(server_id: string) -> null`\n- `list-servers() -> list`\n- `get-server-info(server_id: string) -> record`\n- `start-server(server_id: string) -> null`\n- `stop-server(server_id: string) -> null`\n- `reboot-server(server_id: string) -> null`\n\n#### Pricing and Plans\n\n- `get-pricing() -> list`\n- `get-plans() -> list`\n- `get-zones() -> list`\n\n#### SSH and Access\n\n- `get-ssh-access(server_id: string) -> record`\n- `configure-firewall(server_id: string, rules: list) -> null`\n\n### Provider Development Template\n\n#### Nickel Configuration Schema\n\nCreate `schemas/settings.ncl`:\n\n```\n# Provider settings schema\n{\n ProviderSettings = {\n # Authentication configuration\n auth | {\n method | "api_key" | "certificate" | "oauth" | "basic",\n api_key | String = null,\n api_secret | String = null,\n username | String = null,\n password | String = null,\n certificate_path | String = null,\n private_key_path | String = null,\n },\n\n # API configuration\n api | {\n base_url | String,\n version | String = "v1",\n timeout | Number = 30,\n retries | Number = 3,\n },\n\n # Default server configuration\n defaults: {\n plan?: str\n zone?: str\n os?: str\n ssh_keys?: [str]\n firewall_rules?: [FirewallRule]\n }\n\n # Provider-specific settings\n features: {\n load_balancer?: bool = false\n storage_encryption?: bool = true\n backup?: bool = true\n monitoring?: bool = false\n }\n}\n\nschema FirewallRule {\n direction: "ingress" | "egress"\n protocol: "tcp" | "udp" | "icmp"\n port?: str\n source?: str\n destination?: str\n action: "allow" | "deny"\n}\n\nschema ServerConfig {\n hostname: str\n plan: str\n zone: str\n os: str = "ubuntu-22.04"\n ssh_keys: [str] = []\n tags?: {str: str} = {}\n firewall_rules?: [FirewallRule] = []\n storage?: {\n size?: int\n type?: str\n encrypted?: bool = true\n }\n network?: {\n public_ip?: bool = true\n private_network?: str\n bandwidth?: int\n }\n}\n```\n\n#### Nushell Implementation\n\nCreate `nulib/mod.nu`:\n\n```\nuse std log\n\n# Provider name and version\nexport const PROVIDER_NAME = "my-provider"\nexport const PROVIDER_VERSION = "1.0.0"\n\n# Import sub-modules\nuse create.nu *\nuse delete.nu *\nuse utils.nu *\n\n# Provider interface implementation\nexport def "provider-info" [] -> record {\n {\n name: $PROVIDER_NAME,\n version: $PROVIDER_VERSION,\n type: "provider",\n interface: "API",\n supported_operations: [\n "create-server", "delete-server", "list-servers",\n "get-server-info", "start-server", "stop-server"\n ],\n required_auth: ["api_key", "api_secret"],\n supported_os: ["ubuntu-22.04", "debian-11", "centos-8"],\n regions: (get-zones).name\n }\n}\n\nexport def "validate-config" [config: record] -> record {\n mut errors = []\n mut warnings = []\n\n # Validate authentication\n if ($config | get -o "auth.api_key" | is-empty) {\n $errors = ($errors | append "Missing API key")\n }\n\n if ($config | get -o "auth.api_secret" | is-empty) {\n $errors = ($errors | append "Missing API secret")\n }\n\n # Validate API configuration\n let api_url = ($config | get -o "api.base_url")\n if ($api_url | is-empty) {\n $errors = ($errors | append "Missing API base URL")\n } else {\n try {\n http get $"($api_url)/health" | ignore\n } catch {\n $warnings = ($warnings | append "API endpoint not reachable")\n }\n }\n\n {\n valid: ($errors | is-empty),\n errors: $errors,\n warnings: $warnings\n }\n}\n\nexport def "test-connection" [config: record] -> record {\n try {\n let api_url = ($config | get "api.base_url")\n let response = (http get $"($api_url)/account" --headers {\n Authorization: $"Bearer ($config | get 'auth.api_key')"\n })\n\n {\n success: true,\n account_info: $response,\n message: "Connection successful"\n }\n } catch {|e|\n {\n success: false,\n error: ($e | get msg),\n message: "Connection failed"\n }\n }\n}\n```\n\nCreate `nulib/create.nu`:\n\n```\nuse std log\nuse utils.nu *\n\nexport def "create-server" [\n config: record # Server configuration\n --check # Check mode only\n --wait # Wait for completion\n] -> record {\n log info $"Creating server: ($config.hostname)"\n\n if $check {\n return {\n action: "create-server",\n hostname: $config.hostname,\n check_mode: true,\n would_create: true,\n estimated_time: "2-5 minutes"\n }\n }\n\n # Validate configuration\n let validation = (validate-server-config $config)\n if not $validation.valid {\n error make {\n msg: $"Invalid server configuration: ($validation.errors | str join ', ')"\n }\n }\n\n # Prepare API request\n let api_config = (get-api-config)\n let request_body = {\n hostname: $config.hostname,\n plan: $config.plan,\n zone: $config.zone,\n os: $config.os,\n ssh_keys: $config.ssh_keys,\n tags: $config.tags,\n firewall_rules: $config.firewall_rules\n }\n\n try {\n let response = (http post $"($api_config.base_url)/servers" --headers {\n Authorization: $"Bearer ($api_config.auth.api_key)"\n Content-Type: "application/json"\n } $request_body)\n\n let server_id = ($response | get id)\n log info $"Server creation initiated: ($server_id)"\n\n if $wait {\n let final_status = (wait-for-server-ready $server_id)\n {\n success: true,\n server_id: $server_id,\n hostname: $config.hostname,\n status: $final_status,\n ip_addresses: (get-server-ips $server_id),\n ssh_access: (get-ssh-access $server_id)\n }\n } else {\n {\n success: true,\n server_id: $server_id,\n hostname: $config.hostname,\n status: "creating",\n message: "Server creation in progress"\n }\n }\n } catch {|e|\n error make {\n msg: $"Server creation failed: ($e | get msg)"\n }\n }\n}\n\ndef validate-server-config [config: record] -> record {\n mut errors = []\n\n # Required fields\n if ($config | get -o hostname | is-empty) {\n $errors = ($errors | append "Hostname is required")\n }\n\n if ($config | get -o plan | is-empty) {\n $errors = ($errors | append "Plan is required")\n }\n\n if ($config | get -o zone | is-empty) {\n $errors = ($errors | append "Zone is required")\n }\n\n # Validate plan exists\n let available_plans = (get-plans)\n if not ($config.plan in ($available_plans | get name)) {\n $errors = ($errors | append $"Invalid plan: ($config.plan)")\n }\n\n # Validate zone exists\n let available_zones = (get-zones)\n if not ($config.zone in ($available_zones | get name)) {\n $errors = ($errors | append $"Invalid zone: ($config.zone)")\n }\n\n {\n valid: ($errors | is-empty),\n errors: $errors\n }\n}\n\ndef wait-for-server-ready [server_id: string] -> string {\n mut attempts = 0\n let max_attempts = 60 # 10 minutes\n\n while $attempts < $max_attempts {\n let server_info = (get-server-info $server_id)\n let status = ($server_info | get status)\n\n match $status {\n "running" => { return "running" },\n "error" => { error make { msg: "Server creation failed" } },\n _ => {\n log info $"Server status: ($status), waiting..."\n sleep 10sec\n $attempts = $attempts + 1\n }\n }\n }\n\n error make { msg: "Server creation timeout" }\n}\n```\n\n### Provider Registration\n\nAdd provider metadata in `metadata.toml`:\n\n```\n[extension]\nname = "my-provider"\ntype = "provider"\nversion = "1.0.0"\ndescription = "Custom cloud provider integration"\nauthor = "Your Name "\nlicense = "MIT"\n\n[compatibility]\nprovisioning_version = ">=2.0.0"\nnushell_version = ">=0.107.0"\nnickel_version = ">=1.15.0"\n\n[capabilities]\nserver_management = true\nload_balancer = false\nstorage_encryption = true\nbackup = true\nmonitoring = false\n\n[authentication]\nmethods = ["api_key", "certificate"]\nrequired_fields = ["api_key", "api_secret"]\n\n[regions]\ndefault = "us-east-1"\navailable = ["us-east-1", "us-west-2", "eu-west-1"]\n\n[support]\ndocumentation = "https://docs.example.com/provider"\nissues = "https://github.com/example/provider/issues"\n```\n\n## Task Service Extension API\n\n### Task Service Interface\n\nTask services must implement:\n\n#### Core Operations\n\n- `install(config: record) -> record`\n- `uninstall(config: record) -> null`\n- `configure(config: record) -> null`\n- `status() -> record`\n- `restart() -> null`\n- `upgrade(version: string) -> record`\n\n#### Version Management\n\n- `get-current-version() -> string`\n- `get-available-versions() -> list`\n- `check-updates() -> record`\n\n### Task Service Development Template\n\n#### Nickel Schema\n\nCreate `schemas/version.ncl`:\n\n```\n# Task service version configuration\n{\n taskserv_version = {\n name | String = "my-service",\n version | String = "1.0.0",\n\n # Version source configuration\n source | {\n type | String = "github",\n repository | String,\n release_pattern | String = "v{version}",\n },\n\n # Installation configuration\n install | {\n method | String = "binary",\n binary_name | String,\n binary_path | String = "/usr/local/bin",\n config_path | String = "/etc/my-service",\n data_path | String = "/var/lib/my-service",\n },\n\n # Dependencies\n dependencies | [\n {\n name | String,\n version | String = ">=1.0.0",\n }\n ],\n\n # Service configuration\n service | {\n type | String = "systemd",\n user | String = "my-service",\n group | String = "my-service",\n ports | [Number] = [8080, 9090],\n },\n\n # Health check configuration\n health_check | {\n endpoint | String,\n interval | Number = 30,\n timeout | Number = 5,\n retries | Number = 3,\n },\n }\n}\n```\n\n#### Nushell Implementation\n\nCreate `nulib/mod.nu`:\n\n```\nuse std log\nuse ../../../lib_provisioning *\n\nexport const SERVICE_NAME = "my-service"\nexport const SERVICE_VERSION = "1.0.0"\n\nexport def "taskserv-info" [] -> record {\n {\n name: $SERVICE_NAME,\n version: $SERVICE_VERSION,\n type: "taskserv",\n category: "application",\n description: "Custom application service",\n dependencies: ["containerd"],\n ports: [8080, 9090],\n config_files: ["/etc/my-service/config.yaml"],\n data_directories: ["/var/lib/my-service"]\n }\n}\n\nexport def "install" [\n config: record = {}\n --check # Check mode only\n --version: string # Specific version to install\n] -> record {\n let install_version = if ($version | is-not-empty) {\n $version\n } else {\n (get-latest-version)\n }\n\n log info $"Installing ($SERVICE_NAME) version ($install_version)"\n\n if $check {\n return {\n action: "install",\n service: $SERVICE_NAME,\n version: $install_version,\n check_mode: true,\n would_install: true,\n requirements_met: (check-requirements)\n }\n }\n\n # Check system requirements\n let req_check = (check-requirements)\n if not $req_check.met {\n error make {\n msg: $"Requirements not met: ($req_check.missing | str join ', ')"\n }\n }\n\n # Download and install\n let binary_path = (download-binary $install_version)\n install-binary $binary_path\n create-user-and-directories\n generate-config $config\n install-systemd-service\n\n # Start service\n systemctl start $SERVICE_NAME\n systemctl enable $SERVICE_NAME\n\n # Verify installation\n let health = (check-health)\n if not $health.healthy {\n error make { msg: "Service failed health check after installation" }\n }\n\n {\n success: true,\n service: $SERVICE_NAME,\n version: $install_version,\n status: "running",\n health: $health\n }\n}\n\nexport def "uninstall" [\n --force # Force removal even if running\n --keep-data # Keep data directories\n] -> null {\n log info $"Uninstalling ($SERVICE_NAME)"\n\n # Stop and disable service\n try {\n systemctl stop $SERVICE_NAME\n systemctl disable $SERVICE_NAME\n } catch {\n log warning "Failed to stop systemd service"\n }\n\n # Remove binary\n try {\n rm -f $"/usr/local/bin/($SERVICE_NAME)"\n } catch {\n log warning "Failed to remove binary"\n }\n\n # Remove configuration\n try {\n rm -rf $"/etc/($SERVICE_NAME)"\n } catch {\n log warning "Failed to remove configuration"\n }\n\n # Remove data directories (unless keeping)\n if not $keep_data {\n try {\n rm -rf $"/var/lib/($SERVICE_NAME)"\n } catch {\n log warning "Failed to remove data directories"\n }\n }\n\n # Remove systemd service file\n try {\n rm -f $"/etc/systemd/system/($SERVICE_NAME).service"\n systemctl daemon-reload\n } catch {\n log warning "Failed to remove systemd service"\n }\n\n log info $"($SERVICE_NAME) uninstalled successfully"\n}\n\nexport def "status" [] -> record {\n let systemd_status = try {\n systemctl is-active $SERVICE_NAME | str trim\n } catch {\n "unknown"\n }\n\n let health = (check-health)\n let version = (get-current-version)\n\n {\n service: $SERVICE_NAME,\n version: $version,\n systemd_status: $systemd_status,\n health: $health,\n uptime: (get-service-uptime),\n memory_usage: (get-memory-usage),\n cpu_usage: (get-cpu-usage)\n }\n}\n\ndef check-requirements [] -> record {\n mut missing = []\n mut met = true\n\n # Check for containerd\n if not (which containerd | is-not-empty) {\n $missing = ($missing | append "containerd")\n $met = false\n }\n\n # Check for systemctl\n if not (which systemctl | is-not-empty) {\n $missing = ($missing | append "systemctl")\n $met = false\n }\n\n {\n met: $met,\n missing: $missing\n }\n}\n\ndef check-health [] -> record {\n try {\n let response = (http get "http://localhost:9090/health")\n {\n healthy: true,\n status: ($response | get status),\n last_check: (date now)\n }\n } catch {\n {\n healthy: false,\n error: "Health endpoint not responding",\n last_check: (date now)\n }\n }\n}\n```\n\n## Cluster Extension API\n\n### Cluster Interface\n\nClusters orchestrate multiple components:\n\n#### Core Operations\n\n- `create(config: record) -> record`\n- `delete(config: record) -> null`\n- `status() -> record`\n- `scale(replicas: int) -> record`\n- `upgrade(version: string) -> record`\n\n#### Component Management\n\n- `list-components() -> list`\n- `component-status(name: string) -> record`\n- `restart-component(name: string) -> null`\n\n### Cluster Development Template\n\n#### Nickel Configuration\n\nCreate `schemas/cluster.ncl`:\n\n```\n# Cluster configuration schema\n{\n ClusterConfig = {\n # Cluster metadata\n name | String,\n version | String = "1.0.0",\n description | String = "",\n\n # Components to deploy\n components | [Component],\n\n # Resource requirements\n resources | {\n min_nodes | Number = 1,\n cpu_per_node | String = "2",\n memory_per_node | String = "4Gi",\n storage_per_node | String = "20Gi",\n },\n\n # Network configuration\n network | {\n cluster_cidr | String = "10.244.0.0/16",\n service_cidr | String = "10.96.0.0/12",\n dns_domain | String = "cluster.local",\n },\n\n # Feature flags\n features | {\n monitoring | Bool = true,\n logging | Bool = true,\n ingress | Bool = false,\n storage | Bool = true,\n },\n },\n\n Component = {\n name | String,\n type | String | "taskserv" | "application" | "infrastructure",\n version | String = "",\n enabled | Bool = true,\n dependencies | [String] = [],\n config | {} = {},\n resources | {\n cpu | String = "",\n memory | String = "",\n storage | String = "",\n replicas | Number = 1,\n } = {},\n },\n\n # Example cluster configuration\n buildkit_cluster = {\n name = "buildkit",\n version = "1.0.0",\n description = "Container build cluster with BuildKit and registry",\n components = [\n {\n name = "containerd",\n type = "taskserv",\n version = "1.7.0",\n enabled = true,\n dependencies = [],\n },\n {\n name = "buildkit",\n type = "taskserv",\n version = "0.12.0",\n enabled = true,\n dependencies = ["containerd"],\n config = {\n worker_count = 4,\n cache_size = "10Gi",\n registry_mirrors = ["registry:5000"],\n },\n },\n {\n name = "registry",\n type = "application",\n version = "2.8.0",\n enabled = true,\n dependencies = [],\n config = {\n storage_driver = "filesystem",\n storage_path = "/var/lib/registry",\n auth_enabled = false,\n },\n resources = {\n cpu = "500m",\n memory = "1Gi",\n storage = "50Gi",\n replicas = 1,\n },\n },\n ],\n resources = {\n min_nodes = 1,\n cpu_per_node = "4",\n memory_per_node = "8Gi",\n storage_per_node = "100Gi",\n },\n features = {\n monitoring = true,\n logging = true,\n ingress = false,\n storage = true,\n },\n },\n}\n```\n\n#### Nushell Implementation\n\nCreate `nulib/mod.nu`:\n\n```\nuse std log\nuse ../../../lib_provisioning *\n\nexport const CLUSTER_NAME = "my-cluster"\nexport const CLUSTER_VERSION = "1.0.0"\n\nexport def "cluster-info" [] -> record {\n {\n name: $CLUSTER_NAME,\n version: $CLUSTER_VERSION,\n type: "cluster",\n category: "build",\n description: "Custom application cluster",\n components: (get-cluster-components),\n required_resources: {\n min_nodes: 1,\n cpu_per_node: "2",\n memory_per_node: "4Gi",\n storage_per_node: "20Gi"\n }\n }\n}\n\nexport def "create" [\n config: record = {}\n --check # Check mode only\n --wait # Wait for completion\n] -> record {\n log info $"Creating cluster: ($CLUSTER_NAME)"\n\n if $check {\n return {\n action: "create-cluster",\n cluster: $CLUSTER_NAME,\n check_mode: true,\n would_create: true,\n components: (get-cluster-components),\n requirements_check: (check-cluster-requirements)\n }\n }\n\n # Validate cluster requirements\n let req_check = (check-cluster-requirements)\n if not $req_check.met {\n error make {\n msg: $"Cluster requirements not met: ($req_check.issues | str join ', ')"\n }\n }\n\n # Get component deployment order\n let components = (get-cluster-components)\n let deployment_order = (resolve-component-dependencies $components)\n\n mut deployment_status = []\n\n # Deploy components in dependency order\n for component in $deployment_order {\n log info $"Deploying component: ($component.name)"\n\n try {\n let result = match $component.type {\n "taskserv" => {\n taskserv create $component.name --config $component.config --wait\n },\n "application" => {\n deploy-application $component\n },\n _ => {\n error make { msg: $"Unknown component type: ($component.type)" }\n }\n }\n\n $deployment_status = ($deployment_status | append {\n component: $component.name,\n status: "deployed",\n result: $result\n })\n\n } catch {|e|\n log error $"Failed to deploy ($component.name): ($e.msg)"\n $deployment_status = ($deployment_status | append {\n component: $component.name,\n status: "failed",\n error: $e.msg\n })\n\n # Rollback on failure\n rollback-cluster-deployment $deployment_status\n error make { msg: $"Cluster deployment failed at component: ($component.name)" }\n }\n }\n\n # Configure cluster networking and integrations\n configure-cluster-networking $config\n setup-cluster-monitoring $config\n\n # Wait for all components to be ready\n if $wait {\n wait-for-cluster-ready\n }\n\n {\n success: true,\n cluster: $CLUSTER_NAME,\n components: $deployment_status,\n endpoints: (get-cluster-endpoints),\n status: "running"\n }\n}\n\nexport def "delete" [\n config: record = {}\n --force # Force deletion\n] -> null {\n log info $"Deleting cluster: ($CLUSTER_NAME)"\n\n let components = (get-cluster-components)\n let deletion_order = ($components | reverse) # Delete in reverse order\n\n for component in $deletion_order {\n log info $"Removing component: ($component.name)"\n\n try {\n match $component.type {\n "taskserv" => {\n taskserv delete $component.name --force=$force\n },\n "application" => {\n remove-application $component --force=$force\n },\n _ => {\n log warning $"Unknown component type: ($component.type)"\n }\n }\n } catch {|e|\n log error $"Failed to remove ($component.name): ($e.msg)"\n if not $force {\n error make { msg: $"Component removal failed: ($component.name)" }\n }\n }\n }\n\n # Clean up cluster-level resources\n cleanup-cluster-networking\n cleanup-cluster-monitoring\n cleanup-cluster-storage\n\n log info $"Cluster ($CLUSTER_NAME) deleted successfully"\n}\n\ndef get-cluster-components [] -> list {\n [\n {\n name: "containerd",\n type: "taskserv",\n version: "1.7.0",\n dependencies: []\n },\n {\n name: "my-service",\n type: "taskserv",\n version: "1.0.0",\n dependencies: ["containerd"]\n },\n {\n name: "registry",\n type: "application",\n version: "2.8.0",\n dependencies: []\n }\n ]\n}\n\ndef resolve-component-dependencies [components: list] -> list {\n # Topological sort of components based on dependencies\n mut sorted = []\n mut remaining = $components\n\n while ($remaining | length) > 0 {\n let no_deps = ($remaining | where {|comp|\n ($comp.dependencies | all {|dep|\n $dep in ($sorted | get name)\n })\n })\n\n if ($no_deps | length) == 0 {\n error make { msg: "Circular dependency detected in cluster components" }\n }\n\n $sorted = ($sorted | append $no_deps)\n $remaining = ($remaining | where {|comp|\n not ($comp.name in ($no_deps | get name))\n })\n }\n\n $sorted\n}\n```\n\n## Extension Registration and Discovery\n\n### Extension Registry\n\nExtensions are registered in the system through:\n\n1. **Directory Structure**: Placed in appropriate directories (providers/, taskservs/, cluster/)\n2. **Metadata Files**: `metadata.toml` with extension information\n3. **Schema Files**: `schemas/` directory with Nickel schema files\n\n### Registration API\n\n#### `register-extension(path: string, type: string) -> record`\n\nRegisters a new extension with the system.\n\n**Parameters:**\n\n- `path`: Path to extension directory\n- `type`: Extension type (provider, taskserv, cluster)\n\n#### `unregister-extension(name: string, type: string) -> null`\n\nRemoves extension from the registry.\n\n#### `list-registered-extensions(type?: string) -> list`\n\nLists all registered extensions, optionally filtered by type.\n\n### Extension Validation\n\n#### Validation Rules\n\n1. **Structure Validation**: Required files and directories exist\n2. **Schema Validation**: Nickel schemas are valid\n3. **Interface Validation**: Required functions are implemented\n4. **Dependency Validation**: Dependencies are available\n5. **Version Validation**: Version constraints are met\n\n#### `validate-extension(path: string, type: string) -> record`\n\nValidates extension structure and implementation.\n\n## Testing Extensions\n\n### Test Framework\n\nExtensions should include comprehensive tests:\n\n#### Unit Tests\n\nCreate `tests/unit_tests.nu`:\n\n```\nuse std testing\n\nexport def test_provider_config_validation [] {\n let config = {\n auth: { api_key: "test-key", api_secret: "test-secret" },\n api: { base_url: "https://api.test.com" }\n }\n\n let result = (validate-config $config)\n assert ($result.valid == true)\n assert ($result.errors | is-empty)\n}\n\nexport def test_server_creation_check_mode [] {\n let config = {\n hostname: "test-server",\n plan: "1xCPU-1 GB",\n zone: "test-zone"\n }\n\n let result = (create-server $config --check)\n assert ($result.check_mode == true)\n assert ($result.would_create == true)\n}\n```\n\n#### Integration Tests\n\nCreate `tests/integration_tests.nu`:\n\n```\nuse std testing\n\nexport def test_full_server_lifecycle [] {\n # Test server creation\n let create_config = {\n hostname: "integration-test",\n plan: "1xCPU-1 GB",\n zone: "test-zone"\n }\n\n let server = (create-server $create_config --wait)\n assert ($server.success == true)\n let server_id = $server.server_id\n\n # Test server info retrieval\n let info = (get-server-info $server_id)\n assert ($info.hostname == "integration-test")\n assert ($info.status == "running")\n\n # Test server deletion\n delete-server $server_id\n\n # Verify deletion\n let final_info = try { get-server-info $server_id } catch { null }\n assert ($final_info == null)\n}\n```\n\n### Running Tests\n\n```\n# Run unit tests\nnu tests/unit_tests.nu\n\n# Run integration tests\nnu tests/integration_tests.nu\n\n# Run all tests\nnu tests/run_all_tests.nu\n```\n\n## Documentation Requirements\n\n### Extension Documentation\n\nEach extension must include:\n\n1. **README.md**: Overview, installation, and usage\n2. **API.md**: Detailed API documentation\n3. **EXAMPLES.md**: Usage examples and tutorials\n4. **CHANGELOG.md**: Version history and changes\n\n### API Documentation Template\n\n```\n# Extension Name API\n\n## Overview\nBrief description of the extension and its purpose.\n\n## Installation\nSteps to install and configure the extension.\n\n## Configuration\nConfiguration schema and options.\n\n## API Reference\nDetailed API documentation with examples.\n\n## Examples\nCommon usage patterns and examples.\n\n## Troubleshooting\nCommon issues and solutions.\n```\n\n## Best Practices\n\n### Development Guidelines\n\n1. **Follow Naming Conventions**: Use consistent naming for functions and variables\n2. **Error Handling**: Implement comprehensive error handling and recovery\n3. **Logging**: Use structured logging for debugging and monitoring\n4. **Configuration Validation**: Validate all inputs and configurations\n5. **Documentation**: Document all public APIs and configurations\n6. **Testing**: Include comprehensive unit and integration tests\n7. **Versioning**: Follow semantic versioning principles\n8. **Security**: Implement secure credential handling and API calls\n\n### Performance Considerations\n\n1. **Caching**: Cache expensive operations and API calls\n2. **Parallel Processing**: Use parallel execution where possible\n3. **Resource Management**: Clean up resources properly\n4. **Batch Operations**: Batch API calls when possible\n5. **Health Monitoring**: Implement health checks and monitoring\n\n### Security Best Practices\n\n1. **Credential Management**: Store credentials securely\n2. **Input Validation**: Validate and sanitize all inputs\n3. **Access Control**: Implement proper access controls\n4. **Audit Logging**: Log all security-relevant operations\n5. **Encryption**: Encrypt sensitive data in transit and at rest\n\nThis extension development API provides a comprehensive framework for building robust, scalable, and maintainable extensions for provisioning.