For the complete documentation index, see llms.txt.

Getting started with skill hardening

Upload an agent skill for hardening, track the job, browse results in user folders, and review the report before installing the skill.
  7 min read

Use chainctl skills harden to upload an agent skill, submit it for server-side hardening, and download the result with a report of the changes and scanner findings. You can submit a local directory or harden an artifact you have already pushed to your organization’s uploads registry.

This guide builds on Getting started with the Chainguard Skills Registry, covering hardening and job tracking before you install the skill.

Note: Chainguard Agent Skills is in beta.

Prerequisites

You need:

Set up your organization

In the commands below, replace your-organization with your organization’s name or UIDP (its unique identifier).

If onboarding is not already complete, an organization administrator with skills.entitlements.create and terms.accept permissions runs:

chainctl skills entitlements create --parent your-organization
chainctl skills accept-terms --group your-organization

Review and accept the terms in the interactive prompt. To check whether the organization already has an entitlement, run:

chainctl skills entitlements list --parent your-organization

An entitlement enables access to the service. Its presence does not indicate that a skill has been uploaded or hardened.

Check your chainctl version

Check that your chainctl version includes the commands:

chainctl skills harden --help
chainctl skills status --help

The harden help should show --folder, --digest, --wait, and --timeout. If it shows only the generic skills help, update chainctl.

Create and validate an example skill

Create a small skill that produces a release checklist:

mkdir harden-demo
cat > harden-demo/SKILL.md <<'EOF'
---
name: harden-demo
description: Write a short release checklist when the user asks to prepare a software release.
license: Apache-2.0
---

Ask the user for the project name and intended release version if either is missing.
Return a checklist covering tests, release notes, and the release owner.
Use only information provided by the user. Mark missing details as "to confirm".
EOF

chainctl skills validate ./harden-demo

The directory name must match the frontmatter name. Keep the directory within the 10 MB limit. Validation checks the skill’s structure locally; the hardening pipeline performs the subsequent review and evaluation.

Harden a local directory

From the directory containing harden-demo, run:

chainctl skills harden ./harden-demo --group your-organization --wait --timeout 30m

The command packages and uploads the directory, submits a hardening job, prints its ID, and waits for completion. --folder ./harden-demo is equivalent to the positional directory argument. A separate skills push is unnecessary for this workflow.

The examples use the production registries. chainctl uploads to uploads.cgr.dev by default in production; no registry environment variable is required.

On success, the command prints the hardened artifact’s reference and digest and downloads it into ./hardened/harden-demo/. The download includes SKILL.md, any supporting files, and HARDENING.md with the hardening report and findings.

The hardened artifact is published under the submitting user’s namespace:

skills.cgr.dev/<org-uidp>/users/<user-namespace>/harden-demo@sha256:<digest>

The service generates the user namespace. Save the exact reference returned by the command, including users/<user-namespace>/ and the digest, for subsequent pulls or installs.

Submit now and check later

Omit --wait to return after submission. Use -o id to capture the job ID:

JOB_ID=$(chainctl skills harden ./harden-demo --group your-organization -o id)
chainctl skills status --group your-organization --id "$JOB_ID"

To resume waiting and download the result:

chainctl skills status --group your-organization --id "$JOB_ID" --wait --timeout 30m

--id takes the 64-character job ID, without a sha256: prefix or an operation path. Repeating a submission with the same organization, user, skill name, and content digest returns the same job. Use status when you only need to check progress.

--timeout requires --wait and bounds the waiting command, including its other work. A timeout or Ctrl-C stops the local command; it does not cancel the server-side job. Resume with the saved ID. A pipeline failure exits nonzero and prints its failure reason.

Harden an existing upload

You can also push a tagged artifact first and then explicitly request hardening:

chainctl skills push ./harden-demo --group your-organization --tag v1.0.0
chainctl skills list --group your-organization --source uploads

chainctl skills harden uploads.cgr.dev/your-organization/harden-demo:v1.0.0 \
  --group your-organization --wait --timeout 30m

push stores the original artifact in uploads.cgr.dev. Use harden to submit it for hardening and status to track the job. A successful push does not mean that a hardened result is available in skills.cgr.dev.

The upload must be in the same organization passed to --group. This command accepts a reference at <uploads-host>/<org>/<skill-name>; use the organization root when pushing an artifact you intend to harden this way.

