Publish HTML frontend games to the AI Game MCP platform.
# Add to your Claude Code skills
git clone https://github.com/publisher-skill/publisherpublisher is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by publisher-skill. Publish HTML frontend games to the AI Game MCP platform. It has 52 GitHub stars.
publisher's catalog security scan is still queued. You can run an instant dependency and prompt-injection check now with the "Scan for vulnerabilities" button above.
Clone the repository with "git clone https://github.com/publisher-skill/publisher" and add it to your Claude Code skills directory (see the Installation section above). publisher ships a SKILL.md manifest, so compatible agents can discover and load it automatically.
publisher is primarily written in Shell. It is open-source under publisher-skill on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh publisher against similar tools.
No comments yet. Be the first to share your thoughts!
Unlocks once the catalog security scan passes (runs nightly).
The deep catalog scan for this skill is still queued. Run an instant dependency check now instead.
Publish HTML frontend projects to the publishing platform and optionally package them as Android APKs.
Platform URL:
https://pushwebly.com
Use "project" in user-facing messages. The canonical API paths are
/api/projects and canonical tool names are project_*. Deprecated game_*
aliases and gameId response fields may still appear; treat gameId as the
project id.
project_* MCP tools if they exist in the current environment.curl.~/.publisher/config.json after consent.| User intent | Action | Missing information to ask for |
|---|---|---|
| Publish, ship, upload, put online | Publish project | zip path, project name |
| Make an installable phone app, APK, Android package | Publish and build APK | zip path, project name |
| Build APK for an already published project | Build APK | project id; use project list if needed |
| Make an app private/public, add/remove access password | Change visibility | app URL, target visibility (optional password when private) |
| Show my projects, list published projects | List projects | none if token is available |
| Log in, register, account setup | Login/register | username and password |
If the intent is ambiguous, ask one short question: "Just publish it, or publish it and build an Android APK too?"
When users express intentions such as publishing, deploying, launching, sharing applications, generating access links, etc., they must enter this process.
S-1 (version check, non-blocking), then proceed in the order of S0 -> S1 -> S2 -> S3 -> S4.S-1).When entering the publish flow, run a version self-check before S0. This step is NOT part of the <HARD-GATE> blocking rules: whatever the result — even if the endpoint is unreachable — always continue. Never interrupt publishing because of a version issue.
Steps:
Read the local skill version: the version field in this file's frontmatter.
Query the latest platform version (no login required):
curl -s https://ai-pub.pushwebly.com/api/skill/latest-version
The response data contains: version (latest), downloadUrl (cross-platform doc package, unzip-and-use), downloadUrlWindows (Windows installer .exe), and downloadUrlMac (macOS installer .zip).
Compare local version with the returned version.
Comparison rule: a version is major.minor.patch. Compare segment by segment as integers, left to right — major first, then minor, then patch; pad missing segments with 0 (1.1 means 1.1.0). Compare as integers, NOT as strings: 1.10.0 is greater than 1.9.0 (second segment 10 > 9); a string compare would get this wrong. Ascending example: 1.0.0 < 1.0.9 < 1.1.0 < 1.2.0 < 1.10.0 < 2.0.0.
Local is older (local's integer-segment sequence is less than the returned one): you MUST output an update notice to the user before continuing, and the notice MUST include the actual download URL (this does not block publishing, but the notice must not be omitted). Pick the download URL by the user's OS:
downloadUrlWindowsdownloadUrlMacdownloadUrlNotice text (output it in the SAME language the user is conversing in — Chinese if they write Chinese, English if English; do not hard-code one language; the example below is English only as a template; replace the URL with the real selected one; write the download URL as a clickable Markdown link [URL](URL) — do NOT wrap it in backticks as inline code, or the user cannot click it; never leave a placeholder, never say "a new version exists" without giving the link):
Note: a newer Publisher skill version
<version>is available (you are on<local version>). Download: https://ai-pub.pushwebly.com/downloads/AI_Publisher_skill.exe (updating does not affect the current publish).
Local equals or is newer: stay silent and continue.
Request fails/times out/cannot parse: silently skip, go straight to S0, do not surface an error.
In all cases, proceed to S0 next. Because this step only notifies (no input, no blocking), the "at most one user-facing question per reply" rule does not apply to it — the version note may share the same reply as the first S0 question.
First, check if there is already an available token/local credential.
S2.S1_USERNAME.Ask the user a question:
I need to confirm the publishing account first: Do you already have an available account or token?
User answer:
S2.S1_USERNAME.If there is no username, only ask:
Please provide the username to be registered.
After receiving the username, record it as username and enter S1_PASSWORD.
If there is no password, only ask:
Please provide the registration password.
After receiving the password, record it as password and enter S1_VALIDATE.
Only after having both username and password can the backend interface be called for joint verification.
Verification passed:
Registration and login successfulS2Verification failed:
If the public or private status has not been clearly defined, only ask:
Is this application public? Public means anyone can access it via a link; private requires a 6-digit access password.
User answer:
visibility=public, enter S4visibility=private, enter S3If visibility=private, it is necessary to ask whether to customize the password, asking only:
Do you want to customize a 6-digit access password? You can also reply "system-generated".
User answer:
accessPassword=<user password> and enter S4accessPassword, let the backend generate it, and enter S4Calling the publishing interface is only allowed if one of the following conditions is met:
visibility=publicvisibility=private and the user has selected a custom password or a system-generated passwordRelease Parameters:
Public Application:
{
"visibility": "public"
}
Private application, custom password:
{
Default to `public` if the user does not specify visibility. A private access
password must match `^[A-Za-z0-9]{6}$`; otherwise ask for a valid password or let
the backend generate one.
## Token Handling
A Bearer token is required for all publishing APIs.
Use this order:
1. If the user provided a token in the conversation, use it directly.
2. If `~/.publisher/config.json` exists, read the stored username/password and
log in again to refresh the token.
3. Otherwise ask for username and password. The login endpoint automatically
registers new accounts.
Login/register endpoint:
```bash
curl -s -X POST https://ai-pub.pushwebly.com/api/auth/login-or-register \
-H "Content-Type: application/json" \
-d @login.json
Write login.json as:
{"username":"alice","password":"plain-text-password"}
Use data.token from the response as:
Authorization: Bearer <TOKEN>
Delete the temp login file after use.
Optional local credential file:
{
"baseUrl": "https://ai-pub.pushwebly.com",
"username": "alice",
"password": "plain-text-password",
"authorization": "Bearer <TOKEN>",
"userId": 1
}
On Linux/macOS, set mode 600 after writing. On 401, refresh the token once by
logging in again, then retry the failed operation once.
Verify token:
curl -s https://ai-pub.pushwebly.com/api/auth/verify-token \
-H "Authorization: Bearer <TOKEN>"
Before publishing:
.zip extension.index.html or index.htm.Public:
curl -s -X POST https://ai-pub.pushwebly.com/api/projects/publish \
-H "Authorization: Bearer <TOKEN>" \
-F "project_name=demo" \
-F "file=@demo.zip"
Private with optional custom password:
curl -s -X POST https://ai-pub.pushwebly.com/api/projects/publish \
-H "Authorization: Bearer <TOKEN>" \
-F "project_name=demo" \
-F "file=@demo.zip" \
-F "visibility=private" \
-F "access_password=a1b2c3"
For private apps, omit access_password to let the backend generate a password.
Always relay the final accessPassword from the response to the user.
curl -s https://ai-pub.pushwebly.com/api/projects/my \
-H "Authorization: Bearer <TOKEN>"
Toggle an already-published app between public and private. The input is the app URL; the backend parses the app identifier from it and verifies the app belongs to the current user — you can only change your own apps, not others'.
curl -s -X PATCH https://ai-pub.pushwebly.com/api/projects/visibility \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-d @visibility.json
Write visibility.json (to private):
{"url":"https://ai-pub.pushwebly.com/play/aB3xYz/","visibility":"private","accessPassword":"a1b2c3"}
Or to public (no password needed; the old password is cleared):
{"url":"https://ai-pub.pushwebly.com/play/aB3xYz/","visibility":"public"}
accessPassword is optional and only used when switching to private (6 digits or
letters; auto-generated if omitted). The response data includes the final
visibility, url, and — when private — the accessPassword. Relay a private
app's URL and password separately, never with ?pwd=. If the app is not found,
already deleted, or belongs to another user, state the concrete reason and that
only your own apps can be changed.
curl -s -X POST https://ai-pub.pushwebly.com/api/apk/build \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-d @build-apk.json
Write build-apk.json as:
{"projectId":12}
Use data.apkUrl from the response as the APK download URL.
This is the recommended operation when the user wants an installable Android app.
curl -s -X POST https://ai-pub.pushwebly.com/api/apk/publish-and-build \
-H "Authorization: Bearer <TOKEN>" \
-F "project_name=airplane-war" \
-F "file=@project.zip"
For a private app, add:
-F "visibility=private" -F "access_password=a1b2c3"
Omit access_password to auto-generate it.
Expected response fields may include:
{
"gameId": 12,
"projectName": "airplane-war",
"playUrl": "https://ai-pub.pushwebly.com/play/aB3xYz/",
"status": "enabled",
"apkUrl": "https://ai-pub.pushwebly.com/api/apk/download/airplane-war_aB3xYz.apk",
"apkFileName": "airplane-war_aB3xYz.apk",
"apkFileSize": 2300000
}
Read gameId as the project id.
If project_* tools are mounted, use these canonical parameter shapes.
project_publish:
{
"authorization": "Bearer <TOKEN>",
"projectName": "project-name",
"zipFilePath": "server-side local zip path",
"visibility": "public",
"accessPassword": ""
}
project_list:
{"authorization": "Bearer <TOKEN>"}
project_update_visibility:
{
"authorization": "Bearer <TOKEN>",
"url": "https://ai-pub.pushwebly.com/play/aB3xYz/",
"visibility": "private",
"accessPassword": "a1b2c3"
}
project_build_apk:
{
"authorization": "Bearer <TOKEN>",
"projectId": 12
}
project_publish_and_build_apk:
{
"authorization": "Bearer <TOKEN>",
"projectName": "project-name",
"zipFilePath": "server-side local zip path",
"visibility": "public",
"accessPassword": ""
}
Publish only, public:
Project published successfully.
Project name: <projectName>
Access URL: <url>
Visibility: public
Status: enabled
Publish only, private:
Private project published successfully.
Project name: <projectName>
Access URL: <url>
Access password: <accessPassword>
Visibility: private
Share the URL and the access password separately. The recipient opens the URL and enters the password on the page. Do not append the password to the URL.
Publish and build APK:
Project published successfully.
Project name: <projectName>
Access URL: <playUrl>
APK download: <apkUrl>
Build APK only:
APK build complete.
Project name: <projectName>
APK download: <apkUrl>
On failure, state the concrete reason and the next retry action. Common reasons:
missing index.html/index.htm, invalid or expired token, missing zip file,
empty project name, invalid private password, APK timeout, or server missing
Android SDK configuration.
?pwd=<password>, but do not promote that suffixed-link form.)
After successful entry, the browser stores a cookie.com.pushwebly.g{playToken}.project_publish_and_build_apk for one-step publish plus APK generation.English | 简体中文
Publish HTML frontend projects to the publishing platform.
Extract this directory to:
~/.claude/skills/publisher
Then use the Skill inside Claude Code.
https://pushwebly.com
Just tell Claude what you want in plain language, for example:
Claude infers the action, asks only for what's missing (username/password on
first use), logs in, and completes the workflow directly via the MCP tools or
HTTP APIs. You don't need to install or run anything. See SKILL.md for the
full agent workflow.
Credentials are saved locally to ~/.publisher/config.json so subsequent runs
refresh the token automatically.
Canonical names are
project_*(preferred). The oldgame_*names still work as deprecated aliases. Describe them as "project" operations to users.
user_login_or_registerproject_publishproject_listproject_update_visibilityproject_build_apkproject_publish_and_build_apk