# 🤖 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*