> For the complete documentation index, see [llms.txt](https://docs.aboutcircles.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.aboutcircles.com/miniapps/contribute-mini-apps.md).

# Contribute Mini Apps

{% embed url="<https://github.com/aboutcircles/CirclesMiniapps>" %}

{% hint style="info" %}
There are two ways to contribute Mini Apps to Circles:

* **Garage Mini Apps** — externally hosted experimental, community, and hackathon apps
* **Embedded Mini Apps** — curated production-grade apps fully shipped from this repository
  {% endhint %}

***

## Circles Mini App Host

Circles Mini Apps are hosted by a SvelteKit application that renders apps inside iframes at:

```txt
https://<VITE_BASE_URL>/miniapps
```

Mini apps communicate with the host through a `postMessage` wallet bridge for:

* Wallet connection
* Transaction requests
* Message signing
* App metadata

The marketplace reads app metadata from:

```txt
static/miniapps.json
```

When a user opens:

```txt
/miniapps/<slug>
```

the host loads the corresponding app URL inside an iframe.

***

## Choose Your Submission Type

| Type              | Best For                                                 | Hosting                          | Review Level       |
| ----------------- | -------------------------------------------------------- | -------------------------------- | ------------------ |
| Garage Mini App   | Experimental apps, hackathons, demos, community projects | External hosting allowed         | Lightweight review |
| Embedded Mini App | Curated production apps                                  | Must live inside this repository | Full review        |

***

## Garage Mini Apps

Garage Mini Apps are intended for:

* Hackathon projects
* Experimental apps
* Community tools
* Early-stage prototypes
* Circles Garage competition entries

Garage apps:

* Can be hosted anywhere
* Only require a manifest PR
* Run under a stricter transaction policy
* Show a "use at your own risk" disclaimer

Examples of allowed hosting:

* Vercel
* Netlify
* GitHub Pages
* Your own domain

### What a Garage PR should contain

Garage submissions only require a metadata entry.

The app itself remains in your own repository and deployment.

Your PR should contain:

* A new entry in `static/miniapps.json`
* Optionally a logo under `static/app-logos/`
* A deployed HTTPS URL that already works inside an iframe

Open the PR against:

```txt
aboutcircles/CirclesMiniapps
```

branch:

```txt
master
```

***

## Embedded Mini Apps

Embedded Mini Apps are curated production-grade apps that ship directly from this repository.

This path is intended for apps that:

* Should become part of the official Mini Apps experience
* Need deeper review and maintainability
* Are intended to be maintained long term inside this repository

For Embedded Mini Apps:

* The full source code must be included in the PR
* The app must live inside this repository
* External-host-only submissions are not accepted

***

## Embedded Mini App structure

Recommended layout:

```txt
src/routes/apps/<slug>/+page.svelte
src/routes/apps/<slug>/components/...
static/app-logos/<slug>.png
static/apps/<slug>/...
```

Recommended routing pattern:

| Route              | Purpose                   |
| ------------------ | ------------------------- |
| `/miniapps/<slug>` | Marketplace wrapper route |
| `/apps/<slug>`     | Actual embedded app route |

Example manifest entry:

```json
{
  "slug": "my-app",
  "name": "My App",
  "logo": "/app-logos/my-app.png",
  "url": "/apps/my-app",
  "description": "Short description of the app.",
  "tags": ["payments", "tools"],
  "category": "miniapp"
}
```

***

## Manifest Format

Both Garage and Embedded Mini Apps are registered in:

```txt
static/miniapps.json
```

### Required fields

| Field         | Required | Notes                        |
| ------------- | -------: | ---------------------------- |
| `slug`        |      yes | URL-safe unique identifier   |
| `name`        |      yes | Display name                 |
| `logo`        |      yes | HTTPS URL or local repo path |
| `url`         |      yes | App URL                      |
| `description` |      yes | Short app description        |
| `tags`        |      yes | Discovery tags               |
| `category`    |      yes | `"garage"` or `"miniapp"`    |
| `isHidden`    |       no | Hide from marketplace grid   |

***

## Example Garage Entry

```json
{
  "slug": "your-app-slug",
  "name": "Your App",
  "logo": "/app-logos/your-app.png",
  "url": "https://your-app.example.com/",
  "description": "One-sentence description.",
  "tags": ["demo", "tools"],
  "category": "garage"
}
```

***

## Example Embedded Entry

```json
{
  "slug": "embedded-app",
  "name": "Embedded App",
  "logo": "/app-logos/embedded-app.png",
  "url": "/apps/embedded-app",
  "description": "Embedded app description.",
  "tags": ["payments"],
  "category": "miniapp"
}
```

***

## Host Integration

Mini apps communicate with the host using `postMessage`.

Mini app → host:

* `request_address`
* `send_transactions`
* `sign_message`

Host → mini app:

* `wallet_connected`
* `wallet_disconnected`
* `app_data`
* `tx_success`
* `tx_rejected`
* `sign_success`
* `sign_rejected`

Current implementation lives in:

```txt
src/routes/miniapps/[slug]/+page.svelte
src/routes/playground/+page.svelte
```

Build against the actual implementation, not assumptions.

***

## Garage Transaction Policy

Garage apps run under a stricter transaction policy.

Before approval, the host rejects any transaction batch that:

* Targets the user's currently acting Safe
* Targets the user's primary Safe while in child-safe mode
* Uses restricted Safe-management selectors

Restricted selectors:

| Selector     | Function                                 |
| ------------ | ---------------------------------------- |
| `0x0d582f13` | `addOwnerWithThreshold(address,uint256)` |
| `0xf8dc5dd9` | `removeOwner(address,address,uint256)`   |
| `0xe318b52b` | `swapOwner(address,address,address)`     |
| `0x694e80c3` | `changeThreshold(uint256)`               |
| `0xe19a9dd9` | `setGuard(address)`                      |
| `0xf08a0323` | `setFallbackHandler(address)`            |
| `0x610b5925` | `enableModule(address)`                  |
| `0xe009cfde` | `disableModule(address,address)`         |
| `0x6a761202` | `execTransaction(...)`                   |

The entire batch is rejected on the first violation.

The user sees a restricted-action modal and the iframe receives:

```txt
tx_rejected
```

### Garage apps cannot

* Call `execTransaction`
* Add/remove owners
* Change Safe configuration
* Enable modules
* Modify guards
* Wrap their own Safe execution flow

If your app requires these permissions, it should be submitted as an Embedded Mini App instead.

***

## Local Development

Before opening a PR, run:

```sh
npm install
npm run check
npm run build
```

Then verify manually:

1. Open `/miniapps`
2. Confirm the app appears
3. Open `/miniapps/<slug>`
4. Confirm the iframe loads correctly
5. Test the main app flow
6. Test wallet/signing flows if applicable

***

## PR Expectations

All PRs should include:

* App metadata in `static/miniapps.json`
* Working routes and URLs
* Logo/assets
* Clear PR description
* Testing notes

Embedded Mini Apps must additionally include:

* Full application source code
* Any required dependencies
* Local assets and routes

Recommended PR titles:

Garage:

```txt
feat: add <app-name> garage app
```

Embedded:

```txt
feat: add <app-name> embedded miniapp
```

***

## Review Criteria

Maintainers will review:

* Whether the app works inside the iframe host
* Wallet/signing safety
* Build stability
* Asset quality
* Maintainability
* Transaction behavior
* Whether the correct submission path was used

***

## Common Rejection Reasons

Garage submissions may be rejected if:

* The app does not load in an iframe
* The URL is broken
* Restricted Safe-management actions are attempted
* The manifest is incomplete

Embedded submissions may be rejected if:

* The PR only links to an external deployment
* Core logic still lives outside this repository
* Local routes/assets are missing
* The app fails build or check
* The iframe integration is broken

***

## Minimal Checklist

### Garage Mini App

* [ ] Added entry to `static/miniapps.json`
* [ ] `category` is `"garage"`
* [ ] App loads over HTTPS
* [ ] App works inside iframe
* [ ] Logo resolves correctly
* [ ] `slug` is unique
* [ ] No restricted Safe-management calls

### Embedded Mini App

* [ ] App source added under `src/routes/apps/<slug>/`
* [ ] Metadata added to `static/miniapps.json`
* [ ] `category` is `"miniapp"`
* [ ] Local logo/assets committed
* [ ] `/miniapps/<slug>` works
* [ ] `npm run check` passes
* [ ] `npm run build` passes

If you want maintainers to merge and host your app directly as part of the Circles Mini Apps platform, submit it as an Embedded Mini App.
