Submission
Open the PR against vendo-templates, get it reviewed, and watch your tool go live.
Submitting a tool to the public catalog is two PRs and a migration:
- A PR against
runvendo/vendo-templatesadding{slug}/{version}.json. - A PR against the Vendo monorepo with the DB seed migration and the release migration.
The monorepo PR depends on the templates PR being merged first (so the manifest exists in R2 when the release row points at it). Submit them together — reviewers will sequence the merges.
Templates PR — what to include
vendo-templates/
└── <slug>/
└── <version>.jsonThat's it. One file. Push to a branch, open a PR against main of runvendo/vendo-templates, with a body that includes:
- What the tool does in one sentence.
- Repo URL for the source code or container image.
- Image tag referenced in
services[].image(and which registry;ghcr.iois preferred). - Integrations required (
openrouter,telegram, etc.) — and whether any are new providers that need apackages/integrations/<slug>/adapter in the monorepo. - Pricing intent —
creditsif the tool calls the proxy,freeotherwise. Don't setpricing: "free"on a tool that calls the proxy; billing is silently skipped.
What the action checks automatically
The sync.yml action runs a validate job on every push and PR (npm run validate), then a sync job that pushes to R2 and Supabase on push-to-main only. The PR cannot merge if validation fails. Validation uses the local Zod schema at vendo-templates/src/schema.ts, which is stricter than the deploy worker's runtime schema. It covers:
- Required top-level fields (
slug,name,version,source, plusservices,readiness, andintegrationsenforced by the deploy worker on top). slugis kebab-case;versionis semver.- Service-level shape:
imageORbuildArtifact,roleis one ofweb | worker | cron | init. integrations[]entries declareprovider,profile, andcardinality(Zod requires these — the deploy worker's JSON schema doesn't).wizardLayout(if present) matches thesubSteps[]shape.
Schema-valid does not mean correct. The reviewer still checks the actual content.
What the reviewer checks
- Slug discipline. Slug matches across the directory name, the manifest field, the monorepo seed migration, and the proxy adapter (if any). See The vendo-templates repo § Naming.
- Image is pullable. The tag exists and is publicly accessible (or the registry credentials are wired into the Railway template).
- Integrations exist. Every
integrations[].providerslug matches a row inpackages/integrations/<slug>/integration.tsin the monorepo. New providers need their own PR first. integrations[]is not silently empty. If your tool calls third-party APIs, the array must list them. See the COALESCE trap in Versioning & releases.- Wizard sanity. A
["*"]input sweep exists ifwizardLayoutis defined, so forgotten keys still surface. - Healthcheck is real.
readiness.healthPathactually responds 2xx on a fresh container. - Data preservation. Any state that must survive suspend/resume lives in Postgres, R2, KV, or a Railway volume — never in-container filesystem outside a volume.
- Pricing model matches behavior.
pricing: "free"only on tools that never call the proxy.
Monorepo PR — what to include
A reviewer will ask for these alongside the templates PR:
- DB seed migration — INSERT into
apps_catalog. Required columns:id(UUID, usegen_random_uuid()),slug,name,tool_type('deployment'for tenant-deployable tools),enabled,featured,usage_category,allowed_callback_patterns,marketing(JSONB). Optional:auth_mode(nullable — only set if your tool'sadminBootstrap.authModeneeds it),description,surface_all_connections,supported_connections. Pattern: existing tool migrations undersupabase/migrations/. - Release migration — INSERT a
tool_releasesrow withtool_idset from(SELECT id FROM apps_catalog WHERE slug = '<slug>')(UUID FK, nottool_slug),version = '<version>', andstatus = 'active'. If the tool already has an active release, the migration UPDATEs the old row toinactivefirst (the partial unique index ontool_releases (tool_id) WHERE status='active'enforces this anyway). - Proxy adapter — if the tool calls a new provider that doesn't yet have an adapter in
packages/integrations/<slug>/orproxy/src/adapters/.
Migrations don't apply automatically on merge — they need supabase db push against the prod project. The reviewer will run this; don't run it yourself unless you're on the Vendo team and have been asked to.
After merge
Once both PRs merge and the migration is applied:
- The sync action uploads
{slug}/{version}.jsonto R2. - The release row goes active.
- The sync action's
sync:supabasestep updatestool_releases.template_version,wizard_inputs,requires, andwizard_layoutfrom the manifest. - The catalog query starts returning your tool to public surfaces (unless
marketing.internal = true). - The next tenant who clicks Deploy gets your tool.
Watch your first real-tenant deploy in deploy_logs and verify it advances cleanly from validate_template to notify_user.
Next: Versioning & releases.