# ZenCore Agent Submission Guide

How to package, validate, and submit your agent to the ZenCore marketplace.

> **Quick start:** download the [starter template (.zip)](/submit/zencore-agent-template.zip),
> make it your agent, validate with `npx @zencore/cli stack validate`, then submit at
> [zencore.solutions/submit](/submit).

---

## 1. How it works

You do **not** get access to ZenCore's servers. You submit a **reviewed, version‑pinned
artifact** — a public GitHub repo plus a `stack.json` manifest. ZenCore validates it, an
admin reviews and sandbox‑tests it, and on approval it goes live.

From then on your agent deploys through the same pipeline as first‑party agents: buyer pays
→ a dedicated VPS is provisioned → components install in order → the agent is live at
`https://<buyer>.zencore.solutions`.

**You keep your architecture.** ZenCore owns the *install and hosting mechanics* so that
every buyer's deployment is identical to the one that passed review, and so stranger code
never runs as unconstrained root on a server we provisioned. You describe *how your agent
installs* by pointing each part of it at one of the install methods below — and one of
those methods (`runtime/docker`) runs **literally any architecture**.

## 2. Two lanes: VPS stack vs. local agent

| | VPS stack | Local agent |
|---|---|---|
| Runs on | A dedicated VPS ZenCore provisions per buyer | The buyer's own computer |
| You submit | Public GitHub repo URL + pinned commit SHA + `stack.json` | A sanitized `.zip` (≤ 80 MB) |
| Pricing | Subscription or one-time | One-time license |
| Keys | Buyer enters at setup; injected as env vars | Buyer brings their own, stays on their machine |

This guide focuses on the **VPS stack** lane. See §7 for the local lane.

## 3. What your repo needs (VPS stack)

Minimum — start from the [template](/submit/zencore-agent-template.zip):

```
my-agent/
  stack.json                 # the manifest (required)
  README.md                  # what it does, keys needed, support (required for review)
  LICENSE                    # required for review
  server.js                  # your agent — any language / framework
  package.json
  config/
    config.template.json     # placeholders only — NO real secrets
```

### The 3 rules your runtime must follow

1. **Listen on the port** — `process.env.PORT`, or your `stack.json` `entrypoints.primaryPort`.
2. **Expose the health endpoint** declared in `source.healthPath` (e.g. `/health`), returning HTTP 200 when the agent is up.
3. **Read every secret from an environment variable** whose name matches a `requiredCredentials[].id`. Never hard-code keys.

Everything else — your framework, LLM provider, agent architecture — is yours.

## 4. The stack.json manifest

A complete, valid single-component example (this is the template):

```json
{
  "schemaVersion": 1,
  "id": "my-agent",
  "name": "My Agent",
  "version": "1.0.0",
  "summary": "One sentence describing what your agent does.",
  "reviewStatus": "review",
  "components": [
    {
      "id": "app",
      "type": "runtime",
      "recipe": "runtime/node-service",
      "source": {
        "repo": "https://github.com/your-org/my-agent",
        "ref": "<full 40-character commit SHA>",
        "buildCmd": "npm ci",
        "startCmd": "node server.js",
        "healthPath": "/health"
      },
      "credentialIds": ["anthropic_api_key"],
      "installOrder": 10,
      "required": true
    }
  ],
  "entrypoints": { "setupUrl": "/", "primaryPort": 8080 },
  "requiredCredentials": [
    { "id": "anthropic_api_key", "label": "Anthropic API key", "requiredFor": "LLM reasoning" }
  ]
}
```

### Field reference

| Field | Notes |
|---|---|
| `schemaVersion` | Always `1`. |
| `id` | Lowercase, hyphenated. Must equal the folder name and the catalog id. |
| `reviewStatus` | `draft` or `review` on submit. |
| `components[]` | Each is `{ id, type, recipe, source?, credentialIds?, installOrder, required }`. Runs in `installOrder`. |
| `source.repo` / `source.ref` | Must match your submission's repo URL and a full 40-char commit SHA. |
| `source.containerPort` | `runtime/docker` only — the loopback port your container listens on. |
| `source.dataPath` | `runtime/docker` only — an absolute in-container path (e.g. `/data`) that persists across restarts (bind-mounted to host storage). |
| `requiredCredentials[]` | What the buyer is asked for at setup; ids become env var names. |
| `resourceHints` | Optional `{ minMemoryMb, gpuOptional }`. |

## 5. Install methods — ship *any* agent

ZenCore can run any agent. You just tell it *how your agent installs* by pointing each
component at one of these platform‑owned install methods (they clone your reviewed source
and stand it up under a hardened service — you never write a custom install script). These
are examples for the common cases; **`runtime/docker` is the universal one — if your agent
builds and runs in a container, ZenCore can run it, whatever the architecture.**

Run `npx @zencore/cli stack recipes` for the live list.

| Method | Great for |
|---|---|
| `runtime/docker` | **Anything.** Builds your Dockerfile *from source* at the pinned SHA and runs it hardened. Multi-service, exotic deps, any language — this is the catch‑all. |
| `runtime/node-service` | A single Node service (clone, `npm ci`, start). Simplest path. |
| `runtime/python-service` | A single Python service (clone, venv, start). |
| `runtime/openclaw` | OpenClaw gateway (config merge only). |
| `inference/ollama` | Local Ollama models. |
| `inference-provider/anthropic` · `inference-provider/google` | Wire an LLM provider key into your runtime config. |
| `data/chroma-vault` | ChromaDB + vault layout for RAG. |
| `dashboard/static-spa` | A prebuilt static dashboard. |

