Publish Software on Pulsar Store
Submit your GNOME Shell extension, Flatpak application, or Sayri AI skill for automatic OpenCode verification and instant publishing.
Official repository of applications, GNOME Shell extensions, and Sayri AI skills for Pulsar OS.
Submit your GNOME Shell extension, Flatpak application, or Sayri AI skill for automatic OpenCode verification and instant publishing.
Specification and instructions for AI coding assistants (Antigravity, Cursor, Claude, etc.) on how to autonomously submit and publish packages to Pulsar Store via GitHub Issues.
# 🤖 AI Agent Submission Guide — Pulsar Store
> **Purpose**: This document teaches AI coding agents how to autonomously submit, update, and manage packages on the Pulsar Store (https://store-os.inled.es) via the GitHub Issue-based automated pipeline.
---
## 📖 Table of Contents
1. [How the Store Works](#how-the-store-works)
2. [Package Types & Structures](#package-types--structures)
3. [How to Submit a New Package](#how-to-submit-a-new-package)
4. [How to Update an Existing Package](#how-to-update-an-existing-package)
5. [How to Delete a Package](#how-to-delete-a-package)
6. [Security Audit Pipeline](#security-audit-pipeline)
7. [Automation Scripts](#automation-scripts)
8. [Examples for AI Agents](#examples-for-ai-agents)
---
## How the Store Works
The Pulsar Store is a **GitHub Issue-driven** package registry. There is no REST API — all operations happen through GitHub Issues with specific YAML form templates. A GitHub Actions workflow (`validate-and-publish.yml`) triggers automatically on new/edited issues and:
1. Parses the issue form fields
2. Downloads the ZIP archive and icon
3. Runs **VirusTotal** malware scanning (zero-tolerance)
4. Runs **OpenCode AI** semantic code audit (Groq Llama 3.3 70B)
5. Publishes the package to GitHub Releases
6. Updates `schema/index.json` (the catalog database)
7. Rebuilds `CATALOG.md` and web dist
8. Closes the issue as "completed"
**Repository**: `https://github.com/Inled-Pulsar-OS/store`
---
## Package Types & Structures
### 1. Sayri Skill (`sayri_skill`)
AI capabilities and system prompts for Sayri subagents.
**ZIP Structure**:
```
sayri-skill-my-skill.zip
├── SKILL.md # Required: Frontmatter YAML + prompt instructions
├── scripts/ # Optional: Executable helper scripts
├── tools/ # Optional: Tool definitions
└── requirements.txt # Optional: Python dependencies
```
**SKILL.md Format**:
```yaml
---
name: sayri-skill-my-skill
title: My Custom Skill
description: What this skill does for Sayri.
version: 1.0.0
author: your-github-username
sandbox_level: LEVEL_1_READONLY
allowed_tools:
- tool_name_1
- tool_name_2
required_secrets:
- SECRET_NAME
---
# Role & Capabilities
You are a [description of the AI persona].
## Guidelines
1. [Instruction 1]
2. [Instruction 2]
## Tools
- `tool_name_1`: Description of what this tool does.
- `tool_name_2`: Description of what this tool does.
```
**Issue Template**: `submit-skill.yml`
- **Title format**: `[Skill]: My Skill Name`
- **Labels**: `skill`, `sayri`, `submission`
---
### 2. Sayri Plugin / Gateway (`sayri_plugin`)
Out-of-process sandboxed gateways (Discord, Telegram, MCP, Matrix, etc.)
**ZIP Structure**:
```
sayri-gateway-myplatform.zip
├── manifest.json # Required: Plugin manifest
├── gateway.py # Required: Main entrypoint daemon
├── requirements.txt # Optional: Python dependencies
└── README.md # Optional: Documentation
```
**manifest.json Format**:
```json
{
"id": "sayri-gateway-myplatform",
"name": "My Platform Gateway",
"version": "1.0.0",
"author": "your-github-username",
"description": "What this gateway does.",
"entrypoint": "gateway.py",
"sandbox_level": "LEVEL_1_READONLY",
"required_secrets": [
"MY_PLATFORM_TOKEN"
],
"authorization": {
"mode": "pairing_otp",
"allowed_users": [],
"pairing_pin_required": true,
"pin_expiration_seconds": 300,
"rate_limit": {
"max_requests_per_minute": 15,
"burst": 3
}
},
"capabilities": [
"receive_messages",
"send_replies"
],
"allowed_domains": [
"api.myplatform.com"
]
}
```
**Important Notes**:
- `allowed_users` should be an **empty array** `[]` — users authorize themselves via OTP pairing on first message
- Never hardcode usernames like `["@admin"]` — each user pairs via PIN
- The `gateway.py` daemon uses IPC UNIX socket to communicate with Sayri Core
- Must implement `AuthorizationManager` class for OTP pairing
**Issue Template**: `submit-plugin.yml`
- **Title format**: `[Plugin]: My Gateway Name`
- **Labels**: `plugin`, `gateway`, `submission`
---
### 3. GNOME Extension (`gnome_extension`)
Shell extensions for GNOME 45+.
**ZIP Structure**:
```
my-extension.zip
├── metadata.json # Required: uuid, name, shell-version
├── extension.js # Required: ESM module code
├── stylesheet.css # Optional: CSS styling
└── prefs.js # Optional: Settings UI
```
**Issue Template**: `submit-extension.yml`
- **Title format**: `[Extension]: My Extension Name`
- **Labels**: `extension`, `gnome`, `submission`
---
### 4. Flatpak App (`flatpak`)
Desktop applications via Flathub or direct manifests.
**ZIP Structure**: `.flatpak` binary or `.flatpakref` link
**Issue Template**: `submit-app.yml`
- **Title format**: `[App]: My App Name`
- **Labels**: `app`, `flatpak`, `submission`
---
## How to Submit a New Package
### Step 1: Prepare the ZIP Archive
Create a properly structured ZIP file for your package type. Ensure:
- All required files are present
- No `node_modules/`, `vendor/`, or `__pycache__/` directories
- No hardcoded credentials, API keys, or tokens
- Code is clean and follows security best practices
### Step 2: Host the ZIP Archive
Upload the ZIP to a publicly accessible URL. Options:
- **GitHub Release** (recommended): Upload to your repo's releases
- **Direct URL**: Any HTTPS-accessible file hosting
### Step 3: Create the GitHub Issue
Open an issue on `https://github.com/Inled-Pulsar-OS/store` using the appropriate template:
| Package Type | Issue Template URL |
|---|---|
| Sayri Skill | `https://github.com/Inled-Pulsar-OS/store/issues/new?template=submit-skill.yml` |
| Sayri Plugin | `https://github.com/Inled-Pulsar-OS/store/issues/new?template=submit-plugin.yml` |
| GNOME Extension | `https://github.com/Inled-Pulsar-OS/store/issues/new?template=submit-extension.yml` |
| Flatpak App | `https://github.com/Inled-Pulsar-OS/store/issues/new?template=submit-app.yml` |
### Step 4: Fill the Form Fields
**Required fields for all types**:
- **ID**: Unique identifier (e.g., `sayri-gateway-telegram`)
- **Name**: Human-readable name
- **Description**: What the package does
- **ZIP Archive URL**: Direct link to the .zip file
- **Icon URL**: Link to a square PNG or SVG icon (128x128+)
**Optional fields**:
- **Source Repository**: GitHub URL of the source code
- **Demo Screenshots**: Links to preview images
- **AI Audit Provider**: Custom LLM for security audit (default: Groq Llama 3.3 70B)
### Step 5: Automated Pipeline Runs
Once the issue is created, the workflow `validate-and-publish.yml` triggers automatically. You'll see real-time progress comments on the issue:
1. ⏳ Form Preparation & Validation
2. 🔄 Asset & Package Download
3. 🔄 Manifest & Sandbox Validation
4. 🔄 Malware Scan (VirusTotal)
5. 🔄 OpenCode AI Semantic Code Audit
6. 🔄 Catalog Publication (Pulsar Store)
If all steps pass, the issue is closed as "completed" and the package appears in the store.
---
## How to Update an Existing Package
Use the **Update Package** template:
**Issue Template**: `update-package.yml`
- **Title format**: `update: package-id`
- **Labels**: `update`, `version-bump`
**Required fields**:
- **Package ID**: The existing package identifier
- **New Version Number**: Semantic version (e.g., `1.1.0`)
- **New Release ZIP Archive**: Updated .zip file URL
**Optional fields**:
- **Changelog / Release Notes**: Summary of changes
---
## How to Delete a Package
Use the **Delete Package** template:
**Issue Template**: `04_delete_package.yml`
- **Title format**: `delete: package-id`
- **Labels**: `delete`, `package-removal`
**Required fields**:
- **Package ID**: The package to remove
**Note**: Only the administrator (`@jaimegh-es`) or the original package author can delete a package.
---
## Security Audit Pipeline
Every submission goes through a **double-layer security audit**:
### Layer 1: VirusTotal Malware Scan
- Strict **zero-tolerance** policy
- SHA256 hash is checked first; if unknown, the file is uploaded
- If **any** engine detects malware → **REJECTED**
- Results include permalink to VirusTotal report
### Layer 2: OpenCode AI Semantic Audit
- Powered by **Groq Llama 3.3 70B** (or user-specified provider)
- Checks for:
- Malware, backdoors, credential exfiltration
- Prompt injection attacks
- Unauthorized network requests
- Sandbox policy violations
- Destructive shell commands
- Score threshold: **≥ 70/100** to pass
- Score **< 70** → **REJECTED** with detailed risk report
### Sandbox Levels
| Level | Description |
|---|---|
| `LEVEL_0_NO_EXEC` | Isolated / No host execution |
| `LEVEL_1_READ_ONLY` | Read-only filesystem sandbox |
| `LEVEL_2_STRICT_BWRAP` | Bubblewrap container |
| `LEVEL_3_FULL_HOST` | Full host access (requires user confirmation) |
---
## Automation Scripts
### For AI Agents: Programmatic Issue Creation
Use the GitHub API to create issues programmatically:
```bash
# Create a new skill submission issue
curl -X POST \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/Inled-Pulsar-OS/store/issues \
-d '{
"title": "[Skill]: My New Skill",
"body": "### Skill ID\nsayri-skill-my-skill\n\n### Skill Name\nMy New Skill\n\n### Skill Description\nDoes amazing things for Sayri.\n\n### Declared Sandbox Isolation Level\nLEVEL_1_READONLY\n\n### Skill ZIP Archive\nhttps://github.com/myorg/myrepo/releases/download/v1.0.0/sayri-skill-my-skill.zip\n\n### Skill Icon (PNG or SVG)\nhttps://github.com/myorg/myrepo/releases/download/v1.0.0/icon.png\n\n### Source Repository (Optional)\nhttps://github.com/myorg/myrepo",
"labels": ["skill", "sayri", "submission"]
}'
```
### For AI Agents: Programmatic Update
```bash
# Update an existing package
curl -X POST \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/Inled-Pulsar-OS/store/issues \
-d '{
"title": "update: sayri-skill-my-skill",
"body": "### Package ID\nsayri-skill-my-skill\n\n### New Version Number\n1.1.0\n\n### New Release ZIP Archive\nhttps://github.com/myorg/myrepo/releases/download/v1.1.0/sayri-skill-my-skill.zip\n\n### Changelog / Release Notes\nFixed bug X, added feature Y.",
"labels": ["update", "version-bump"]
}'
```
### ZIP Packaging (Bash)
```bash
# Package a skill
cd my-skill/
zip -r ../sayri-skill-my-skill.zip . \
-x "*.pyc" "__pycache__/*" "node_modules/*" ".git/*"
# Package a gateway plugin
cd my-gateway/
zip -r ../sayri-gateway-myplatform.zip . \
-x "*.pyc" "__pycache__/*" "node_modules/*" ".git/*"
```
---
## Examples for AI Agents
### Example: Submitting a Telegram Gateway Plugin
1. **Create the files**:
- `manifest.json` with proper authorization config (empty `allowed_users`)
- `gateway.py` with OTP pairing implementation
- `README.md` with setup instructions
2. **Package as ZIP**:
```bash
cd packages/plugins/sayri-gateway-telegram/
zip -r /tmp/sayri-gateway-telegram.zip . -x "*.pyc" "__pycache__/*"
```
3. **Upload ZIP** to GitHub Releases:
```bash
gh release upload packages /tmp/sayri-gateway-telegram.zip --clobber
```
4. **Create issue** via GitHub API or web UI with the template form
5. **Wait for audit** — the pipeline will:
- Validate the ZIP structure
- Extract and analyze `manifest.json` and `gateway.py`
- Run VirusTotal scan
- Run OpenCode AI audit
- Publish to catalog
### Example: Updating a Package Version
1. **Update version** in `manifest.json` (e.g., `1.0.0` → `1.1.0`)
2. **Re-package** as ZIP
3. **Upload** new ZIP to GitHub Releases
4. **Create update issue** with new version number and changelog
---
## 📋 Quick Reference
| Action | Issue Title Format | Template |
|---|---|---|
| Submit Skill | `[Skill]: Name` | `submit-skill.yml` |
| Submit Plugin | `[Plugin]: Name` | `submit-plugin.yml` |
| Submit Extension | `[Extension]: Name` | `submit-extension.yml` |
| Submit App | `[App]: Name` | `submit-app.yml` |
| Update Version | `update: package-id` | `update-package.yml` |
| Delete Package | `delete: package-id` | `04_delete_package.yml` |
| Field | Required | Description |
|---|---|---|
| ID | ✅ | Unique package identifier |
| Name | ✅ | Human-readable name |
| Description | ✅ | What the package does |
| ZIP Archive URL | ✅ | Direct HTTPS link to .zip |
| Icon URL | ✅ | Square PNG or SVG (128x128+) |
| Source Repository | ❌ | GitHub URL |
| Sandbox Level | ✅ | Security isolation level |
| AI Provider | ❌ | Custom LLM for audit |
---
*Generated for AI Agent autonomous submission to Pulsar Store.*
*Repository: https://github.com/Inled-Pulsar-OS/store*
Official Native App & Ecosystem Hub for Pulsar OS, Arch Linux and Debian/Ubuntu.