Pack Manifest

Pack Manifest

Every Intelligence Pack requires a huitzo.yaml manifest file that defines metadata, permissions, and configuration. This file is the single source of truth for all pack configuration — pyproject.toml is auto-generated from it by the CLI.

pyproject.toml Generation: You should never edit pyproject.toml directly. Run huitzo pack sync to regenerate it from huitzo.yaml, or it will be regenerated automatically on huitzo pack build and huitzo pack dev.

Manifest Files: Intelligence Packs use huitzo.yaml. Dashboards use huitzo-dashboard.yaml. See Dashboard Manifest for dashboard configuration.

Optional fullstack scaffolding. When a Pack ships alongside a Dashboard as one app, huitzo project init can scaffold both into a single directory. That is a CLI convenience for fullstack work — it does not change the Pack manifest below or anything about how huitzo pack ... behaves. Standalone Packs created with huitzo pack new remain fully supported. See Intelligence Projects if fullstack scaffolding is useful for your work.

Quick Example

pack:
  name: "my-company-analytics"
  namespace: "analytics"
  version: "1.0.0"
  description: "Business analytics and reporting tools"
  visibility: "organization"
  author: "My Company"
  license: "proprietary"

commands:
  - name: "generate-report"
    description: "Generate analytics report"
    entry_point: "my_company_analytics.commands.report:generate_report"
    permissions: ["llm:complete"]
    timeout: 300
    queue: "long"

  - name: "quick-summary"
    description: "Get quick data summary"
    entry_point: "my_company_analytics.commands.summary:quick_summary"
    permissions: []
    timeout: 30
    queue: "fast"

data_types:
  - name: "reports"
    description: "Generated report data"
    ttl_days: 90

  - name: "cache"
    description: "Temporary calculation cache"
    ttl_days: 7

services:
  llm:
    required: true
    models: ["gpt-4o-mini", "claude-sonnet"]
  email:
    required: false
  telegram:
    required: false

secrets:
  user_required:
    - name: "ANALYTICS_API_KEY"
      description: "Your analytics provider API key"
      help_url: "https://analytics.example.com/api-keys"
  user_optional:
    - name: "PREMIUM_API_KEY"
      description: "Optional premium tier API key"

metadata:
  homepage: "https://example.com/analytics-pack"
  repository: "https://github.com/example/analytics-pack"
  documentation: "https://docs.example.com/analytics"
  keywords: ["analytics", "reporting", "business-intelligence"]
  category: "business"

File Structure

The manifest uses YAML format with these main sections:

Section Required Description
pack ✅ Yes Core pack metadata
deployment ❌ No Deployment capability flags
resources ❌ No Resource requirements
embedded_models ❌ No Embedded AI models (edge)
commands ✅ Yes Command definitions
data_types ❌ No Storage data type definitions
services ❌ No External service dependencies
mcp_servers ❌ No MCP server configurations
ssh_targets ❌ No SSH target access declarations
secrets ❌ No User-provided secrets configuration
metadata ❌ No Additional metadata

Pack Section

The pack section defines core metadata about your Intelligence Pack.

Required Fields

pack:
  name: "my-pack"           # Unique identifier (kebab-case)
  namespace: "mypack"       # Command namespace (lowercase, no dashes)
  version: "1.0.0"          # Semantic version
  description: "Short description of what the pack does"

Optional Fields

pack:
  # ... required fields ...

  visibility: "organization"  # public | unlisted | organization | private
  author: "Your Name"         # Pack author or company
  author_email: "[email protected]"  # Author email
  license: "MIT"              # License identifier
  min_sdk_version: "2.0.0"    # Minimum SDK version required
  min_platform_version: "2.0.0"  # Minimum platform version required

  # Python dependencies beyond huitzo-sdk (which is always included)
  dependencies:
    - "pydantic>=2.0"
    - "requests>=2.31"

  # Dev-only dependencies
  dev_dependencies:
    - "pytest>=9.0"
    - "ruff>=0.14"

  # Pricing (marketplace only)
  pricing:
    model: "one-time"         # one-time | subscription | usage
    price: 49                 # USD (0 = free)

Field Reference

Field Type Required Default Description
name string - Unique pack identifier. Must be kebab-case.
namespace string - Command namespace. Lowercase, no special chars.
version string - Semantic version (MAJOR.MINOR.PATCH)
description string - Short description (max 200 chars)
visibility enum organization Access control level
author string - Author name or organization
license string proprietary License identifier
min_sdk_version string 2.0.0 Minimum SDK version
min_platform_version string 2.0.0 Minimum platform version

Visibility Levels