To select the exact artifact from the push output, use its digest instead:

chainctl skills harden --group your-organization --name harden-demo \
  --digest 'sha256:<64-hex-digest-from-push>' --wait --timeout 30m

--digest requires --name and takes only the digest, not a tag or full registry reference. Choose one input form per invocation: a path, --folder, an uploads reference, or --digest with --name.

Browse results in user folders

Why do I only see a users folder?

By default, chainctl skills list reads the hardened registry (--source skills) and shows only the immediate folders and skills at the selected level. For example:

chainctl skills list --group your-organization
     SOURCE     |  TYPE  | NAME  | TAGS | UPDATED
----------------|--------|-------|------|---------
 skills.cgr.dev | folder | users | --   | --

users is a registry folder containing namespaces for users who submit skills for hardening. A row with TYPE set to folder has no skill tag or update time, so those columns show --. The folder row alone does not tell you whether a hardening job has completed or whether your skill is inside it.

Hardened results are organized like this:

skills.cgr.dev/<org-uidp>/
└── users/
    └── <user-namespace>/
        └── harden-demo

Each submitting user has a separate namespace, so different users can harden a skill with the same name without sharing a repository path.

Expand all user folders

Add --recursive (or -r) to include skills from every nested folder in the listing:

chainctl skills list --group your-organization --source skills --recursive

The NAME column shows the full path relative to the organization, such as users/<user-namespace>/harden-demo. Repeating the default non-recursive command continues to show only the top-level folder.

The TAGS column lists all tags for each skill, including version tags and generated hardening tags. Skills without tags are also listed, with -- in that column. The CLI does not require a latest tag. MCP skill discovery uses latest, so its results can differ from the CLI listing.

To browse one level at a time, append the registry folder path to --group:

chainctl skills list --group your-organization/users
chainctl skills list --group "your-organization/users/<user-namespace>"

Replace <user-namespace> with a folder name returned by the first command. These paths select registry folders; they do not refer to directories on your machine.

Find a skill after pushing it

If push returned an uploads.cgr.dev reference, select the uploads source to browse that registry:

chainctl skills list --group your-organization --source uploads --recursive

To browse uploads and hardened results in one listing:

chainctl skills list --group your-organization --source all --recursive

Use the SOURCE column to distinguish the registries:

Source optionRegistryContents
--source skills (default)skills.cgr.devHardened skills, including skills in user namespaces.
--source uploadsuploads.cgr.devOriginal uploads.
--source allBoth registriesSkills from either source, labeled by registry.

If you have only run push, follow Harden an existing upload. If you already submitted a hardening job, use chainctl skills status --group your-organization --id "$JOB_ID" to check it. An entitlement listing or a users folder row is not a job status check.

Find a skill that is missing from the listing

First, check the source and folder: use --source uploads for an uploaded original, --source skills for a hardened result, and --recursive to include nested skills.

Older chainctl builds display a LATEST TAG column and omit skills without a latest tag. This can hide version-tagged uploads and completed hardening results. Update chainctl to use the listing with all tags. You can also inspect and pull these artifacts by their exact references.

For an upload, inspect the full reference from the push output:

chainctl skills describe uploads.cgr.dev/your-organization/harden-demo:v1.0.0

For a hardening job, use status and save the returned hardened reference as described in Review and install the result. Use that reference for describe, pull, or install; an empty listing does not mean the job failed.

Review and install the result

Read hardened/harden-demo/HARDENING.md for the change summary and findings, including findings that remain open. Review the resulting instructions before using the skill. A successful hardening job can still have remaining findings.

Copy the full hardened reference printed by harden or status:

export HARDENED_REF='<full-hardened-reference-including-@sha256:digest>'
chainctl skills describe "$HARDENED_REF"
chainctl skills install "$HARDENED_REF"

install detects your local agents and reports where it placed the skill. Use the installed name and location shown by the command to load it in your agent, then ask it to prepare a release checklist for a test project.

If ./hardened/harden-demo/ already contains a previous download, --wait will not overwrite it. Check status without --wait, then pull the returned reference into a new directory:

chainctl skills pull "$HARDENED_REF" ./harden-demo-reviewed

Last updated: 2026-09-23 16:38