> **Missing a method your agent needs?** Tell us — new install methods are a platform task,
> not a rejection. In the meantime, `runtime/docker` covers essentially any setup, since you
> control everything inside the image.

### What `runtime/docker` can and can't run

If your agent runs in a container, ZenCore can almost certainly run it. To save you a
rejected submission, here's the exact envelope.

**Runs great — this is most agents:**

- Any language, framework, or dependency — it's your Dockerfile.
- Custom runtimes, bundled models, compiled binaries.
- Multiple services — express each as its own component (each a `runtime/docker` build in a
  different `subdir`), ordered by `installOrder`.
- Any LLM provider, any RAG/memory/agent design.

**Needs to fit these rules:**

1. **It's a service, not a bare CLI.** Your agent must listen on a port and expose a health
   endpoint. A pure command-line tool needs a thin HTTP wrapper around it.
2. **Built from source.** A public GitHub repo with a `Dockerfile`, pinned to a commit SHA —
   we build the image ourselves for auditability. (No prebuilt or private-registry images.)
3. **Hardened sandbox.** The container runs non-root with dropped capabilities, a read-only
   root filesystem (+ writable `/tmp`), a loopback-only port, and resource caps. Anything
   needing elevated privileges, host networking, privileged mode, raw device access, or
   docker-in-docker won't fit.
4. **Persistent data goes through a declared path.** The container filesystem is ephemeral,
   so writes to random locations vanish on restart. To keep data, set `source.dataPath` to an
   absolute in-container path (e.g. `/data`) — ZenCore bind-mounts it to host storage that
   survives restarts and redeploys. Write your database/files there. (Or use a data component
   like `data/chroma-vault`, or an external database.)
5. **One VPS of resources.** It runs on a single tenant server. Multi-node or very heavy
   workloads don't fit.

**Not supported yet (ask us — roadmap, not "no"):** on-tenant **GPU** (we don't pass `--gpus`
yet). If your agent needs to self-host a model on a GPU, reach out before submitting.

## 6. Validation rules (run `stack validate` first)

The validator runs the moment you submit — catch issues early with
`npx @zencore/cli stack validate --stack ./stack.json`.

| Rule | |
|---|---|
| Public GitHub HTTPS repo URL (`https://github.com/owner/repo`) | required |
| A full **40-character commit SHA** — no branches, no `main` | required |
| Each component names an install method (`recipe`) — the platform installs it, you don't ship a custom `install.sh` | required |
| Each `source.repo` / `source.ref` matches the submission's repo / SHA | required |
| `stack.json id` equals your proposed stack id | required |
| A `README.md` and a `LICENSE` in the repo | required |
| No secrets, no `.env` with real keys, no customer data | rejected if present |

**Why install is platform‑owned, not arbitrary shell:** ZenCore provisions and runs the VPS
for the buyer. Running a stranger's arbitrary root install script on that machine is an
unacceptable supply‑chain risk, so install runs through vetted, platform‑maintained methods.
`runtime/docker` is the escape hatch that keeps this compatible with *any* agent — you get
full control inside the container while the host stays safe.

## 7. Local agents (zip lane)

Submitting software the buyer runs on their own machine? Submit a `.zip` instead of a repo
(choose *Local agent* at [/submit](/submit)).

- Max ~80 MB; must include an install doc (`ZENCORE-INSTALL.md`, `GET-STARTED.md`, or `README.md`).
- **Blocked by the sanitizer:** path traversal, nested `.zip`, `.exe`/`.dll`/`.msi`, `.env`, key/credential files, `.git/`.
- Bring-your-own keys only — inference runs on the buyer's key, on the buyer's machine.
- Priced one-time; buyers get a licensed download.

## 8. Submission & review process

1. **Build** from the template; push to a public GitHub repo.
2. **Pin** — set `source.repo` and a full commit `source.ref`.
3. **Validate** locally: `npx @zencore/cli stack validate --stack ./stack.json` (exit 0 = ready).
4. **Submit** at [zencore.solutions/submit](/submit) with your repo URL, SHA, stack.json, and listing details (name, summary, price).
5. **Review** — an admin reads your repo at that SHA and runs a sandbox install test. Track status at `/account/submissions`.
6. **Go live** — on approval your listing is promoted to the catalog and buyers can deploy it.

Status flow: `submitted → review → approved → promoted` (or `changes_requested` / `rejected`).

## 9. Security model

Your code runs under a **hardened, non-root systemd unit** (or a hardened container for
`runtime/docker`): dropped privileges, restricted filesystem, resource caps. Your repo is
cloned at the **exact reviewed SHA** — nothing floating. Buyer credentials are injected by
the setup server and never pass through you.

## 10. FAQ

**Do I need to buy an agent to submit?**
No. You need a ZenCore account and a public GitHub repo pinned to a commit.

**Can ZenCore run *any* agent?**
Any agent architecture — yes. If it builds and runs in a container, `runtime/docker` runs it,
whatever it's made of. The only thing that's constrained is the *install mechanism* (vetted
platform methods, not arbitrary root scripts), for the security reasons in §6.

**Do I have to use OpenClaw or a specific framework?**
No. Any language, framework, or LLM. OpenClaw is one optional method.

**Can I ship a prebuilt Docker image?**
No — the Docker method builds *from your source* at the reviewed SHA, so the image is auditable.

**How do buyers give my agent its keys?**
They enter them in the setup wizard; ZenCore injects them as env vars named after your
`requiredCredentials[].id`.

---

*Full engineering references: `docs/ZENCORE_AGENT_DEVELOPER_GUIDE.md` and
`docs/THIRD-PARTY-STACK-SUBMISSION-DESIGN.md` in the ZenCore repo. Questions? Reach ZenCore
support from your account.*