Level Description Discovery Access
public Available to all tenants Searchable, browsable No access grant required
unlisted Hidden from discovery Not searchable Requires pack link or ID
organization Requires explicit access grant Org members only Must have PluginAccessGrant
private Only available to owner organization Owner only Owner tenant only

Unlisted Visibility

Unlisted packs are not discoverable through search or the pack marketplace, but can be accessed and installed using a direct link or pack ID. This is ideal for:

  • Agency model: Build custom packs for specific clients without exposing to other customers
  • Beta testing: Share with select users before public release
  • Custom enterprise: Deliver tailored solutions to specific organizations

Sharing an unlisted pack:

# Get shareable pack ID and link
$ huitzo pack share
Pack ID: pack_a1b2c3d4e5f6
Direct URL: https://app.huitzo.com/packs/pack_a1b2c3d4e5f6

# Client installs via pack ID
$ huitzo pack install pack_a1b2c3d4e5f6

Important: The pack ID is the only way to access unlisted packs. Treat it like a private invitation link.

Best Practice: Use organization (the default) for internal commercial packs. Use unlisted for client-specific deliverables. Use public only for utility/demo packs.


Pricing Section

The pricing section configures marketplace pricing for your pack. This section only applies to Cloud (SaaS) deployments; self-hosted packs cannot be sold on the marketplace.

Basic Pricing

pack:
  pricing:
    model: "one-time"
    price: 49

Full Pricing Configuration

pack:
  pricing:
    model: "one-time"           # one-time | subscription | usage
    price: 49                   # USD (0 = free, minimum $5 for paid)
    currency: "usd"             # Only USD initially

    # Subscription-only fields (v0.1+)
    billing_period: "monthly"   # monthly | annual
    trial_days: 14              # Free trial period

    # Usage-based fields (v2.5+)
    per_execution: 0.05         # USD per command execution
    monthly_minimum: 5          # Optional minimum monthly charge

Pricing Models

One-Time Purchase (v0.0)

Customer pays once for permanent access to the pack:

