VendoVendo Docs
Deploy & publishPublish to the catalog

The vendo-templates repo

Structure and layout of runvendo/vendo-templates — where every catalog manifest lives.

Catalog manifests live in a dedicated repo: runvendo/vendo-templates. It is the single source of truth for what the deploy worker provisions. Manifests are not stored in the Vendo monorepo, and they are not stored in your tool's own repo.

Repo layout

vendo-templates/
├── README.md
├── .github/workflows/
│   ├── sync.yml
│   └── upstream-tracker.yml
└── <slug>/
    ├── 1.0.0.json
    ├── 1.0.1.json
    └── 1.1.0.json

One directory per tool, named exactly the same as the tool's apps_catalog.slug. One JSON file per version, named {semver}.json. That's the entire convention.

How the sync action works

On every push to main, .github/workflows/sync.yml runs two jobs in sequence: a validate job (also runs on PR) followed by a sync job (push-to-main + manual workflow_dispatch only).

  1. Validate. npm run validate parses every {slug}/{version}.json against the local Zod schema in vendo-templates/src/schema.ts. The Zod schema is intentionally stricter than the deploy worker's manifest.schema.json — for example, every integrations[] entry must declare profile and cardinality. A submission that passes the deploy-worker schema can still fail Zod here.
  2. Sync to R2. npm run sync:r2 uploads each {slug}/{version}.json to the vendo-templates R2 bucket at the same path. The deploy worker fetches templates/{slug}/{version}.json at deploy time.
  3. Sync to Supabase. npm run sync:supabase joins each template against apps_catalog.slug, finds the matching tool_releases row with status='active', and — only if the active release's version matches the template's version — UPDATEs the row's template_version, wizard_inputs, requires, wizard_layout, and version columns from the manifest JSON. Templates whose version doesn't match the active release are skipped (with a log line). See src/sync-supabase.ts.

R2 is content-addressed by {slug}/{version}. Once a version is uploaded, do not edit the file in place — every change is a new version. Existing deployments reference the manifest version that was active when they deployed.

Editing a published 1.0.0.json in place is a footgun. Existing deployments snapshot the manifest into deployments.manifest at deploy time, so they keep running. But anything that re-fetches the manifest (e.g. retries) will pick up the silent change, and sync:supabase will rewrite tool_releases columns next push. Always cut a new version.

Order of operations matters: sync:supabase only updates an active release whose version matches the template. Adding {slug}/1.0.5.json does nothing in the DB until the matching release migration lands. The recommended flow is to merge the monorepo release migration first (or at the same time) so the active release pins to the new version before sync runs.

Required workflow secrets

The sync action needs five secrets configured on the vendo-templates repo. These are already wired by Vendo for the main repo; you only deal with them if you fork:

  • R2_ACCESS_KEY_ID
  • R2_SECRET_ACCESS_KEY
  • CLOUDFLARE_ACCOUNT_ID
  • SUPABASE_URL
  • SUPABASE_SERVICE_ROLE_KEY

What's NOT in the templates repo

  • Catalog entry. The row in apps_catalog lives in a DB seed migration in the Vendo monorepo, not here.
  • Release row. tool_releases is also driven by monorepo migrations.
  • Adapter code. Per-provider proxy adapters live in packages/integrations/<slug>/ in the monorepo.
  • Source code. Your tool's container image and source code live wherever the image is built — usually a separate repo entirely. The manifest only references the image tag.

Naming and slug discipline

The tool's slug is load-bearing in five places: the directory name here, apps_catalog.slug, deployments.tool_slug, the proxy adapter registry (if the tool defines one), and the deployment URL. Pick it once and never rename it. If you absolutely must rename, expect to write a data migration touching all five surfaces.

A minimal first PR

For a brand-new tool:

vendo-templates/
└── my-tool/
    └── 1.0.0.json

That single file is enough to open a PR. The matching catalog entry and release row come from migrations in the Vendo monorepo — see Submission for the full checklist.

Next: Manifest format — what goes inside {version}.json.

On this page