Packs and Distribution
Install providers, handlers, workflows, and more through the pack system.
Autopilot distributes reusable integration material through packs — versioned bundles that install into your .autopilot/ directory via autopilot sync.
What is a pack
A pack is a distribution unit. It can contain any combination of:
- Providers — integration instance configs
- Handlers — executable Bun adapter scripts
- Workflows — step progression definitions
- Skills — agent skill definitions
- Prompts — reusable prompt templates
- Context — company/project documentation
- MCP config — tool surface setup
A pack is not a plugin runtime. It materializes files into your repo. Once installed, those files are normal .autopilot/ config — editable, reviewable, and version-controlled.
Pack manifest
Every pack has a pack.yaml that declares what it contains and what it needs:
id: telegram-surface
name: Telegram Surface
category: surface
version: 1.0.0
description: >
Telegram bot surface for Autopilot.
Outbound notifications with inline buttons,
inbound approve/reject/reply via webhook.
files:
- src: providers/telegram.yaml
dest: providers/telegram.yaml
- src: handlers/telegram.ts
dest: handlers/telegram.ts
required_env:
- name: TELEGRAM_BOT_TOKEN
description: Telegram Bot API token from @BotFather
- name: TELEGRAM_CHAT_ID
description: Default Telegram chat ID for notifications
- name: TELEGRAM_WEBHOOK_SECRET
description: Shared secret for webhook authentication
manual_steps:
- description: "Create a Telegram bot via @BotFather and obtain the bot token"
- description: "Set the webhook URL pointing to your orchestrator"
- description: "Create a conversation binding for your task chat"Pack categories: surface, workflow, provider, context, skill
Declaring packs
Desired packs are declared in .autopilot/company.yaml:
name: "My Company"
slug: my-company
# ...
packs:
- ref: questpie/telegram-surfaceThis is authored desired state — it says "I want this pack installed." It does not contain resolved versions or managed file lists.
Registries
Packs are resolved from registries — currently git-backed repositories.
Registry config lives in two places:
| Location | Scope |
|---|---|
~/.config/autopilot/registries.yaml | User-global (all repos) |
.autopilot/registries.yaml | Repo-local (this project only) |
Example:
registries:
- id: questpie
type: git
url: https://github.com/questpie/autopilot-packs.gitCredentials use your existing git credential helper or SSH agent. No credentials are stored in the repo.
The lockfile
After autopilot sync, a lockfile records the resolved install state:
# .autopilot/packs.lock.yaml — derived state, not authored
packs:
telegram-surface:
ref: questpie/telegram-surface
registry: questpie
resolved_ref: questpie/telegram-surface
commit: abc123def456
installed_at: "2026-04-01T10:00:00Z"
managed_files:
- providers/telegram.yaml
- handlers/telegram.tsThe lockfile is a map keyed by pack ID. Each entry tracks:
- The original ref from
company.yaml - Which registry resolved it
- The resolved ref and exact commit
- Which files it manages
- When it was installed
This is derived state — generated by autopilot sync, not edited by hand. It prevents silent overwrite of locally modified pack-managed files.
autopilot sync
autopilot sync is the single command for all pack operations:
autopilot syncIt performs:
- Resolve — read
company.yamlpack refs and find them in configured registries - Fetch — download pack contents from the resolved registry source
- Materialize — copy pack files into
.autopilot/at their declared destinations - Write lockfile — update
packs.lock.yamlwith resolved state
Conflict handling
In V1, autopilot sync refuses ambiguous overwrites. If a pack wants to write a file you have locally modified (and the lockfile records it as pack-managed), the sync stops and asks you to resolve the conflict.
Root repo files under .autopilot/ always win over pack defaults. Packs provide installable starting points; you take ownership by editing.
Install modes
| Mode | Behavior |
|---|---|
| Strict | Deterministic: resolve, materialize, write lock, refuse ambiguous overwrites |
| AI-assisted | Operator mode for complex setup (choosing variants, adapting templates, wiring config). Must still produce materialized files + updated lockfile |
AI-assisted install may customize during setup, but the end result is always inspectable files in .autopilot/ plus an updated lockfile. The AI does not own hidden state.
What packs are not
- Not
node_modules. Packs materialize into your repo as normal files. There is no hidden dependency tree. - Not a marketplace. Registries are git repos you configure. There is no central store with ratings and downloads.
- Not a plugin runtime. Packs do not run code at install time. They deliver files. Handlers run at invocation time through the normal provider runtime.
Current state
The pack system is operational:
- Pack manifests (
pack.yaml) are real - Git-backed registries work
autopilot syncresolves, fetches, materializes, and writes lockfiles- Conflict detection prevents silent overwrites
- The Telegram surface pack is the first real distributed pack
Not yet implemented:
- npm registry backend (git-first is the foundation)
- Pack discovery/search beyond configured registries
- Pack versioning beyond git commit resolution
- AI-assisted install mode (strict mode works today)
Related docs
- Providers and Handlers — what packs typically install
- Telegram Surface — the first real surface pack example
- Architecture — where packs fit in the truth model