pack:
  pricing:
    model: "one-time"
    price: 49
  • Best for: Tools, utilities, standalone solutions
  • Customer gets: Lifetime access to current version
  • Updates: Major versions may require repurchase (at developer's discretion)

Subscription (v0.1+)

Recurring billing for ongoing access:

pack:
  pricing:
    model: "subscription"
    price: 19
    billing_period: "monthly"
    trial_days: 14
Field Type Default Description
billing_period enum monthly monthly or annual
trial_days int 0 Free trial duration (0-30 days)
  • Best for: Packs with ongoing value, regular updates
  • Customer gets: Access while subscribed
  • Cancellation: Loses access at end of billing period

Usage-Based (v2.5+)

Pay-per-execution pricing:

pack:
  pricing:
    model: "usage"
    per_execution: 0.05
    monthly_minimum: 5
Field Type Default Description
per_execution float required USD per command execution
monthly_minimum float 0 Minimum monthly charge
  • Best for: API-style packs, high-volume processing
  • Customer pays: Based on actual usage
  • Billing: Monthly invoice based on execution count

Free Packs

Set price to 0 for free distribution:

pack:
  pricing:
    model: "one-time"
    price: 0

Free packs: - No Stripe account required - No platform fees - Appear in marketplace with "Free" badge - Great for community building, demos, open-source tools

Pricing Field Reference

Field Type Required Default Description
model enum one-time Pricing model
price int 0 Price in USD (cents for < $1)
currency string usd Currency code (USD only initially)
billing_period enum monthly For subscriptions only
trial_days int 0 Free trial days (subscriptions only)
per_execution float - Per-execution price (usage only)
monthly_minimum float 0 Minimum monthly charge (usage only)

Pricing Validation Rules

Rule Requirement
Minimum paid price $5 USD (prevents race-to-bottom)
Maximum price $10,000 USD
Trial days 0-30 days for subscriptions
Per-execution $0.001 - $100 USD

Revenue Split

See Billing Reference for complete revenue split details.

Annual Revenue Platform Fee Developer Keeps
$0 - $5,000 0% 100%
$5,001 - $50,000 20% 80%
$50,001+ 10% 90%

Pricing Examples

Example 1: Professional Tool ($49 one-time)

pack:
  name: "claims-processor"
  pricing:
    model: "one-time"
    price: 49

Revenue per sale: $49 × 80% = $39.20 (after $5K threshold)

Example 2: SaaS Tool ($19/month subscription)

pack:
  name: "analytics-dashboard"
  pricing:
    model: "subscription"
    price: 19
    billing_period: "monthly"
    trial_days: 7

Monthly revenue per subscriber: $19 × 80% = $15.20

Example 3: API Tool ($0.05/execution usage)

pack:
  name: "document-parser"
  pricing:
    model: "usage"
    per_execution: 0.05
    monthly_minimum: 5

Revenue for 1,000 executions: $50 × 80% = $40.00

Changing Pricing

Pricing changes take effect for new purchases only:

  • Existing one-time buyers: Keep their access
  • Existing subscribers: Grandfathered at old price until they cancel
  • New customers: See new pricing
# Update pricing
$ huitzo pack update-pricing --price 59

# Publish with new pricing
$ huitzo pack publish

Deployment Section

The deployment section declares which deployment modes your pack supports. This enables the platform to validate pack compatibility with different deployment targets.

Basic Configuration

deployment:
  cloud_capable: true          # Can run in Huitzo cloud (default: true)
  self_hosted_capable: true    # Can run on customer infrastructure (default: true)
  edge_capable: false          # Can run on edge devices (default: false)
  offline_capable: false       # Can operate without network (default: false)
  requires_internet: true      # Requires internet for functionality (default: true)

Field Reference

Field Type Default Description
cloud_capable bool true Pack can run in Huitzo-managed cloud
self_hosted_capable bool true Pack can run on customer infrastructure
edge_capable bool false Pack can run on edge devices (Year 3+)
offline_capable bool false Pack can operate without network (Year 3+)
requires_internet bool true Pack requires internet connectivity

Deployment Mode Compatibility

# Example: Pack that only works in cloud (requires cloud LLM APIs)
deployment:
  cloud_capable: true
  self_hosted_capable: false
  requires_internet: true

# Example: Pack that works everywhere (no external dependencies)
deployment:
  cloud_capable: true
  self_hosted_capable: true
  edge_capable: true        # Future
  offline_capable: true     # Future
  requires_internet: false

# Example: Pack designed for regulated environments
deployment:
  cloud_capable: false       # No cloud for compliance
  self_hosted_capable: true
  edge_capable: true         # Future: air-gapped support
  offline_capable: true      # Future
  requires_internet: false

Validation Behavior

Year 1: All fields are validated on pack registration. Only cloud_capable and self_hosted_capable affect deployment routing.

Year 3+: edge_capable and offline_capable will enable edge deployment routing when edge mode is implemented.


Resources Section

The resources section declares pack-level resource requirements. This helps the platform optimize execution and validate deployment feasibility.

Basic Configuration

resources:
  min_memory_mb: 256           # Minimum memory to execute
  recommended_memory_mb: 512   # Recommended for performance
  requires_gpu: false          # GPU required for execution

Field Reference

Field Type Default Description
min_memory_mb int 256 Minimum memory in MB
recommended_memory_mb int 512 Recommended memory in MB
requires_gpu bool false GPU required for execution

Future Fields (Validated but Inactive)

These fields are validated but do not affect behavior until edge mode is implemented:

resources:
  # Future: Hardware acceleration preferences
  # accelerator_preference: "cuda|tensorrt|onnx|cpu"
  # max_latency_ms: 100
  # power_budget_watts: 50

Embedded Models Section (Future)

The embedded_models section declares AI models that should be bundled with the pack for edge deployment. This section is validated but inactive until edge mode is implemented (Year 3+).

Configuration (Year 3+)

embedded_models:
  - id: "custom-ner"
    format: "onnx"             # onnx | pytorch | tensorflow
    size_mb: 128
    quantization: "int8"       # none | fp16 | int8
    description: "Custom NER model for entity extraction"

  - id: "summarizer"
    format: "onnx"
    size_mb: 256
    quantization: "fp16"
    description: "Text summarization model"

Field Reference (Future)

Field Type Description
id string Unique model identifier
format enum Model format: onnx, pytorch, tensorflow
size_mb int Model size in MB
quantization enum Quantization level: none, fp16, int8
description string Human-readable description

Current Status: This section is accepted and validated for forward compatibility, but models are not bundled until edge mode is implemented.


Commands Section

The commands section lists all commands provided by the pack with their configurations.

Basic Command

commands:
  - name: "hello"
    description: "Say hello"
    entry_point: "my_pack.commands.hello:hello_world"

Full Command Configuration

commands:
  - name: "analyze-data"
    description: "Analyze dataset and generate insights"
    entry_point: "my_pack.commands.analyze:analyze_data"
    permissions:
      - "llm:complete"
      - "storage:write"
    timeout: 300
    queue: "long"
    retries: 3
    output_format: "json"
    deprecated: false
    deprecation_message: null

Command Field Reference

Field Type Required Default Description
name string - Command name (kebab-case)
description string - Human-readable description
entry_point string - Python entry point (module.path:function)
permissions list [] Required service permissions
timeout int 60 Max execution time (seconds)
queue enum auto Task queue: fast, medium, long, auto
retries int 3 Max retry attempts
output_format enum json Default output format
schedule string - Cron expression for scheduled execution (e.g., "0 8 * * 1-5")
deprecated bool false Mark command as deprecated
deprecation_message string - Message shown for deprecated commands
resources object - Resource requirements (see below)

Scheduled Commands

Commands can declare a schedule field with a standard cron expression. The platform's Celery Beat scheduler checks every minute and dispatches commands whose schedule is due.

# pseudocode — scheduled command configuration
commands:
  - name: "daily-research"
    description: "Fetch and summarize daily news"
    timeout: 300
    queue: "medium"
    schedule: "0 8 * * 1-5"    # Mon-Fri at 8:00 AM UTC

When a scheduled command runs, ctx.cron.is_scheduled is True and ctx.cron.schedule contains the cron expression. On-demand invocations of the same command have ctx.cron.is_scheduled set to False.

Cron Expression Format: Standard five-field format: minute hour day-of-month month day-of-week. Examples:

Expression Description
* * * * * Every minute
0 8 * * 1-5 Weekdays at 8:00 AM
0 0 1,15 * * 1st and 15th of month at midnight
*/15 * * * * Every 15 minutes

Requirements: Commands with a schedule field must also declare cron in services.

Resources Configuration

Specify resource requirements for command execution:

commands:
  - name: "heavy-analysis"
    description: "Analyze large datasets"
    resources:
      tier: "standard"        # standard | compute | gpu
      timeout_seconds: 300    # Max execution time
      memory_hint: "256MB"    # Helps platform optimize scheduling
      cpu_hint: "0.5"         # Relative CPU weight (0.1 - 2.0)
Field Type Default Description
tier enum standard Worker tier: standard, compute, gpu
timeout_seconds int 60 Max execution time in seconds
memory_hint string - Expected memory usage (e.g., "256MB", "1GB")
cpu_hint string - Relative CPU intensity (0.1 - 2.0)

Tier Reference

Tier Memory CPU Status Use Case
standard 512 MB 0.5 cores Production Standard commands, API calls
compute 2 GB 1 core Future Data processing, file operations
gpu 8 GB + GPU 2 cores Future ML inference, image processing

Current Status (Year 1): - Only standard tier is available - compute and gpu tiers are planned for future releases - The tier field is accepted for forward compatibility but does not currently affect worker routing - All commands run on standard tier workers (512MB RAM, 0.5 CPU) - Future versions will use these hints for intelligent worker pool assignment

Queue Options

Queue Max Duration Use Case
fast 30 seconds Quick lookups, simple operations
medium 5 minutes Standard operations (default)
long 8 hours LLM calls, complex processing, batch jobs
auto Varies Automatically determined (default)

Automatic Queue Assignment

When queue: auto (or omitted), Huitzo automatically determines the optimal queue based on execution statistics collected during development.

How It Works

┌─────────────────────────────────────────────────────────────────┐
│  1. During `huitzo pack dev` and `huitzo pack test`                       │
│     → Execution times are collected per command                 │
│                                                                  │
│  2. During `huitzo pack build`                                        │
│     → Statistics computed: p50, p95, max execution time         │
│     → Embedded in pack metadata                                  │
│                                                                  │
│  3. At runtime (production)                                      │
│     → Platform uses 2-5x multiplier on p95 time                 │
│     → Assigns to appropriate queue                               │
└─────────────────────────────────────────────────────────────────┘

Queue Selection Algorithm

def select_queue(p95_time: float) -> str:
    estimated_max = p95_time * 3  # 3x safety multiplier

    if estimated_max <= 5:
        return "fast"
    elif estimated_max <= 60:
        return "medium"
    else:
        return "long"

Viewing Statistics

After running huitzo pack test, view collected statistics:

$ huitzo stats

Command Statistics (from 47 test runs):

COMMAND              P50      P95      MAX      QUEUE (auto)
get-user            0.02s    0.05s    0.08s    fast
analyze-data        2.10s    4.50s    6.20s    medium
generate-report    12.30s   45.00s   62.00s   long

Overriding Auto-Assignment

To force a specific queue, set it explicitly:

commands:
  - name: "my-command"
    queue: "long"  # Force long queue regardless of stats

When to override: - Commands with highly variable execution time - Commands that call external APIs with unpredictable latency - Commands that must run in a specific queue for operational reasons

Permissions

Permissions control which platform services a command can access:

permissions:
  - "llm:complete"      # LLM completion API
  - "llm:stream"        # LLM streaming API
  - "email:send"        # Send emails
  - "telegram:send"     # Send Telegram messages
  - "storage:read"      # Read from storage
  - "storage:write"     # Write to storage
  - "http:request"      # Make external HTTP requests
  - "files:read"        # Read uploaded files
  - "files:write"       # Write files
  - "mcp:call"          # Call MCP server tools
  - "ssh:execute"       # Execute commands on SSH targets

Best Practice: Request only the permissions your command needs. Users see required permissions before installing.


Data Types Section

Define the types of data your pack stores. This helps with data management, TTL policies, and documentation.

data_types:
  - name: "conversations"
    description: "Chat conversation history"
    ttl_days: 90
    scope: "user"

  - name: "settings"
    description: "User preferences and settings"
    ttl_days: null  # Never expires
    scope: "user"

  - name: "cache"
    description: "Temporary calculation cache"
    ttl_days: 1
    scope: "tenant"

Data Type Field Reference

Field Type Required Default Description
name string - Data type identifier
description string - Human-readable description
ttl_days int/null null Days until auto-deletion (null = never)
scope enum user Data isolation scope

Scope Options

Scope Description Use Case
user Per-user data, fully isolated User preferences, history
tenant Shared within organization Team settings, shared caches
pack Shared across all users of pack Global pack configuration

Services Section

Declare external service dependencies and configuration requirements.

services:
  llm:
    required: true
    models:
      - "gpt-4o-mini"
      - "gpt-4o"
      - "claude-sonnet"
    default_model: "gpt-4o-mini"

  email:
    required: false

  telegram:
    required: false

  http:
    required: true
    allowed_domains:
      - "api.example.com"
      - "data.example.org"

LLM Service Configuration

services:
  llm:
    required: true
    models:                    # Supported models
      - "gpt-4o-mini"
      - "gpt-4o"
      - "claude-sonnet"
      - "claude-haiku"
    default_model: "gpt-4o-mini"  # Default if not specified
    max_tokens: 4096              # Max tokens per request
    temperature: 0.7              # Default temperature

HTTP Service Configuration

services:
  http:
    required: true
    allowed_domains:           # Whitelist of allowed domains
      - "api.example.com"
      - "*.example.org"        # Wildcard supported
    timeout: 60                # Default timeout
    max_redirects: 5           # Max redirect follows

Service Reference

Service Description Configuration Options
llm Large Language Model API models, default_model, max_tokens, temperature
email Email sending service (none)
telegram Telegram bot integration (none)
http External HTTP requests allowed_domains, timeout, max_redirects
cron Scheduled task execution Per-command schedule field (cron expression)
files File upload/download max_size_mb, allowed_types
db Postgres / MySQL connectors (none — paired with top-level db_integrations allowlist)

Database Service Configuration

Declare services: db: {} to receive a ctx.db client at runtime. Combine with a top-level db_integrations list to allow only specific tenant-registered postgres / mysql Integration rows by name (omit the list to allow any tenant-visible DB integration):

# huitzo.yaml — pseudocode
services:
  db: {}
db_integrations:
  - "primary"
  - "warehouse"

The actual connection details (host, port, credentials, TLS, allow_ddl, row_limit) live on the Integration row in the registry — packs never see or edit them. See Integrations Reference → Database Integration for the runtime API and security limits.


MCP Servers Section

The mcp_servers section declares external MCP (Model Context Protocol) servers that your pack can connect to. MCP provides a standardized way to integrate with external tools and services.

Key Concept: Huitzo consumes MCP servers—it does not expose itself as an MCP server. MCP tools become callable via ctx.mcp in your commands. No LLM required—this is pure protocol translation.

Basic Configuration (STDIO)

For MCP servers that run as local subprocesses:

mcp_servers:
  - name: github
    type: stdio
    command: ["uvx", "mcp-server-github"]
    env:
      GITHUB_TOKEN: "${secrets.GITHUB_TOKEN}"

HTTP+SSE Configuration (Remote)

For MCP servers accessible over HTTP:

mcp_servers:
  - name: postgres-remote
    type: http
    url: "https://mcp.example.com/postgres"
    headers:
      Authorization: "Bearer ${secrets.MCP_API_KEY}"
    timeout: 30

Transport Types

Type Description Use Case
stdio Local subprocess, communicates via stdin/stdout CLI tools, local servers
http Remote HTTP endpoint with SSE streaming Hosted MCP servers, enterprise gateways

STDIO Transport Field Reference

Field Type Required Default Description
name string Unique server identifier (kebab-case)
type string Must be "stdio"
command list[str] Command and arguments to spawn
env dict {} Environment variables (supports ${secrets.NAME})
working_dir string Pack root Working directory for subprocess

HTTP+SSE Transport Field Reference

Field Type Required Default Description
name string Unique server identifier (kebab-case)
type string Must be "http"
url string Server endpoint URL (https required in production)
headers dict {} HTTP headers (supports ${secrets.NAME})
timeout int 30 Request timeout in seconds

Secret Interpolation

Use ${secrets.NAME} syntax to reference user secrets:

mcp_servers:
  - name: github
    type: stdio
    command: ["uvx", "mcp-server-github"]
    env:
      GITHUB_TOKEN: "${secrets.GITHUB_TOKEN}"    # From user secrets
      GITHUB_ENTERPRISE_URL: "${secrets.GH_URL}" # Optional enterprise URL

secrets:
  user_required:
    - name: "GITHUB_TOKEN"
      description: "Your GitHub personal access token"
      help_url: "https://github.com/settings/tokens"
  user_optional:
    - name: "GH_URL"
      description: "GitHub Enterprise URL (optional)"

Multiple Servers Example

mcp_servers:
  # Local GitHub MCP server
  - name: github
    type: stdio
    command: ["uvx", "mcp-server-github"]
    env:
      GITHUB_TOKEN: "${secrets.GITHUB_TOKEN}"

  # Local PostgreSQL MCP server
  - name: postgres
    type: stdio
    command: ["uvx", "mcp-server-postgres"]
    env:
      DATABASE_URL: "${secrets.DATABASE_URL}"

  # Remote Slack MCP server
  - name: slack
    type: http
    url: "https://mcp.company.com/slack"
    headers:
      Authorization: "Bearer ${secrets.SLACK_MCP_TOKEN}"

Usage in Commands

Access MCP tools via ctx.mcp:

from huitzo_sdk import command, Context

@command("create-issue", namespace="devtools")
async def create_issue(args: Args, ctx: Context) -> dict:
    """Create a GitHub issue using MCP."""
    result = await ctx.mcp.call(
        server="github",
        tool="create_issue",
        arguments={
            "owner": args.owner,
            "repo": args.repo,
            "title": args.title
        }
    )
    return {"issue_number": result["number"]}

Validation Rules

Rule Requirement
Server name Unique within pack, kebab-case, 1-64 characters
Command array Non-empty list of strings (STDIO only)
URL format Valid HTTPS URL (HTTP only in development)
Timeout 1-300 seconds

SSH Targets Section

The ssh_targets section declares which user-registered SSH targets your pack can access via ctx.ssh.run(). This enables packs to orchestrate tasks on user-owned hardware (GPU clusters, custom servers, on-premise machines).

Allow All Targets

ssh_targets:
  allowed:
    - "*"          # Allow all user-registered targets

Restrict to Specific Targets

ssh_targets:
  allowed:
    - "gpu-cluster"
    - "preprocessing-server"

Field Reference

Field Type Required Default Description
allowed list[str] [] Target names the pack can access. ["*"] = allow all.

Behavior

  • If ssh_targets is omitted, the pack cannot use ctx.ssh (equivalent to allowed: [])
  • If allowed contains "*", the pack can access all targets the user has registered
  • If allowed contains specific names, only those targets are accessible
  • Target names must match the name field used when registering the target

Example: ML Training Pack

pack:
  name: "ml-trainer"
  namespace: "ml"
  version: "1.0.0"
  description: "Train and deploy ML models on your GPU clusters"

commands:
  - name: "train"
    description: "Train a model on remote GPU"
    permissions: ["storage:write"]
    timeout: 3600
    queue: "long"

ssh_targets:
  allowed:
    - "*"          # User decides which GPUs to use

Security Model

Pack manifests create an allowlist that restricts which SSH targets a pack can access:

  1. User registers targets (e.g., "gpu-cluster", "web-server", "db-server")
  2. Pack declares ssh_targets.allowed: ["gpu-cluster"]
  3. At runtime, ctx.ssh.run("gpu-cluster", ...) succeeds
  4. ctx.ssh.run("web-server", ...) raises SSHError — not in pack's allowlist

This ensures packs can only access infrastructure the user has explicitly registered and the pack has explicitly declared.

See SSH Integration and SSH Targets Guide for complete documentation.


Secrets Section

The secrets section declares external API keys and credentials that users must provide to use your pack. This enables the three-tier secrets management system.

Three-Tier Secrets Model

Tier Owner Scope Access Method
Platform Admin All packs ctx.env.require("OPENAI_API_KEY")
Pack Developer Single pack Pack configuration
User End User User + Pack ctx.secrets.require("API_KEY")

User Secrets Configuration

secrets:
  user_required:
    - name: "FINANCIAL_API_KEY"
      description: "Your API key from massive.com"
      help_url: "https://massive.com/developers/api-keys"

    - name: "TRADING_API_SECRET"
      description: "Trading platform secret key"
      help_url: "https://trading.example.com/api"

  user_optional:
    - name: "PREMIUM_API_KEY"
      description: "Optional premium tier API key for enhanced features"

Secret Field Reference

Field Type Required Description
name string Environment variable name (UPPER_SNAKE_CASE)
description string Human-readable description shown to users
help_url string Link to documentation for obtaining the key

Required vs Optional Secrets

Required Secrets (user_required): - Pack will not install until user provides these secrets - Accessing a missing required secret raises SecretsError - Users are prompted during pack installation

Optional Secrets (user_optional): - Pack installs without these secrets - Use ctx.secrets.get() with fallback behavior - Enable premium or enhanced features

Accessing User Secrets in Commands

from huitzo_sdk import command, Context
from huitzo_sdk.errors import SecretsError

@command("fetch-data", namespace="finance")
async def fetch_data(args: Args, ctx: Context) -> dict:
    # Required secret - raises SecretsError if missing
    api_key = ctx.secrets.require("FINANCIAL_API_KEY")

    # Optional secret - returns None if missing
    premium_key = ctx.secrets.get("PREMIUM_API_KEY")

    # Check existence
    if ctx.secrets.exists("PREMIUM_API_KEY"):
        # Use premium features
        pass

    # Call external API with user's key
    response = await ctx.http.get(
        "https://api.massive.com/data",
        headers={"Authorization": f"Bearer {api_key}"}
    )

    return response

Security Model

User secrets are: - Encrypted at rest using platform encryption keys - Scoped to user + pack - other packs cannot access - Never logged - masked in all logs and error messages - Rotatable - users can update secrets without reinstalling

Validation Rules

Rule Requirement
Name format UPPER_SNAKE_CASE, alphanumeric + underscore
Name length 1-64 characters
Description length 10-500 characters
help_url Valid URL (https recommended)

Best Practices

  1. Clear descriptions - Tell users exactly what key they need and why
  2. Include help_url - Link to the provider's API key page
  3. Minimize required secrets - Only require what's truly necessary
  4. Document usage - Explain which commands use which secrets

See Secrets Management Reference for complete documentation.


Metadata Section

Additional metadata for discoverability and documentation.

metadata:
  homepage: "https://example.com/my-pack"
  repository: "https://github.com/example/my-pack"
  documentation: "https://docs.example.com/my-pack"
  changelog: "https://github.com/example/my-pack/blob/main/CHANGELOG.md"
  keywords:
    - "analytics"
    - "reporting"
    - "data"
  category: "business"
  icon: "chart-bar"           # Icon name (Lucide icons)
  screenshots:
    - "https://example.com/screenshot1.png"
    - "https://example.com/screenshot2.png"

Category Options

Category Description
business Business tools, CRM, analytics
developer Development tools, utilities
productivity Personal productivity, notes, tasks
finance Financial analysis, accounting
marketing Marketing automation, campaigns
communication Email, chat, notifications
data Data processing, ETL, analysis
ai AI/ML tools, model integration
other Uncategorized

Validation

The CLI validates your manifest before building:

huitzo pack validate

Validation Rules

  1. Required fields - All required fields must be present
  2. Naming conventions - Names follow kebab-case/lowercase rules
  3. Version format - Version is valid semver
  4. Command uniqueness - No duplicate command names
  5. Permission validity - All permissions are valid
  6. Service references - Services referenced in permissions exist
  7. Dashboard config - If enabled, subdomain is unique

Common Validation Errors

❌ Error: pack.name must be kebab-case
   Found: "MyPack"
   Expected: "my-pack"

❌ Error: commands[0].timeout exceeds queue limit
   Command: "slow-task" (timeout: 120)
   Queue: "fast" (max: 5s)
   Fix: Change queue to "medium" or "long"

❌ Error: Unknown permission "database:query"
   Command: "fetch-data"
   Valid permissions: llm:complete, email:send, ...

Complete Example

Here's a complete manifest for a real-world pack:

# huitzo.yaml - Financial Intelligence Pack

pack:
  name: "plutus-financial"
  namespace: "plutus"
  version: "2.1.0"
  description: "Portfolio analysis and financial reporting tools"
  visibility: "organization"
  author: "Huitzo Inc."
  license: "proprietary"
  min_sdk_version: "2.0.0"

# Deployment capabilities
deployment:
  cloud_capable: true
  self_hosted_capable: true
  edge_capable: false          # Future
  offline_capable: false       # Future
  requires_internet: true      # Needs market data APIs

# Pack-level resource requirements
resources:
  min_memory_mb: 256
  recommended_memory_mb: 512
  requires_gpu: false

# Embedded models (future edge deployment)
embedded_models: []

commands:
  - name: "analyze-portfolio"
    description: "Analyze investment portfolio performance"
    permissions:
      - "llm:complete"
      - "http:request"
      - "storage:write"
    timeout: 300
    queue: "long"
    retries: 2
    resources:
      tier: "standard"
      timeout_seconds: 300

  - name: "generate-report"
    description: "Generate PDF investment report"
    permissions:
      - "llm:complete"
      - "email:send"
      - "storage:read"
      - "files:write"
    timeout: 600
    queue: "long"
    resources:
      tier: "standard"
      timeout_seconds: 600

  - name: "get-quote"
    description: "Get current stock quote"
    permissions:
      - "http:request"
    timeout: 10
    queue: "fast"
    resources:
      tier: "standard"
      timeout_seconds: 10

  - name: "list-holdings"
    description: "List portfolio holdings"
    permissions:
      - "storage:read"
    timeout: 30
    queue: "fast"
    resources:
      tier: "standard"
      timeout_seconds: 30

data_types:
  - name: "portfolios"
    description: "User portfolio data"
    ttl_days: null
    scope: "user"

  - name: "reports"
    description: "Generated reports"
    ttl_days: 365
    scope: "user"

  - name: "market_cache"
    description: "Market data cache"
    ttl_days: 1
    scope: "tenant"

services:
  llm:
    required: true
    models: ["gpt-4o-mini", "gpt-4o"]
    default_model: "gpt-4o-mini"

  email:
    required: true

  http:
    required: true
    allowed_domains:
      - "api.polygon.io"
      - "api.alpaca.markets"

secrets:
  user_required:
    - name: "POLYGON_API_KEY"
      description: "Your Polygon.io API key for market data"
      help_url: "https://polygon.io/dashboard/api-keys"
  user_optional:
    - name: "ALPACA_API_KEY"
      description: "Alpaca Markets API key for trading data"
      help_url: "https://alpaca.markets/docs/api-references/broker-api/"

metadata:
  homepage: "https://huitzo.com/packs/plutus"
  documentation: "https://docs.huitzo.ai/packs/plutus"
  keywords: ["finance", "portfolio", "investment", "analysis"]
  category: "finance"
  icon: "trending-up"


Proposed Sections

The following manifest sections are architecturally specified but not yet supported by the runtime. They are included here for forward reference.

Integrations Section (Proposed)

Declare reusable service integrations provided by this pack. See Component Model.

# pseudocode — proposed integrations section

integrations:
  - name: "salesforce"
    class: "my_pack.integrations.salesforce:SalesforceIntegration"
    required_secrets:
      - name: "SALESFORCE_KEY"
        description: "Your Salesforce API key"
        help_url: "https://developer.salesforce.com/docs"
    allowed_domains:
      - "*.salesforce.com"
    shared_secrets: []  # secrets shared with consuming packs (empty = none)

Dependencies Section (Proposed)

Declare dependencies on other integration packs. Resolved at huitzo pack install time via topological sort. Circular dependencies are rejected. See Component Model — Pack Dependency Resolution.

# pseudocode — proposed dependencies section

dependencies:
  - pack: "@acme/salesforce-connector"
    version: ">=1.0.0"
    integrity: "sha256:abc123..."  # content hash pinning

File Mounts Section (Proposed)

Declare mountable file system drivers for VFS. See Virtual File System.

# pseudocode — proposed file_mounts section

file_mounts:
  - mount_point: "/mnt/s3-reports"
    driver: "s3"
    config:
      bucket: "company-reports"
      region: "us-east-1"
    required_secrets:
      - "AWS_ACCESS_KEY_ID"
      - "AWS_SECRET_ACCESS_KEY"

Events Section (Proposed)

Declare events published and subscribed to by this pack. See Event Bus.

# pseudocode — proposed events section

events:
  publishes:
    - type: "invoice.received"
      description: "Emitted when an invoice is detected in email"
      payload_schema:
        sender: "string"
        amount: "number"

  subscribes:
    - type: "invoice.received"
      handler: "my_pack.handlers:on_invoice_received"
      max_concurrency: 5

Pipelines Section (Proposed)

Declare command pipelines. See Piping Protocol.

# pseudocode — proposed pipelines section

pipelines:
  invoice-processor:
    description: "Extract invoice data from email"
    timeout: 300
    stages:
      - command: "source:scan-inbox"
        config:
          filter: "subject:invoice"
      - command: "action:extract-fields"
      - command: "dest:save-to-sheet"

Config Section (Proposed)

Declare pack-level configuration defaults for the hierarchical config cascade. See Component Model — Hierarchical Configuration.

# pseudocode — proposed config section

config:
  http.timeout: 60
  http.max_retries: 5
  llm.default_model: "gpt-4o"

commands:
  - name: "heavy-report"
    config:
      http.timeout: 300  # command-level override