> ## Documentation Index
> Fetch the complete documentation index at: https://usefused.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a project pack

> Declare a company pack with typed input options and a validated configuration file.

Define a pack in a Python package installed alongside your company CLI. Keep this package outside the agent repository so the deployed agent does not acquire authoring-only dependencies.

## Generate a starter pack

Create a Python pack and an editable compile manifest together:

```bash theme={null}
harnest pack init acme --output ./acme-pack
```

Omit `--output` to use `./acme-pack`. The name must begin with a lowercase letter and contain only lowercase letters, digits, or hyphens, with a maximum of 63 characters. `harnest` is reserved. The destination must not already exist; the command never overwrites an existing team pack.

```text theme={null}
acme-pack/
  pack.py
  harnest-compile.yaml
  team-guide.md
```

| Generated file         | What to customize                                                              |
| ---------------------- | ------------------------------------------------------------------------------ |
| `pack.py`              | Pack identity, initialization, migrations, and the company's CLI.              |
| `harnest-compile.yaml` | Optional dependency groups selected for compilation.                           |
| `team-guide.md`        | Team documentation copied unchanged to `docs/team-guide.md` in each new agent. |

The generated manifest starts with:

```yaml theme={null}
version: 1
extras: []
```

Run the Python file with the Harnest SDK installed in your authoring Python environment and the Harnest CLI on `PATH`:

```bash theme={null}
python ./acme-pack/pack.py init ./sales --minimal
harnest compile ./sales --format executable --output ./dist/sales-agent
```

To start from your team's existing agent template, use:

```bash theme={null}
python ./acme-pack/pack.py init ./sales --template acme-sales
```

The template is prepared first, then the pack initializer runs against its files. See [template initialization](/docs/harnest/build/project-packs/cli#initialize-from-a-template) for checksum pins and option compatibility.

On Windows, use an output name ending in `.exe`. Set `HARNEST_CLI` to your Harnest executable path if it is not on `PATH`.

The initializer copies the manifest and sample documentation into each new agent. The guide stays at `docs/team-guide.md` for teammates to read and is excluded from compilation. It does not become an agent instruction or skill. Use an agent template for standard `instructions.md`, skills, and other required agent structure. A team's custom CLI can also install internal-service extensions using Harnest's existing extension commands.

Adding an extra requires the corresponding `[project.optional-dependencies]` entry in the generated agent's `pyproject.toml`. The compile manifest controls dependency selection only; it does not package arbitrary project files.

Edit these files before creating agents. To update existing agents, increment `schema_version`, add a [migration](/docs/harnest/build/project-packs/migrations), and run `python ./acme-pack/pack.py upgrade ./sales --apply`. Initializers do not run again during upgrade.

You can later move this starter into your team's Python package and expose `main` through a [company CLI](/docs/harnest/build/project-packs/cli) console entry point. Include both template files beside `pack.py` in the installed package. Harnest compiles agents; the pack remains authoring code.

## Start with a typed definition

This first release accepts a team name and writes it to the company's `owner` field. The [migration example](/docs/harnest/build/project-packs/migrations) later renames that field to `team`.

```python pack.py theme={null}
from enum import Enum
from pydantic import BaseModel, Field
from harnest.authoring import ChangePlan, ProjectContext, ProjectPack

class Environment(str, Enum):
    DEVELOPMENT = "development"
    PRODUCTION = "production"

class Options(BaseModel):
    team: str = Field(min_length=1, description="Team responsible for this agent")
    environment: Environment = Environment.DEVELOPMENT

class Settings(BaseModel):
    owner: str = Field(min_length=1)
    environment: Environment

pack = ProjectPack(
    name="acme",
    schema_version=1,
    options=Options,
    config_file="acme-agent.yaml",
    config_model=Settings,
)

@pack.initialize
def initialize(context: ProjectContext) -> ChangePlan:
    return ChangePlan(
        context.yaml.set(
            "acme-agent.yaml", key=("owner",), value=context.options.team,
        ),
        context.yaml.set(
            "acme-agent.yaml",
            key=("environment",),
            value=context.options.environment.value,
        ),
    )
```

`Options` validates values supplied by the caller. `Settings` validates the resulting company file after that pack's hooks finish. They serve different purposes: an upgrade can validate existing settings without asking the user to repeat their init options.

## Pack properties

| Property         | Required            | Contract                                                                                                                |
| ---------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `name`           | Yes                 | A unique kebab-case identifier beginning with a letter, up to 63 characters. `harnest` is reserved.                     |
| `schema_version` | Yes                 | A positive integer identifying the company configuration schema. Track it separately from your package release version. |
| `options`        | No                  | A Pydantic model for caller-supplied inputs.                                                                            |
| `templates`      | No                  | A directory containing inert UTF-8 [templates](/docs/harnest/build/project-packs/changes#templates).                         |
| `config_file`    | With `config_model` | The project-relative company configuration path.                                                                        |
| `config_model`   | With `config_file`  | A Pydantic model that validates the resulting configuration mapping.                                                    |

Keep company properties in a separate file such as `acme-agent.yaml`. Use existing Harnest fields when changing Harnest configuration; arbitrary company fields do not extend Harnest's configuration schema.

## Package templates

A pack that generates a company workflow could have this structure:

```text theme={null}
acme_agent_pack/
  __init__.py
  pack.py
  cli.py
  templates/
    ci.yml
```

Pass `templates=Path(__file__).parent / "templates"` to `ProjectPack`, and include the files in your package's build configuration. Templates are read as data; Harnest does not import or execute them.

## Declare compilation dependencies

Use ordinary pack operations to maintain optional dependency selections:

```python theme={null}
@pack.initialize
def initialize(context: ProjectContext) -> ChangePlan:
    """Select the team's optional integration dependencies for compilation."""
    return ChangePlan(
        context.yaml.set("harnest-compile.yaml", key=("version",), value=1),
        context.yaml.set("harnest-compile.yaml", key=("extras",), value=["crm"]),
    )
```

Declare the matching `[project.optional-dependencies].crm` group in the agent's `pyproject.toml`, for example through the team's agent template. Package versions remain in Python metadata. The compile manifest does not accept `resources`.

When changing existing agents, add a versioned pack migration for the declarations. Generated-file and YAML ownership rules still apply: coordinate shared lists between packs rather than having multiple packs claim the same key. Compilation reads only the resulting declarations and files; it does not import the pack or execute its migrations. Your authoring package does not need to ship with the agent.

See [compilation selections and reports](/docs/harnest/build/testing-and-compilation#select-compilation-dependencies) for dependency selection, compiled content, and shared-runtime behavior.

## Choose what runs

Pass installed pack objects explicitly to [`ProjectCLI`](/docs/harnest/build/project-packs/cli) or [`ProjectPlanner`](/docs/harnest/build/project-packs/plans-and-recovery). Harnest does not discover packs from package names in a project file.

<Note>
  Pack callbacks are trusted Python, not sandboxed code. Keep them deterministic and free of filesystem or network side effects. A preview can execute callbacks multiple times without applying any changes.
</Note>

Continue with the [`@pack.initialize` reference](/docs/harnest/build/project-packs/initialize) or [build your company CLI](/docs/harnest/build/project-packs/cli).
