Reusable packs
A pack is reviewed reusable workflow content. It is not an in-process native
plugin. The manifest API is agentctl.dev/pack/v1alpha1 and uses a fully
qualified dotted name, semantic version, agentctl compatibility constraint,
optional dependencies, and exported actions, agents, tools, and sub-workflows.
Sources and resolution
Section titled “Sources and resolution”Workflow roots and transitive dependencies use an exact source:
packs: - name: example.utility version: "^1.0" source: path: packs/example.pack.yamlSupported sources are:
- a contained local
path; - a Git
httpsURL with a full 40-characterrevand containedmanifest; - an immutable
httpstar-gzip archive URL with SHA-256integrityand a containedmanifest.
Loopback HTTP and contained file: Git URLs exist only for deterministic local
fixtures. URLs with credentials, query parameters, or fragments are rejected.
Git branches and tags are not accepted as revisions. Archive redirects,
symlinks, hardlinks, special files, path escapes, more than 1,024 entries,
compressed content over 16 MiB, and expanded content over 64 MiB are rejected.
Each dependency names its source and semantic constraint:
dependencies: example.base: version: "^2.1" source: git: https://github.com/example/base-pack.git rev: 0123456789abcdef0123456789abcdef01234567 manifest: agentctl.pack.yamlResolution is deterministic because every requirement identifies one immutable
candidate. Conflicting versions or sources, duplicate identities, missing
dependencies, and cycles fail with validation exit 2. There is no hosted
registry and no implicit search order.
Lockfile workflow
Section titled “Lockfile workflow”Generate and commit agentctl.pack.lock beside the workflow:
agentctl packs lock workflow.yamlagentctl packs verify-lock workflow.yaml --lockedagentctl packs update workflow.yamlagentctl packs update workflow.yaml --pack example.utilityThe lock API is agentctl.dev/pack-lock/v1. It records agentctl compatibility,
pack identity and concrete version, exact source, manifest digest, dependency
edges, signature metadata, and trust result. Entries are sorted by pack name.
An update resolves the complete graph; --pack validates and identifies the
requested root while preserving graph-wide consistency.
Execution uses the lock whenever it exists. --locked requires it and rejects
workflow, source, graph, digest, compatibility, signature, trust, or unreachable
entry drift. --offline permits local paths and requires Git/archive cache
hits. Legacy exact path plus integrity references remain readable without a
lock and emit a migration warning.
Integrity and trust
Section titled “Integrity and trust”SHA-256 binds the lock to exact bytes. It proves sameness, not publisher identity. Optional keyless publisher verification uses the standard Sigstore bundle format and the embedded Sigstore public-good trust root:
packTrust: unsigned: deny identities: - identity: https://github.com/example/repository/.github/workflows/release.yml@refs/tags/v1.2.0 issuer: https://token.actions.githubusercontent.compacks: - name: example.utility version: "=1.2.0" source: path: packs/example.pack.yaml signature: bundle: packs/example.pack.sigstore.json identity: https://github.com/example/repository/.github/workflows/release.yml@refs/tags/v1.2.0 issuer: https://token.actions.githubusercontent.comVerification checks the artifact signature, certificate chain, identity, issuer, transparency-log proof, signed timestamp, and locked bundle digest. The bundle is sufficient for offline cryptographic verification, subject to the freshness of the trust root embedded in the installed agentctl version. See the Sigstore bundle model and Cosign blob verification.
packTrust.unsigned is deny, warn, or allow, with warn as the default.
Unsigned process-capable packs are always blocked unless
allowUnsignedProcess: true is also explicit. That exception is a review
acknowledgement, not proof of publisher identity or process isolation.
Manifest policy defaults remain inspectable metadata and never weaken the
invoking workflow policy. Exported definitions are qualified as
<pack-name>.<item-name> before compilation.
Verification evidence
Section titled “Verification evidence”Unit fixtures cover semantic constraints, deterministic ordering, conflicts, cycles, path containment, tamper, locked drift, pinned Git cache reuse, offline misses, bounded archives, archive links, valid and invalid Sigstore bundles, identity policy, unsigned process denial, and dependency reachability. Packaged acceptance scenario 42 verifies the checked-in transitive example, locks an extension pack, proves that its process cannot start before explicit trust authorization, executes it once, and replays without another invocation.
Canonical source:
docs/PACKS.md. Verified against agentctl commit2aeaa88fba71162206b5f08f5bda4f0150247e4f.