Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "github-release",
"version": "0.2.0",
"version": "0.2.1",
"description": "Create GitHub repositories for Agent Skills and release them right the first time: version gate, deterministic host packages, draft-first publishing, published-asset verification and a per-host install log.",
"author": {
"name": "Jesse Raber",
Expand Down
2 changes: 1 addition & 1 deletion .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "github-release",
"version": "0.2.0",
"version": "0.2.1",
"description": "Create GitHub repositories for Agent Skills and release them right the first time: version gate, deterministic host packages, draft-first publishing, published-asset verification and a per-host install log.",
"skills": "./skills/",
"author": {
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 0.2.1 (draft, not released)

- Gemini Apps package: leave out files without an extension. Gemini's skill uploader rejected 0.2.0 ("The skill folder contains a file with an unsupported file type") because of `templates/gitattributes`; the same package without it was accepted (2026-10-08).
- Builder 1.0.1: new `exclude_no_suffix` key in `packages.json`, plus a host invariant that refuses extensionless files in `gemini-apps-only` regardless of config. Regression test added.
- host-matrix, packaging and INSTALL docs record what Gemini accepted (`.py`, `.json`, `.md`, `.txt`) and the open question of whether scripts run there.

## 0.2.0 (draft, not released)

Portfolio and install lessons (R-023..R-035, R-038..R-040; evidence in the project's 2026-10-08 scan and install records):
Expand Down
10 changes: 10 additions & 0 deletions HOST_INSTALL_LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,13 @@ Evidence: `observed` (agent saw it), `user-reported`, or a path to a screenshot
| 2026-10-08 14:xx-14:28 EDT | 0.1.0 candidate | github-release-0.1.0-claude-code-plugin.zip (2d0bf67303c3) | Claude Code 2.1.223 / local user plugin | Install, enable, validate and routing smoke test | loaded-smoke-pass; install accepted, enabled, 26/26 cached files matched, marketplace validation passed, and authenticated routing smoke passed after an earlier expired-OAuth attempt | `Loaded GitHub Release v0.1.0`; selected `-claude-code-plugin` | observed; local CLI output, session T005 | Codex session 185e6066-cbb8-4abd-9d1a-394bd0b4fcb5 |
| 2026-10-08 ~16:2x EDT | 0.1.0 (published) | github-release-0.1.0-claude-code-plugin.zip (f7d0f6bfed75) | Claude Code / local user plugin via marketplace | Reinstall from published release asset (hash-verified vs SHA256SUMS), routing smoke test | loaded-smoke-pass; supersedes candidate-hash row above | `Loaded GitHub Release v0.1.0`; selected `-claude-code-plugin` | observed; CLI output, Claude session 2e2fbf7d | Claude session 2e2fbf7d-1c2d-47a7-82fd-16374ceac5f0 |
| 2026-10-08 ~16:2x EDT | 0.1.0 (published) | github-release-0.1.0-UNIVERSAL-skill.zip (cfffc4ea2d18) | Codex desktop / local user skills | Reinstall from published release asset (hash-verified vs SHA256SUMS) | accepted; 22/22 installed files match archive; behavioral smoke not run (needs a Codex session); supersedes candidate-hash row above | none shown | observed; file-hash comparison, Claude session 2e2fbf7d | Claude session 2e2fbf7d-1c2d-47a7-82fd-16374ceac5f0 |

## From 0.2.0 (rows with Channel column, per verify-and-record.md)

| Date (TZ) | Version | Asset (sha256 first 12) | Host / account | Channel | Action | Result | Displayed | Evidence | By |
|---|---|---|---|---|---|---|---|---|---|
| 2026-10-08 23:31-23:36 EDT | 0.2.0 (published) | github-release-0.2.0-claude-code-plugin.zip (4c1a598e1bdf) | Claude Code / owner PC, user scope | Claude Code plugin via directory marketplace `jesseraber-github-release` (re-pointed to session dc8fe785 scratch `claude-plugin-stage-0.2.0`) | Update 0.1.0 → 0.2.0: backup w/ manifest (26 files, 0 mismatch), hash-verify vs SHA256SUMS, marketplace remove/add, install, file compare, fresh-session load | loaded-smoke-pass; supersedes 0.1.0 (published) Claude Code row; cache 0.2.0 28/28 match, 0 missing, 0 extra; staging dir identical to cache (28/28); old cache dir 0.1.0 still present (not deleted) | `Loaded GitHub Release v0.2.0 (SKILL.md at …\scratch\dc8fe785-…\claude-plugin-stage-0.2.0\github-release\skills\github-release\SKILL.md)` | observed; `claude -p` fresh session; session dc8fe785 T002 | Claude session dc8fe785-5fdc-4d28-8476-654133a6caf2 |
| 2026-10-08 23:42 EDT | 0.2.0 (published) | github-release-0.2.0-UNIVERSAL-skill.zip (657833803ab8) | Codex desktop / owner PC | standalone skills dir `~/.codex/skills/github-release` | Update 0.1.0 → 0.2.0: backup w/ manifest (22 files, 0 mismatch); old dir moved to session dc8fe785 scratch/replaced; hash-verified ZIP extracted; file compare | accepted; 24/24 match ZIP, 0 missing, 0 extra; only github-release SKILL.md under ~/.codex; fresh-session load NOT RUN (no `codex` CLI on PATH) — owner check prompt in Handoffs/2026-10-08_github-release-0.2.0-host-install-checklist.md; supersedes 0.1.0 (published) Codex row | none shown (pending owner check) | observed; file-hash comparison, session dc8fe785 T003 | Claude session dc8fe785-5fdc-4d28-8476-654133a6caf2 |
| 2026-10-08 23:48-23:50 EDT | 0.2.0 (published) | github-release-0.2.0-claude-code-plugin.zip (4c1a598e1bdf) | Claude Code / owner PC, user scope | Claude Code plugin via directory marketplace `jesseraber-github-release`, source moved to `%USERPROFILE%\.claude\local-marketplaces\github-release` (outside OneDrive; R-041) | Re-point marketplace: hash-verified ZIP extracted to new path, marketplace remove/add, reinstall, file compare, fresh-session load | loaded-smoke-pass; supersedes the 23:31 row's source path; marketplace source 28/28 and cache 0.2.0 28/28 vs ZIP, 0 missing, 0 extra | `Loaded GitHub Release v0.2.0 (SKILL.md at C:\Users\JesseRaber\.claude\local-marketplaces\github-release\skills\github-release\SKILL.md)` | observed; `claude -p` fresh session; session dc8fe785 T005 | Claude session dc8fe785-5fdc-4d28-8476-654133a6caf2 |
| 2026-10-08 ~23:5x EDT | 0.2.0 (published) | github-release-0.2.0-gemini-apps-only.zip (published asset) | Gemini Apps / owner account | Gemini skill upload (UI) | Upload | rejected: "The skill folder contains a file with an unsupported file type. Please remove it and try again." | none | user-reported error text | owner; diagnosed by Claude session 01J7MzndUA7hmG1BaegLPWa3 |
| 2026-10-09 ~00:00 EDT | 0.2.0 test build (not a release asset) | test-A-no-gitattributes.zip (71495d265da0) = 0.2.0 Gemini ZIP minus templates/gitattributes | Gemini Apps / owner account | Gemini skill upload (UI) | Upload | accepted; left installed; behavioral/script-run check not done; to be superseded by the 0.2.1 Gemini asset | not reported | user-reported | owner; test ZIP built by Claude session 01J7MzndUA7hmG1BaegLPWa3 |
2 changes: 1 addition & 1 deletion packaging/INSTALL-microsoft-copilot.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ This package has no PowerShell files. The Python helpers need only the standard

A successful upload proves only package acceptance. Test with a read-only request such as "Is this repository ready to tag?".

Expected loaded version: **GitHub Release v0.2.0**.
Expected loaded version: **GitHub Release v0.2.1**.
4 changes: 2 additions & 2 deletions packaging/INSTALL-universal.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

The folder `github-release/` **is** the skill. Keep `SKILL.md`, `references/`, `scripts/` and `templates/` together.

Host-specific packages leave some files out: Gemini Apps omits the `.yml` workflow templates (precaution); Opal keeps only `SKILL.md` and `references/*.md`, so the helper scripts and templates are not available there.
Host-specific packages leave some files out: Gemini Apps omits the `.yml` workflow templates (precaution) and `templates/gitattributes` (Gemini rejects files without an extension); Opal keeps only `SKILL.md` and `references/*.md`, so the helper scripts and templates are not available there.

## Claude app

Expand All @@ -25,7 +25,7 @@ Point the system prompt or context loader at `github-release/SKILL.md`.

> Is my skill repository ready to tag v1.0.0?

A loaded skill states **Mode: Gate** first and reports **Loaded GitHub Release v0.2.0 (SKILL.md at <path>)**.
A loaded skill states **Mode: Gate** first and reports **Loaded GitHub Release v0.2.1 (SKILL.md at <path>)**.

## Requirements

Expand Down
12 changes: 12 additions & 0 deletions packaging/RELEASE_NOTES_v0.2.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# github-release 0.2.1

Patch: the Gemini Apps package no longer contains files without an extension. Gemini's skill uploader rejected 0.2.0 with "The skill folder contains a file with an unsupported file type" (`templates/gitattributes`). The builder now refuses extensionless files in Gemini packages regardless of `packages.json`. Other packages are unchanged apart from the version number.

Verify downloads with `sha256sum -c SHA256SUMS.txt`.

## Publication boundary

Installed host copies are updated separately; this release does not change any host by itself.

---
Built by [Jesse Raber](https://jesseraber.net) · [YouTube](https://www.youtube.com/@Jesse_Raber)
11 changes: 9 additions & 2 deletions packaging/build_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import tempfile
import zipfile

__version__ = '1.0.0'
__version__ = '1.0.1'
STAMP = (2026, 1, 1, 0, 0, 0)
REPO = Path(__file__).resolve().parents[1]
OPAL_SIZE_WARN = 48 * 1024 # observed Opal per-file rejection ~48-79 KB (approximate, 2026-10-03)
Expand All @@ -34,6 +34,9 @@
'microsoft-copilot-agent-only': ('.ps1',),
'gemini-apps-only': ('.ps1', '.yml', '.yaml'),
}
# Hosts whose uploader rejects files without an extension (Gemini Apps: observed 2026-10-08,
# "unsupported file type" on templates/gitattributes; same package without it was accepted).
HOST_NO_EXTENSIONLESS = {'gemini-apps-only'}
# Package names that may appear in packages.json. A renamed package must be added here
# deliberately, so it cannot silently escape its host invariants.
KNOWN_PACKAGES = {'UNIVERSAL-skill', 'claude-code-plugin', 'codex-chatgpt-plugin',
Expand Down Expand Up @@ -83,7 +86,8 @@ def source_files(skill_dir):
def excluded(rel, spec):
return (rel.startswith(tuple(spec.get('exclude_prefix', [])))
or rel.endswith(tuple(spec.get('exclude_suffix', [])))
or rel in spec.get('exclude_files', []))
or rel in spec.get('exclude_files', [])
or (spec.get('exclude_no_suffix') and '.' not in rel.rsplit('/', 1)[-1]))


def opal_skill_md(data):
Expand Down Expand Up @@ -163,6 +167,9 @@ def verify(archive, flavor, spec, items, dirs, version, smoke, warnings, smoked)
if flavor == suffix:
bad = [n for n in files_only if n.lower().endswith(banned)]
check(not bad, ('host invariant: %s must not contain %s' % (flavor, banned), bad))
if flavor in HOST_NO_EXTENSIONLESS:
bad = [n for n in files_only if '.' not in n.rsplit('/', 1)[-1]]
check(not bad, ('host invariant: %s must not contain files without an extension' % flavor, bad))
if spec['layout'] == 'opal':
check(all(n.endswith('.md') for n in files_only))
check(not any(n.endswith('/') for n in listed))
Expand Down
2 changes: 1 addition & 1 deletion packaging/check_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import re
import sys

__version__ = '0.2.0'
__version__ = '0.2.1'
SEMVER = re.compile(r'^\d+\.\d+\.\d+$')
TEXT_SUFFIXES = {'.md', '.py', '.json', '.yml', '.yaml', '.txt', '.ps1', '.toml', '.cfg'}
SKIP_DIRS = {'.git', '__pycache__', 'node_modules', 'dist'}
Expand Down
2 changes: 1 addition & 1 deletion packaging/packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"claude-code-plugin": {"layout": "plugin", "metadata": ".claude-plugin", "add": {"LICENSE": "LICENSE", "README.md": "README.md", "CHANGELOG.md": "CHANGELOG.md", "INSTALL.md": "packaging/INSTALL-claude-code.md"}},
"codex-chatgpt-plugin": {"layout": "plugin", "metadata": ".codex-plugin", "add": {"LICENSE": "LICENSE", "README.md": "README.md", "CHANGELOG.md": "CHANGELOG.md", "INSTALL.md": "packaging/INSTALL-codex-chatgpt.md"}},
"microsoft-copilot-agent-only": {"layout": "skill", "exclude_suffix": [".ps1"], "add": {"LICENSE.txt": "LICENSE", "INSTALL.md": "packaging/INSTALL-microsoft-copilot.md"}},
"gemini-apps-only": {"layout": "skill", "exclude_prefix": ["agents/"], "exclude_suffix": [".ps1", ".yaml", ".yml"], "add": {"LICENSE.txt": "LICENSE"}},
"gemini-apps-only": {"layout": "skill", "exclude_prefix": ["agents/"], "exclude_suffix": [".ps1", ".yaml", ".yml"], "exclude_no_suffix": true, "add": {"LICENSE.txt": "LICENSE"}},
"opal-only": {"layout": "opal"}
}
}
2 changes: 1 addition & 1 deletion packaging/verify_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import sys
import zipfile

__version__ = '0.2.0'
__version__ = '0.2.1'
SUMS = 'SHA256SUMS.txt'


Expand Down
4 changes: 2 additions & 2 deletions skills/github-release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ name: github-release
description: Create GitHub repositories for Agent Skills and release them right the first time - version agreement, a pre-tag gate, deterministic host-specific packages (Claude app, Claude Code, Codex/ChatGPT, Microsoft Copilot, Grok, Gemini Apps, Opal, Antigravity, local models), draft-first publishing, verification of published assets against the local build, and a dated per-host install log. Use whenever an agent prepares, tags, publishes, re-packages or verifies a skill release, sets up a skill repository or release workflow, decides which ZIP a host needs, or records that a skill was uploaded or installed somewhere.
license: MIT
metadata:
version: "0.2.0"
version: "0.2.1"
repository: https://github.com/JesseRaber/github-release
---

# GitHub Release

A release is right the first time when the bytes you tested are the bytes people download, every host gets a package it accepts, and the record says which host has which version and how anyone knows.

Report as: **Loaded GitHub Release v0.2.0 (SKILL.md at <path you loaded>)**. State the mode in the first line. The path lets install checks detect shadow copies and stale channels.
Report as: **Loaded GitHub Release v0.2.1 (SKILL.md at <path you loaded>)**. State the mode in the first line. The path lets install checks detect shadow copies and stale channels.

## Choose the mode

Expand Down
5 changes: 3 additions & 2 deletions skills/github-release/references/host-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ A host can have several install channels that drift to different versions indepe
- **Codex / ChatGPT**: plugin via Plugin Creator; standalone skill via the Universal ZIP.
- **Microsoft Copilot**: two distinct surfaces — **Agent Builder** (Configure → Skills, takes the agent ZIP) and **chat attachment** (observed 2026-10-07 rejecting the ZIP but accepting Markdown files attached directly). The documented Agent Builder layout is root-level `SKILL.md`, while this package nests it under `<name>/`; whether Agent Builder requires the root layout is an **open question** (pending test, ai-prompting W-015) — do not change the package until that test runs. The sandbox has no direct network; packaged scripts must not need it (repo).
- **Grok**: sandbox is POSIX; OneDrive/SharePoint hydration cannot be checked there (repo).
- **Gemini Apps**: never rename or obfuscate code to pass the scan; omit and document.
- **Gemini Apps**: the skill uploader rejects a folder containing a file without an extension ("The skill folder contains a file with an unsupported file type", observed 2026-10-08 on `templates/gitattributes`); the same package without that file was accepted, including `.py`, `.json`, `.md` and `.txt`. Whether packaged `.py` scripts can run there is untested. Never rename or obfuscate code to pass the scan; omit and document. Add-on files must keep an extension (`LICENSE.txt`, not `LICENSE`).
- **Opal**: references must be flat for the skill to work there; keep essential instructions in `SKILL.md` and top-level `references/`.
- **Antigravity**: installs from the GitHub repository (repo-documented; untested here).
- **Local models (Ollama, LM Studio, llama.cpp front-ends)**: point the system prompt or context loader at `SKILL.md`.
Expand All @@ -45,7 +45,8 @@ A host can have several install channels that drift to different versions indepe

## Open questions

- Does Gemini accept `.yml` templates? (github-release omits them as a precaution.)
- Does Gemini accept `.yml` templates? (github-release omits them as a precaution; `.py`/`.json`/`.md`/`.txt` were accepted 2026-10-08.)
- Can packaged `.py` scripts execute inside Gemini Apps?
- Is the Opal size limit per file or per package, and what is the exact threshold?
- Which hosts load an `AGENTS.md` from a project folder? Not a packaging rule; tracked in the project.
- Does Copilot Agent Builder require root-level `SKILL.md` in the ZIP? (See Microsoft Copilot host note; pending W-015 test.)
5 changes: 3 additions & 2 deletions skills/github-release/references/packaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Copy `templates/build_packages.py` to `packaging/build_packages.py` and `templat

Fidelity check (2026-10-08, by the author, repeatable): with a `packages.json` describing multi-agent-folder-cleanup's seven packages (six like `templates/packages.json` plus a `subtree` add-on), this builder reproduced all seven published v1.6.1 ZIPs byte-for-byte against GitHub's asset digests.

Independent of `packages.json`, the builder also refuses `.ps1` in Copilot packages, `.ps1`/`.yml`/`.yaml` in Gemini packages and non-Markdown in Opal packages, and fails if a script named in `smoke_version_scripts` is never packaged.
Independent of `packages.json`, the builder also refuses `.ps1` in Copilot packages, `.ps1`/`.yml`/`.yaml` and files without an extension (e.g. `gitattributes`, `LICENSE`) in Gemini packages and non-Markdown in Opal packages, and fails if a script named in `smoke_version_scripts` is never packaged.

## packages.json

Expand All @@ -21,7 +21,7 @@ Independent of `packages.json`, the builder also refuses `.ps1` in Copilot packa
"smoke_version_scripts": ["my_helper.py"],
"packages": {
"UNIVERSAL-skill": {"layout": "skill", "add": {"LICENSE.txt": "LICENSE", "INSTALL.md": "packaging/INSTALL-universal.md"}},
"gemini-apps-only": {"layout": "skill", "exclude_suffix": [".ps1", ".yaml", ".yml"], "exclude_prefix": ["agents/"]}
"gemini-apps-only": {"layout": "skill", "exclude_suffix": [".ps1", ".yaml", ".yml"], "exclude_no_suffix": true, "exclude_prefix": ["agents/"]}
}
}
```
Expand All @@ -30,6 +30,7 @@ Independent of `packages.json`, the builder also refuses `.ps1` in Copilot packa
|---|---|
| `layout` | `skill` (folder `<name>/…`), `plugin` (`<name>/skills/<name>/…` + `metadata` manifests), `opal` (flat Markdown, no folder entries), `subtree` (`from` → `to`, for add-ons) |
| `exclude_prefix` / `exclude_suffix` / `exclude_files` | paths relative to the skill folder to leave out |
| `exclude_no_suffix` | `true` leaves out skill files whose name has no extension (required for Gemini Apps) |
| `add` | extra files: archive path inside `<name>/` → repository path |
| `metadata` | plugin manifest folder (`.claude-plugin`, `.codex-plugin`) |
| `folder_entries` | override; default true except `opal` |
Expand Down
2 changes: 1 addition & 1 deletion skills/github-release/scripts/check_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import re
import sys

__version__ = '0.2.0'
__version__ = '0.2.1'
SEMVER = re.compile(r'^\d+\.\d+\.\d+$')
TEXT_SUFFIXES = {'.md', '.py', '.json', '.yml', '.yaml', '.txt', '.ps1', '.toml', '.cfg'}
SKIP_DIRS = {'.git', '__pycache__', 'node_modules', 'dist'}
Expand Down
2 changes: 1 addition & 1 deletion skills/github-release/scripts/verify_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import sys
import zipfile

__version__ = '0.2.0'
__version__ = '0.2.1'
SUMS = 'SHA256SUMS.txt'


Expand Down
Loading
Loading