11 Feb 20266 minute read

The CI/CD of Agent Skills: Automate Publishing with GitHub Actions
11 Feb 20266 minute read

You’ve built a brilliant skill. Bump the version, package it, authenticate, upload… and then spot it: you forgot to update the manifest summary. Again. Third time this week.
Manual publishing usually looks like this:
- Make changes to your artifact
- Remember to bump the version
- Package the files
- Authenticate with the API
- Upload the package
- Realise you shipped the wrong thing anyway:
- forgot to update the manifest/summary
- packaged stale files from an old build directory
- bumped the version but published from the wrong branch
- auth token expired mid-upload, leaving a half-published release
- everything “worked”… until a user installs it and hits a runtime error 🫠
Why You Need CI/CD for your Agent Context
A stale skill doesn't just sit there - it actively teaches agents the wrong patterns. When your team updated that API last month but nobody re-published the skill, every agent in every repo is now generating code against deprecated endpoints. CI/CD for skills isn't nice-to-have; it's how you prevent context debt from compounding silently.
Tessl is our answer to that problem - a package manager for skills and context. It gives us a repeatable way to publish “tiles” (packages of context that can include skills, docs, and rules - see image below)to the Tessl Registry, so every version changes are tracked and reflected in your tile.

How do you publish and update your agent skills?
tesslio/publish is a simple workflow that adds automatic publishing of Tessl tiles to your repository. This is done as a GitHub action, as follows:

This ensures every push to main automatically publishes your tile, so long as the tile version has changed. The action checks if your version already exists in the Tessl registry. If it does, the publish step is skipped gracefully:
myworkspace/my-tile@1.2.0 has already been published. Skipping publish stepThis means you can run the action on every push without worrying about duplicate publishes or version conflicts. You control when a new version is published by updating the version in your tile.json.
The action uses GitHub's OIDC (OpenID Connect) integration for secure, keyless authentication.
It’s worth noting that this action currently only packages the following files types in your tile: .md, .json, .js, .py, .sh, and .txt.
Here’s how to get started
Prerequisites
- A Tessl API token - Retrieve here, or run
tessl auth token - A tile with a valid
tile.jsonmanifest
Step 1: Create your tile manifest
Every tile needs a tile.json manifest file, which should look something like this:
{
"name": "your-workspace/your-tile-name",
"version": "1.0.0",
"summary": "What your tile does"
}The name must be in workspace/tile format, and version should follow semantic versioning.
Step 2: Add your Tessl API token as a secret in your GitHub settings
- Go to your repository's Settings → Secrets and variables → Actions
- Click New repository secret
- Name:
TESSL_API_TOKEN - Value:
Step 3: Add the workflow file in GitHub
Create .github/workflows/publish-tile.yml:
name: Publish Tile
permissions:
id-token: write # Required for OIDC token
contents: read # Required for checkout
on:
push:
branches:
- main
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: tesslio/publish@main
with:
token: ${{ secrets.TESSL_API_TOKEN }}Step 4: Push and publish
Commit your changes and push to main. The action will:
- Check if the version already exists
- Create a gzipped archive of your tile files
- Authenticate with the Tessl API
- Publish your tile to the Tessl registry
Advanced usage
Publishing from a subdirectory
If your tile lives in a subdirectory (common in monorepos):
- uses: tesslio/publish@main
with:
token: ${{ secrets.TESSL_API_TOKEN }}
path: './tiles/my-awesome-tile'Multiple Tiles in One Repository
For monorepos with multiple tiles, use a matrix strategy:
jobs:
publish:
runs-on: ubuntu-latest
strategy:
matrix:
tile:
- tiles/tile-one
- tiles/tile-two
- tiles/tile-three
steps:
- uses: actions/checkout@v4
- uses: tesslio/publish@main
with:
token: ${{ secrets.TESSL_API_TOKEN }}
path: ${{ matrix.tile }}Common Errors & Fixes
The TESSL_API_TOKEN environment var is required
The action can't find your API token. Ensure:
- The secret is named exactly
TESSL_API_TOKENin your repository settings - You're passing it correctly:
token: ${{ secrets.TESSL_API_TOKEN }}
Missing or invalid tile manifest
Your tile.json is either missing or contains invalid JSON. Verify:
- The file exists in the tile directory
- It's valid JSON (use a JSON validator)
- If using
path, ensure it points to the correct directory
Already published. Skipping the publish step
This is expected behavior when the version hasn't changed. To publish a new version, update the version field in your tile.json.
Invalid tile name. Expected format 'workspace/tile'
Your tile name must include both a workspace and tile name separated by a forward slash. Update your tile.json:
{
"name": "my-workspace/my-tile", // ✓ Correct
"name": "my-tile" // ✗ Missing workspace
"name": "my-workspace" // ✗ Missing tile name
}The Takeaway
Once the above is wired in, publishing stops being a checklist.
Update tile.json, push to main, and the action publishes - or skips if nothing changed! Remember that dev who forgot to update the manifest summary? Now the workflow catches the drift before users do.
No stale files, no expired tokens, no 🫠 moments. Just tiles that stay current, automatically. Discover what's already on the Tessl Registry, or reach out in Discord if you run into issues.
Join Our Newsletter
Be the first to hear about events, news and product updates from AI Native Dev.



