Publish a package
Repository layout, SKILL.md frontmatter, package types, versioning, GitHub import, the Sync button and webhooks.
Packages are imported from public GitHub repositories. Denofy downloads the repository at an exact commit, verifies the package folder and stores it as an immutable tarball. You never upload files by hand, so every version can be traced back to a commit.
Repository layout#
One repository can hold any number of packages; each package is a folder (or the repository root). A typical skill:
my-skills/
├── commit-helper/ ← package folder ("Path in repo": commit-helper)
│ ├── SKILL.md ← required for skills
│ ├── reference.md ← resources the skill links to
│ ├── scripts/
│ │ └── changelog.sh ← scanned strictly as executable code
│ ├── denofy.json ← optional: {"version": "1.3.0"}
│ ├── denofy.yml ← optional: exceptions for the security scan
│ └── README.md ← shown on the package page
└── pr-checklist/
└── ...Ignored during import: .git, node_modules, .DS_Store and __MACOSX.
| Limit | Value |
|---|---|
| Files per package | 200 |
| Size of one file | 1 MiB |
| Total package size | 5 MiB |
Frontmatter description | 20–1024 characters |
Recommended length of SKILL.md | ≤ 500 lines |
Package types#
| Type | What the folder contains | Tools |
|---|---|---|
| Skill | SKILL.md with frontmatter, plus any resources it references | Claude Code, Codex, Cursor |
| Cursor Rule | One or more .mdc files with description / globs / alwaysApply | Cursor |
| AGENTS.md | An AGENTS.md (or one markdown file) that is merged into the target | Codex, Claude Code, Cursor |
| Subagent | Markdown files with name and description frontmatter | Claude Code |
| Slash Command | Markdown files whose file name is the command (deploy.md → /deploy) | Claude Code, Codex, Cursor |
Where each type is installed is listed in the CLI reference.
SKILL.md frontmatter#
---
name: commit-helper
description: Writes Conventional Commit messages from the staged diff. Use when the user asks for a commit message or wants to commit.
version: 1.3.0
license: MIT
---
# Commit helper
1. Run `git diff --staged`.
2. Read [the conventions](reference.md) …| Field | Required | Rules |
|---|---|---|
name | yes | Lowercase letters, digits and hyphens. Should equal the package name (warning if not). |
description | yes | 20–1024 characters. Agents use it to decide when to load the skill — say when. |
version | no | Semver; used as the version on import (see below). |
license | no | SPDX id, shown on the package page. |
Every relative link ([text](file.md), images) must point to a file inside the package —
missing files fail the structure check. Paths mentioned in backticks that do not exist produce a
warning.
Versioning#
Each import is pinned to one commit. The version number is chosen in this order:
- The version you type in the Sync dialog, or the tag of a tag push (
v1.4.0→1.4.0). versionindenofy.jsonin the package folder.version(ormetadata.version) in the frontmatter ofSKILL.md/ the main file.- Otherwise the patch version is bumped automatically (
1.2.3→1.2.4; the first version is1.0.0).
Rules:
- A version number can only exist once. Importing the same version from a different commit fails with "Bump the version to publish changes".
- Importing a commit that is already published does nothing.
- Versions are never edited after import. You can yank a version (hidden from ranges and
latest, still installable by exact number) from the dashboard. latestis the highest version that is not yanked, not blocked and did not fail verification.
Import from GitHub#
Sign in with GitHub#
Sign in and open Publish in the header.
Choose repository and path#
Enter the repository (owner/repo), the path of the package folder (empty for the root) and
optionally a branch (default branch if empty).
Describe the package#
Name (the slug used in denofy add <name>, cannot be changed later), title, summary, type,
supported tools, category, tags and license. The description defaults to the package's README.
Submit#
Denofy queues the import. The worker downloads the repository at the current commit, runs the verifier and stores the tarball — usually within a few seconds. The dashboard shows the result and the full verification report.
New accounts can create a limited number of packages per day; see rate limits.
Sync button#
On Dashboard → your package the Sync button imports the newest commit of the configured branch. You can optionally enter a version and a changelog. Re-verify runs the current rules again on an existing version without creating a new one.
Webhook: publish on every push#
With a webhook, a push to your repository publishes a new version automatically.
Open the webhook settings#
In your GitHub repository go to Settings → Webhooks → Add webhook.
Fill in the form#
- Payload URL:
https://denofy.com/api/webhooks/github(also shown with a copy button in your package dashboard) - Content type:
application/json - Secret: the webhook secret of the Denofy instance — the value of
GITHUB_WEBHOOK_SECRETon a self-hosted instance; for denofy.com ask the Denofy team - Events: Just the push event
Enable auto-sync#
Keep Auto-sync enabled in the package settings (it is on by default).
Push#
- A push to the package's branch that changes files under the package path publishes a new
version (patch bump, or the version declared in
denofy.json/ frontmatter). - Pushing a tag like
v1.4.0publishes exactly that version from the tagged commit. - Pushes that do not touch the package path are ignored.
GitHub shows the delivery result under Recent Deliveries. A 200 response lists the packages
that were queued, for example {"ok": true, "queued": ["commit-helper"]}. 401 means the secret
does not match. Webhook syncs count against the per-package sync limit.
After publishing#
- Add the README badge to your repository.
- Look at the verification report on the package page. If a finding is a false positive, either rephrase the text (see how context works) or add an exception with a reason in denofy.yml.
- Watch installs and views in analytics.